@sei-code/analytics
Version:
Blockchain data analysis and monitoring for Sei network
254 lines (253 loc) • 10.3 kB
JavaScript
// Main analytics agents
export { PortfolioAnalyzer } from './portfolio-analyzer';
export { PerformanceTracker } from './performance-tracker';
export { MarketDataAgent } from './market-data';
// Export all types
export * from './types';
import { PortfolioAnalyzer } from './portfolio-analyzer';
import { PerformanceTracker } from './performance-tracker';
import { MarketDataAgent } from './market-data';
/**
* Comprehensive analytics agent that combines portfolio tracking,
* performance analysis, and market data capabilities
*/
export class AnalyticsAgent {
portfolio;
performance;
market;
config;
constructor(agent, precompiles, config = {}) {
this.config = {
updateInterval: 300, // 5 minutes
priceHistoryDepth: 30, // 30 days
enableAlerts: true,
benchmarkAssets: ['usei', 'uatom'],
riskFreeRate: 3.0, // 3% annual
confidenceLevel: 95, // 95% for VaR
...config
};
this.portfolio = new PortfolioAnalyzer(agent, precompiles);
this.performance = new PerformanceTracker(agent, precompiles);
this.market = new MarketDataAgent(agent, precompiles);
}
/**
* Get comprehensive analytics dashboard for a user
*/
async getDashboard(userAddress) {
try {
const [portfolioSnapshot, performanceReports, marketTrends] = await Promise.all([
this.portfolio.analyzePortfolio(userAddress),
this.performance.trackAssetPerformance('usei', ['24h', '7d', '30d']),
this.market.getMarketTrend('usei', ['24h', '7d'])
]);
const allocation = await this.portfolio.getAssetAllocation(userAddress);
const performanceHistory = await this.portfolio.trackPerformanceOverTime(userAddress);
return {
portfolioSnapshot,
performanceReports: performanceReports,
marketTrends,
allocation,
performanceHistory,
recommendations: []
};
}
catch (error) {
throw new Error(`Failed to generate dashboard: ${error.message}`);
}
}
/**
* Compare multiple portfolios
*/
async comparePortfolios(addresses) {
return this.portfolio.comparePortfolios(addresses);
}
/**
* Get market overview for multiple assets
*/
async getMarketOverview(denoms = ['usei', 'uatom', 'uosmo']) {
try {
const [correlations, trends, performance] = await Promise.all([
this.market.calculateCorrelationMatrix(denoms),
Promise.all(denoms.map(denom => this.market.getMarketTrend(denom, ['24h']))),
this.performance.compareAssetPerformance(denoms, '24h')
]);
return {
correlations,
trends: trends.flat(),
performance,
summary: {
totalAssets: denoms.length,
bullishCount: trends.flat().filter(t => t.trend === 'bullish').length,
bearishCount: trends.flat().filter(t => t.trend === 'bearish').length,
topPerformer: performance.summary.bestPerformer,
worstPerformer: performance.summary.worstPerformer
}
};
}
catch (error) {
throw new Error(`Failed to get market overview: ${error.message}`);
}
}
/**
* Generate investment recommendations based on portfolio analysis
*/
async getInvestmentRecommendations(userAddress) {
try {
const [portfolioData, allocation, marketTrends] = await Promise.all([
this.portfolio.analyzePortfolio(userAddress),
this.portfolio.getAssetAllocation(userAddress),
this.market.getMarketTrend('usei', ['7d', '30d'])
]);
const recommendations = [];
// Diversification recommendations
if (portfolioData.performance.diversificationScore < 30) {
recommendations.push({
type: 'diversification',
priority: 'high',
title: 'Improve Portfolio Diversification',
description: `Your diversification score is ${portfolioData.performance.diversificationScore.toFixed(1)}/100. Consider spreading investments across more assets.`,
action: 'Add 2-3 different assets to reduce concentration risk'
});
}
// Liquidity recommendations
if (allocation.liquid < 10) {
recommendations.push({
type: 'liquidity',
priority: 'medium',
title: 'Increase Liquid Holdings',
description: `Only ${allocation.liquid.toFixed(1)}% of your portfolio is liquid. Consider maintaining 10-20% in liquid form.`,
action: 'Undelegate some staked tokens for better liquidity'
});
}
// Market-based recommendations
const bullishTrend = marketTrends.some(t => t.trend === 'bullish' && t.strength !== 'weak');
if (bullishTrend && allocation.liquid > 30) {
recommendations.push({
type: 'market_opportunity',
priority: 'medium',
title: 'Consider Staking During Bullish Trend',
description: 'Market shows bullish momentum. Consider staking some liquid tokens to earn rewards.',
action: 'Stake 10-20% of liquid holdings with reliable validators'
});
}
// Performance recommendations
if (portfolioData.performance.dailyReturnPercentage < -5) {
recommendations.push({
type: 'risk_management',
priority: 'high',
title: 'Review Risk Exposure',
description: `Portfolio is down ${Math.abs(portfolioData.performance.dailyReturnPercentage).toFixed(1)}% today. Review risk exposure.`,
action: 'Consider reducing position sizes or hedging strategies'
});
}
return {
recommendations,
riskLevel: this.assessRiskLevel(portfolioData),
nextReviewDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString() // 7 days
};
}
catch (error) {
throw new Error(`Failed to generate recommendations: ${error.message}`);
}
}
/**
* Track specific metrics over time
*/
async trackMetrics(userAddress, metrics = ['totalValue', 'diversification', 'yields']) {
try {
const history = await this.portfolio.getPortfolioHistory(userAddress);
const trackedMetrics = metrics.map(metric => {
const data = history.map(snapshot => {
let value;
switch (metric) {
case 'totalValue':
value = parseFloat(snapshot.totalValue);
break;
case 'diversification':
value = snapshot.performance.diversificationScore || 0;
break;
case 'yields':
value = snapshot.performance.dailyReturnPercentage;
break;
default:
value = 0;
}
return {
timestamp: snapshot.timestamp,
value
};
});
return {
metric,
data,
trend: this.calculateTrend(data.map(d => d.value)),
latest: data[data.length - 1]?.value || 0
};
});
return trackedMetrics;
}
catch (error) {
throw new Error(`Failed to track metrics: ${error.message}`);
}
}
assessRiskLevel(portfolio) {
let riskScore = 0;
// Low diversification increases risk
if (portfolio.performance.diversificationScore < 30)
riskScore += 30;
else if (portfolio.performance.diversificationScore < 50)
riskScore += 15;
// High volatility increases risk
const dailyChange = Math.abs(portfolio.performance.dailyReturnPercentage);
if (dailyChange > 10)
riskScore += 25;
else if (dailyChange > 5)
riskScore += 15;
// High concentration in staked assets
const stakedRatio = portfolio.assets
.filter((a) => a.type === 'staked')
.reduce((sum, a) => sum + a.allocation, 0);
if (stakedRatio > 80)
riskScore += 20;
else if (stakedRatio > 60)
riskScore += 10;
if (riskScore > 50)
return 'high';
if (riskScore > 25)
return 'medium';
return 'low';
}
calculateTrend(values) {
if (values.length < 2)
return 'stable';
const recent = values.slice(-5); // Last 5 values
const slope = this.calculateSlope(recent);
if (slope > 0.02)
return 'increasing';
if (slope < -0.02)
return 'decreasing';
return 'stable';
}
calculateSlope(values) {
if (values.length < 2)
return 0;
const n = values.length;
const sumX = (n * (n - 1)) / 2; // Sum of indices
const sumY = values.reduce((sum, val) => sum + val, 0);
const sumXY = values.reduce((sum, val, index) => sum + (index * val), 0);
const sumXX = (n * (n - 1) * (2 * n - 1)) / 6; // Sum of squared indices
return (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
}
/**
* Get configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Update configuration
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
}
}