Install
1
Install the plugin$
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin crypto-portfolio-trackerWant just this command?
Then install: npx claudepluginhub u/[userId]/[slug]
Description
Analyze entire crypto portfolio with allocation, risk metrics, and...
Command Content
Portfolio Analysis
Comprehensive portfolio analysis for cryptocurrency holdings with advanced metrics, risk assessment, and optimization recommendations.
Usage
Analyze the user's complete crypto portfolio to provide insights on:
- Asset allocation and diversification
- Risk metrics (Sharpe ratio, volatility, max drawdown)
- Performance attribution
- Correlation analysis
- Rebalancing recommendations
Implementation
1. Portfolio Analytics Engine
class PortfolioAnalyzer {
constructor() {
this.riskFreeRate = 0.02; // 2% annual risk-free rate
this.historicalData = new Map();
this.correlationMatrix = null;
}
async analyzePortfolio(positions) {
// Fetch current prices and calculate values
const portfolioData = await this.enrichPositions(positions);
// Calculate core metrics
const metrics = {
totalValue: this.calculateTotalValue(portfolioData),
totalCost: this.calculateTotalCost(portfolioData),
totalPnL: this.calculateTotalPnL(portfolioData),
allocation: this.calculateAllocation(portfolioData),
concentration: this.calculateConcentration(portfolioData),
volatility: await this.calculateVolatility(portfolioData),
sharpeRatio: await this.calculateSharpeRatio(portfolioData),
sortino: await this.calculateSortinoRatio(portfolioData),
maxDrawdown: await this.calculateMaxDrawdown(portfolioData),
correlations: await this.calculateCorrelations(portfolioData),
var95: this.calculateValueAtRisk(portfolioData, 0.95),
var99: this.calculateValueAtRisk(portfolioData, 0.99)
};
// Generate insights and recommendations
const analysis = {
metrics,
riskAssessment: this.assessRisk(metrics),
diversificationScore: this.calculateDiversificationScore(metrics),
rebalancingPlan: this.generateRebalancingPlan(portfolioData, metrics),
optimizations: this.suggestOptimizations(metrics)
};
return analysis;
}
calculateAllocation(portfolioData) {
const totalValue = portfolioData.reduce((sum, p) => sum + p.currentValue, 0);
return portfolioData.map(position => ({
symbol: position.symbol,
value: position.currentValue,
percentage: (position.currentValue / totalValue) * 100,
targetPercentage: position.targetAllocation || null,
deviation: position.targetAllocation
? Math.abs(((position.currentValue / totalValue) * 100) - position.targetAllocation)
: 0
})).sort((a, b) => b.percentage - a.percentage);
}
calculateConcentration(portfolioData) {
const allocations = this.calculateAllocation(portfolioData);
const herfindahlIndex = allocations.reduce((sum, a) => {
return sum + Math.pow(a.percentage / 100, 2);
}, 0);
return {
herfindahlIndex: herfindahlIndex.toFixed(4),
effectiveAssets: (1 / herfindahlIndex).toFixed(2),
topAssetConcentration: allocations[0].percentage.toFixed(2),
top3Concentration: allocations.slice(0, 3).reduce((sum, a) => sum + a.percentage, 0).toFixed(2)
};
}
async calculateVolatility(portfolioData, period = 30) {
const returns = await this.getHistoricalReturns(portfolioData, period);
if (returns.length < 2) return null;
const avgReturn = returns.reduce((sum, r) => sum + r, 0) / returns.length;
const variance = returns.reduce((sum, r) => sum + Math.pow(r - avgReturn, 2), 0) / (returns.length - 1);
const volatility = Math.sqrt(variance);
// Annualized volatility
return {
daily: (volatility * 100).toFixed(2),
weekly: (volatility * Math.sqrt(7) * 100).toFixed(2),
monthly: (volatility * Math.sqrt(30) * 100).toFixed(2),
annual: (volatility * Math.sqrt(365) * 100).toFixed(2)
};
}
async calculateSharpeRatio(portfolioData) {
const returns = await this.getHistoricalReturns(portfolioData, 365);
if (returns.length < 30) return null;
const avgReturn = returns.reduce((sum, r) => sum + r, 0) / returns.length;
const annualizedReturn = avgReturn * 365;
const stdDev = Math.sqrt(
returns.reduce((sum, r) => sum + Math.pow(r - avgReturn, 2), 0) / (returns.length - 1)
);
const annualizedStdDev = stdDev * Math.sqrt(365);
const sharpeRatio = (annualizedReturn - this.riskFreeRate) / annualizedStdDev;
return {
value: sharpeRatio.toFixed(3),
interpretation: this.interpretSharpeRatio(sharpeRatio)
};
}
interpretSharpeRatio(ratio) {
if (ratio < 0) return 'POOR - Returns below risk-free rate';
if (ratio < 0.5) return 'SUBOPTIMAL - Low risk-adjusted returns';
if (ratio < 1.0) return 'ACCEPTABLE - Moderate risk-adjusted returns';
if (ratio < 2.0) return 'GOOD - Strong risk-adjusted returns';
return 'EXCELLENT - Outstanding risk-adjusted returns';
}
async calculateCorrelations(portfolioData) {
if (portfolioData.length < 2) return null;
const correlationMatrix = [];
const symbols = portfolioData.map(p => p.symbol);
for (let i = 0; i < symbols.length; i++) {
const row = [];
for (let j = 0; j < symbols.length; j++) {
if (i === j) {
row.push(1.0);
} else {
const correlation = await this.calculatePairCorrelation(
symbols[i],
symbols[j],
30 // 30-day correlation
);
row.push(correlation);
}
}
correlationMatrix.push(row);
}
// Find highest correlations
const highCorrelations = [];
for (let i = 0; i < symbols.length; i++) {
for (let j = i + 1; j < symbols.length; j++) {
if (Math.abs(correlationMatrix[i][j]) > 0.7) {
highCorrelations.push({
pair: `${symbols[i]}-${symbols[j]}`,
correlation: correlationMatrix[i][j].toFixed(3),
interpretation: correlationMatrix[i][j] > 0 ? 'POSITIVE' : 'NEGATIVE'
});
}
}
}
return {
matrix: correlationMatrix,
symbols,
highCorrelations,
averageCorrelation: this.calculateAverageCorrelation(correlationMatrix)
};
}
calculateValueAtRisk(portfolioData, confidenceLevel) {
const returns = this.historicalData.get('portfolio_returns') || [];
if (returns.length < 100) return null;
const sortedReturns = returns.sort((a, b) => a - b);
const index = Math.floor((1 - confidenceLevel) * sortedReturns.length);
const var_value = sortedReturns[index];
const totalValue = portfolioData.reduce((sum, p) => sum + p.currentValue, 0);
return {
percentage: (var_value * 100).toFixed(2),
dollarAmount: (totalValue * var_value).toFixed(2),
confidenceLevel: (confidenceLevel * 100).toFixed(0),
interpretation: `${confidenceLevel * 100}% chance that losses won't exceed $${Math.abs(totalValue * var_value).toFixed(2)}`
};
}
assessRisk(metrics) {
const riskFactors = [];
let riskScore = 0;
// Concentration risk
if (metrics.concentration.topAssetConcentration > 50) {
riskFactors.push({
type: 'CONCENTRATION',
severity: 'HIGH',
description: `Top asset represents ${metrics.concentration.topAssetConcentration}% of portfolio`
});
riskScore += 30;
}
// Volatility risk
if (metrics.volatility && metrics.volatility.annual > 100) {
riskFactors.push({
type: 'VOLATILITY',
severity: 'HIGH',
description: `Annual volatility exceeds 100% (${metrics.volatility.annual}%)`
});
riskScore += 25;
}
// Correlation risk
if (metrics.correlations && metrics.correlations.highCorrelations.length > 0) {
riskFactors.push({
type: 'CORRELATION',
severity: 'MEDIUM',
description: `${metrics.correlations.highCorrelations.length} asset pairs highly correlated`
});
riskScore += 15;
}
// Drawdown risk
if (metrics.maxDrawdown && metrics.maxDrawdown.percentage > 40) {
riskFactors.push({
type: 'DRAWDOWN',
severity: 'HIGH',
description: `Maximum drawdown of ${metrics.maxDrawdown.percentage}% observed`
});
riskScore += 20;
}
return {
overallScore: Math.min(riskScore, 100),
level: this.determineRiskLevel(riskScore),
factors: riskFactors,
recommendations: this.generateRiskRecommendations(riskFactors)
};
}
determineRiskLevel(score) {
if (score < 20) return 'LOW';
if (score < 40) return 'MODERATE';
if (score < 60) return 'ELEVATED';
if (score < 80) return 'HIGH';
return 'CRITICAL';
}
generateRebalancingPlan(portfolioData, metrics) {
const currentAllocations = metrics.allocation;
const targetAllocations = this.calculateOptimalAllocation(portfolioData, metrics);
const totalValue = metrics.totalValue;
const rebalancingActions = [];
currentAllocations.forEach((current, index) => {
const target = targetAllocations[index];
const currentValue = current.value;
const targetValue = (target.percentage / 100) * totalValue;
const difference = targetValue - currentValue;
if (Math.abs(difference) > totalValue * 0.01) { // Only rebalance if > 1% of portfolio
rebalancingActions.push({
symbol: current.symbol,
action: difference > 0 ? 'BUY' : 'SELL',
amount: Math.abs(difference).toFixed(2),
currentPercentage: current.percentage.toFixed(2),
targetPercentage: target.percentage.toFixed(2),
reason: target.reason
});
}
});
return {
actions: rebalancingActions,
estimatedCost: this.estimateRebalancingCost(rebalancingActions),
expectedImprovement: this.estimateImprovementMetrics(targetAllocations, currentAllocations)
};
}
calculateOptimalAllocation(portfolioData, metrics) {
// Modern Portfolio Theory optimization
// This is a simplified version - real implementation would use quadratic programming
const riskTolerance = this.determineRiskTolerance(metrics);
const correlations = metrics.correlations?.matrix || [];
// Start with equal weight
let allocations = portfolioData.map(p => ({
symbol: p.symbol,
percentage: 100 / portfolioData.length,
reason: 'Equal weight baseline'
}));
// Adjust based on performance
allocations = this.adjustForPerformance(allocations, portfolioData);
// Adjust based on risk
allocations = this.adjustForRisk(allocations, metrics, riskTolerance);
// Adjust based on correlations
if (correlations.length > 0) {
allocations = this.adjustForCorrelations(allocations, correlations);
}
// Apply constraints
allocations = this.applyAllocationConstraints(allocations);
return allocations;
}
adjustForPerformance(allocations, portfolioData) {
// Increase allocation to better performers
const performances = portfolioData.map(p => ({
symbol: p.symbol,
performance: p.pnlPercentage
})).sort((a, b) => b.performance - a.performance);
return allocations.map(alloc => {
const perf = performances.find(p => p.symbol === alloc.symbol);
const rank = performances.indexOf(perf);
// Top 1/3 get boost, bottom 1/3 get reduction
if (rank < performances.length / 3) {
alloc.percentage *= 1.2;
alloc.reason = 'Strong performance';
} else if (rank > (performances.length * 2 / 3)) {
alloc.percentage *= 0.8;
alloc.reason = 'Weak performance';
}
return alloc;
});
}
applyAllocationConstraints(allocations) {
// No single asset > 40%
const maxAllocation = 40;
// No single asset < 5%
const minAllocation = 5;
// Normalize to ensure sum = 100
const total = allocations.reduce((sum, a) => sum + a.percentage, 0);
allocations = allocations.map(a => ({
...a,
percentage: (a.percentage / total) * 100
}));
// Apply constraints
allocations = allocations.map(alloc => ({
...alloc,
percentage: Math.min(Math.max(alloc.percentage, minAllocation), maxAllocation)
}));
// Re-normalize
const newTotal = allocations.reduce((sum, a) => sum + a.percentage, 0);
return allocations.map(a => ({
...a,
percentage: (a.percentage / newTotal) * 100
}));
}
}
2. Portfolio Visualization
class PortfolioVisualizer {
generateReport(analysis) {
return `
╔════════════════════════════════════════════════════════════════════════════╗
║ PORTFOLIO ANALYSIS REPORT ║
╠════════════════════════════════════════════════════════════════════════════╣
║ SUMMARY METRICS ║
╠════════════════════════════════════════════════════════════════════════════╣
║ Total Value: $${analysis.metrics.totalValue.toFixed(2).padEnd(55)} ║
║ Total Cost: $${analysis.metrics.totalCost.toFixed(2).padEnd(55)} ║
║ Total P&L: ${this.formatPnL(analysis.metrics.totalPnL).padEnd(56)} ║
║ Total Return: ${this.formatPercentage(analysis.metrics.totalReturn).padEnd(56)} ║
╠════════════════════════════════════════════════════════════════════════════╣
║ RISK METRICS ║
╠════════════════════════════════════════════════════════════════════════════╣
║ Risk Level: ${analysis.riskAssessment.level.padEnd(56)} ║
║ Risk Score: ${(analysis.riskAssessment.overallScore + '/100').padEnd(56)} ║
║ Sharpe Ratio: ${analysis.metrics.sharpeRatio?.value || 'N/A'.padEnd(56)} ║
║ Annual Volatility: ${analysis.metrics.volatility?.annual + '%' || 'N/A'.padEnd(56)} ║
║ Max Drawdown: ${analysis.metrics.maxDrawdown?.percentage + '%' || 'N/A'.padEnd(56)} ║
║ VaR (95%): ${analysis.metrics.var95?.dollarAmount || 'N/A'.padEnd(56)} ║
╠════════════════════════════════════════════════════════════════════════════╣
║ ASSET ALLOCATION ║
╠════════════════════════════════════════════════════════════════════════════╣
${this.formatAllocationTable(analysis.metrics.allocation)}
╠════════════════════════════════════════════════════════════════════════════╣
║ CONCENTRATION ANALYSIS ║
╠════════════════════════════════════════════════════════════════════════════╣
║ Herfindahl Index: ${analysis.metrics.concentration.herfindahlIndex.padEnd(56)} ║
║ Effective Assets: ${analysis.metrics.concentration.effectiveAssets.padEnd(56)} ║
║ Top Asset: ${analysis.metrics.concentration.topAssetConcentration + '%'.padEnd(56)} ║
║ Top 3 Assets: ${analysis.metrics.concentration.top3Concentration + '%'.padEnd(56)} ║
╠════════════════════════════════════════════════════════════════════════════╣
║ REBALANCING RECOMMENDATIONS ║
╠════════════════════════════════════════════════════════════════════════════╣
${this.formatRebalancingActions(analysis.rebalancingPlan.actions)}
╠════════════════════════════════════════════════════════════════════════════╣
║ RISK FACTORS ║
╠════════════════════════════════════════════════════════════════════════════╣
${this.formatRiskFactors(analysis.riskAssessment.factors)}
╚════════════════════════════════════════════════════════════════════════════╝
`;
}
formatAllocationTable(allocations) {
return allocations.slice(0, 5).map(a =>
`║ ${a.symbol.padEnd(10)} ${(a.percentage.toFixed(2) + '%').padEnd(10)} $${a.value.toFixed(2).padEnd(15)} ${this.getAllocationBar(a.percentage).padEnd(20)} ║`
).join('\n');
}
getAllocationBar(percentage) {
const barLength = Math.floor(percentage / 5);
return '█'.repeat(Math.min(barLength, 20));
}
formatRebalancingActions(actions) {
if (actions.length === 0) {
return '║ Portfolio is well-balanced. No actions required. ║';
}
return actions.slice(0, 3).map(a =>
`║ ${a.action.padEnd(5)} ${a.symbol.padEnd(6)} $${a.amount.padEnd(10)} (${a.currentPercentage}% → ${a.targetPercentage}%)`.padEnd(77) + '║'
).join('\n');
}
formatRiskFactors(factors) {
if (factors.length === 0) {
return '║ No significant risk factors identified. ║';
}
return factors.map(f =>
`║ [${f.severity}] ${f.type}: ${f.description}`.padEnd(77) + '║'
).join('\n');
}
formatPnL(value) {
const formatted = `$${Math.abs(value).toFixed(2)}`;
return value >= 0 ? `+${formatted} ` : `-${formatted} `;
}
formatPercentage(value) {
const formatted = `${Math.abs(value).toFixed(2)}%`;
return value >= 0 ? `+${formatted} ` : `-${formatted} `;
}
}
3. Optimization Strategies
class PortfolioOptimizer {
suggestOptimizations(metrics) {
const suggestions = [];
// Diversification suggestions
if (metrics.concentration.effectiveAssets < 3) {
suggestions.push({
priority: 'HIGH',
category: 'DIVERSIFICATION',
action: 'Add more uncorrelated assets',
benefit: 'Reduce concentration risk by 30-40%',
implementation: `
Consider adding:
- Large cap altcoins (ETH, BNB) if heavily in BTC
- DeFi tokens if heavily in L1s
- Stablecoins for risk reduction
`
});
}
// Rebalancing suggestions
if (metrics.allocation.some(a => a.deviation > 10)) {
suggestions.push({
priority: 'MEDIUM',
category: 'REBALANCING',
action: 'Rebalance to target allocations',
benefit: 'Improve risk-adjusted returns',
implementation: `
Set up periodic rebalancing:
- Monthly for volatile markets
- Quarterly for stable markets
- Threshold-based (when deviation > 15%)
`
});
}
// Risk management suggestions
if (!metrics.stopLossesSet) {
suggestions.push({
priority: 'HIGH',
category: 'RISK_MANAGEMENT',
action: 'Implement stop-loss orders',
benefit: 'Limit downside risk',
implementation: `
Recommended stop-loss levels:
- Conservative: 15% below entry
- Moderate: 25% below entry
- Aggressive: 35% below entry
`
});
}
// Performance suggestions
if (metrics.sharpeRatio && metrics.sharpeRatio.value < 0.5) {
suggestions.push({
priority: 'MEDIUM',
category: 'PERFORMANCE',
action: 'Improve risk-adjusted returns',
benefit: 'Better Sharpe ratio',
implementation: `
Options to improve:
- Reduce allocation to high-volatility assets
- Add yield-generating positions (staking, lending)
- Consider market-neutral strategies
`
});
}
return suggestions;
}
}
Error Handling
async function executePortfolioAnalysis() {
try {
const analyzer = new PortfolioAnalyzer();
const visualizer = new PortfolioVisualizer();
// Get all open positions
const positions = await getOpenPositions();
if (positions.length === 0) {
console.log('No positions found. Start by tracking some positions first.');
return;
}
// Run analysis
console.log('Analyzing portfolio...');
const analysis = await analyzer.analyzePortfolio(positions);
// Display report
const report = visualizer.generateReport(analysis);
console.log(report);
// Save analysis
await saveAnalysis(analysis);
} catch (error) {
console.error('Portfolio analysis failed:', error.message);
if (error.code === 'INSUFFICIENT_DATA') {
console.log('Not enough historical data for full analysis. Some metrics may be unavailable.');
} else if (error.code === 'API_ERROR') {
console.log('Failed to fetch market data. Please check your internet connection.');
}
}
}
This comprehensive portfolio analysis command provides institutional-grade analytics for crypto portfolios with actionable insights and optimization recommendations.
Stats
Stars1669
Forks210
Last CommitDec 26, 2025