Complete implementation of advanced portfolio analytics engine featuring performance attribution, comprehensive risk metrics (volatility, Sharpe ratio, max drawdown, beta, VaR), benchmark comparisons against major indices, and historical trend analysis.
Users previously lacked visibility into:
- Which assets/sectors drive portfolio returns
- Risk metrics (volatility, Sharpe ratio, drawdown)
- Performance comparison against benchmarks (S&P 500, MSCI World, etc.)
- Historical performance trends and patterns
File: backend/services/performanceAttributionService.js
Calculates comprehensive risk metrics:
- Volatility: Annualized standard deviation of returns
- Sharpe Ratio: Risk-adjusted return metric
- Sortino Ratio: Downside risk-adjusted return
- Calmar Ratio: Return to max drawdown ratio
- Maximum Drawdown: Largest peak-to-trough decline
- Beta: Sensitivity to market movements (vs S&P 500)
- VaR (95%): Value at Risk at 95% confidence
- CVaR (95%): Conditional VaR (expected shortfall)
Returns:
{
success: true,
period: { start, end },
volatility: "15.23", // Annualized %
sharpeRatio: "1.234",
sortinoRatio: "1.567",
calmarRatio: "2.345",
maxDrawdown: "12.45", // %
beta: "0.987",
var95: "-2.34", // %
cvar95: "-3.12", // %
avgDailyReturn: "0.0543",
annualizedReturn: "14.23",
sampleSize: 252
}Compares portfolio against major market benchmarks:
- S&P 500 (SPY)
- NASDAQ 100 (QQQ)
- MSCI World (ACWI)
- MSCI EAFE (EFA)
- US Aggregate Bonds (AGG)
- Gold (GLD)
- Real Estate/REITs (VNQ)
- Bitcoin (BTC-USD)
Calculates:
- Portfolio vs benchmark returns
- Alpha (excess return)
- Relative performance
- Outperformance indicators
Returns:
{
success: true,
period: { start, end },
portfolioReturn: "18.45",
comparisons: [
{
benchmark: "S&P 500",
symbol: "SPY",
portfolioReturn: "18.45",
benchmarkReturn: "15.20",
alpha: "3.25", // Excess return
outperforming: true,
relativePerformance: "21.38" // % better
},
// ... more benchmarks
]
}Analyzes historical performance patterns:
- 30-day and 90-day trend analysis
- Momentum calculation (acceleration/deceleration)
- Volatility trend (increasing/decreasing/stable)
- Market regime identification (bull/bear/sideways)
- Rolling returns and volatility metrics
Returns:
{
success: true,
period: { start, end },
trend: "upward",
trend30Day: "0.0125",
trend90Day: "0.0098",
momentum: "0.0027",
momentumSignal: "accelerating",
volatilityTrend: "decreasing",
volatility30Day: "1.234",
volatility90Day: "1.543",
regime: "bull_market",
rollingMetrics: {
returns: [...],
volatility: [...]
}
}calculateStdDev(values)- Standard deviation calculationcalculateMaxDrawdown(snapshots)- Peak-to-trough analysiscalculateSortinoRatio(returns, riskFreeRate)- Downside risk metriccalculateBeta(userId, returns, periodStart, periodEnd)- Market sensitivitygetBenchmarkReturn(symbol, startDate, endDate)- Fetch/cache benchmark datagetBenchmarkReturns(symbol, startDate, endDate)- Time series benchmark datacalculateReturnsFromPrices(prices)- Convert prices to returnsgetPortfolioTimeSeries(userId, startDate, endDate, vaultId)- Fetch snapshotscalculateLinearTrend(data)- Least squares trend linecalculateRollingReturns(returns, window)- Rolling period analysiscalculateRollingVolatility(returns, window)- Rolling volatilityidentifyMarketRegime(returns)- Bull/bear/sideways classification
File: backend/routes/analytics.js
Query Parameters:
startDate(required) - Analysis start dateendDate(required) - Analysis end datevaultId(optional) - Specific vault/portfolio
Response: Complete attribution breakdown by asset class, sector, holding, and geography
Query Parameters:
startDate(required)endDate(required)vaultId(optional)
Response: All risk metrics (volatility, Sharpe, drawdown, beta, VaR, etc.)
Query Parameters:
startDate(required)endDate(required)vaultId(optional)
Response: Comparison against 8 major benchmarks with alpha calculations
Query Parameters:
startDate(required)endDate(required)vaultId(optional)
Response: Trend analysis with momentum and regime identification
Query Parameters:
startDate(required)endDate(required)vaultId(optional)
Response: ALL analytics in one call (attribution + risk + benchmarks + trends)
- Optimized with
Promise.all()for parallel execution - Single API call for dashboard views
Uses existing schema tables:
portfolioSnapshots- Time series portfolio valuesbenchmarkPrices- Cached benchmark historical databenchmarkComparisons- Stored comparison resultsperformanceAttributions- Attribution analysis logs
GET /api/analytics/portfolio/risk-metrics?startDate=2025-01-01&endDate=2026-03-03
Response:
{
"success": true,
"data": {
"volatility": "15.23",
"sharpeRatio": "1.234",
"maxDrawdown": "12.45",
"beta": "0.987",
"var95": "-2.34",
"cvar95": "-3.12"
}
}GET /api/analytics/portfolio/benchmark-comparison?startDate=2025-01-01&endDate=2026-03-03
Response:
{
"success": true,
"data": {
"portfolioReturn": "18.45",
"comparisons": [
{
"benchmark": "S&P 500",
"portfolioReturn": "18.45",
"benchmarkReturn": "15.20",
"alpha": "3.25",
"outperforming": true
},
{
"benchmark": "NASDAQ 100",
"portfolioReturn": "18.45",
"benchmarkReturn": "22.10",
"alpha": "-3.65",
"outperforming": false
}
]
}
}GET /api/analytics/portfolio/performance-trends?startDate=2025-01-01&endDate=2026-03-03
Response:
{
"success": true,
"data": {
"trend": "upward",
"momentum": "0.0027",
"momentumSignal": "accelerating",
"volatilityTrend": "decreasing",
"regime": "bull_market"
}
}GET /api/analytics/portfolio/comprehensive?startDate=2025-01-01&endDate=2026-03-03
Response:
{
"success": true,
"data": {
"attribution": { /* full attribution */ },
"riskMetrics": { /* all risk metrics */ },
"benchmarkComparison": { /* all benchmarks */ },
"trends": { /* trend analysis */ },
"generatedAt": "2026-03-03T10:30:00Z"
}
}- Asset-level contribution to returns
- Sector-level aggregation
- Weight and return calculations
- Contribution decomposition
- Volatility (annualized)
- Sharpe Ratio
- Sortino Ratio (downside risk)
- Calmar Ratio
- Maximum Drawdown
- Beta (market correlation)
- Value at Risk (VaR)
- Conditional VaR (CVaR)
- 8 major market indices
- Alpha calculation
- Relative performance
- Automatic data caching
- Historical price storage
- Multiple timeframe trends (30/90 day)
- Momentum indicators
- Volatility trend tracking
- Market regime classification
- Rolling metrics
- Parallel API execution
- Benchmark data caching
- Efficient time-series queries
- Minimal database hits
// Fetches from market data service only if not cached
// Stores in benchmarkPrices table for future use
const benchmarkReturn = await this.getBenchmarkReturn('SPY', startDate, endDate);const riskFreeRate = 0.02; // 2% assumption
// Can be made configurable for different marketsconst annualizedVolatility = dailyVolatility * Math.sqrt(252); // 252 trading days
const annualizedReturn = Math.pow(1 + avgDailyReturn, 252) - 1;// Covariance(portfolio, market) / Variance(market)
// Uses S&P 500 (SPY) as market proxy
beta = covariance / marketVariance;All endpoints return structured error responses:
{
"success": false,
"message": "Insufficient data for risk calculation"
}Common error cases handled:
- Insufficient historical data (< 2 snapshots)
- Missing benchmark data
- Invalid date ranges
- Network failures on market data fetch
- Risk metric calculations with known data
- Benchmark return calculations
- Trend analysis with synthetic data
- Edge cases (zero volatility, negative returns)
- API endpoint responses
- Database interactions
- Caching behavior
- Error scenarios
- Large portfolios (1000+ assets)
- Long time periods (10+ years)
- Multiple concurrent requests
- Benchmark data fetching
- ✅ All endpoints protected with
protectmiddleware - ✅ User isolation (can only access own portfolio)
- ✅ Vault-level permissions respected
- ✅ No sensitive data in error messages
- Configurable Risk-Free Rate - Per-market adjustment
- Custom Benchmarks - User-defined comparison indices
- Factor Attribution - Fama-French multi-factor analysis
- Monte Carlo Simulations - Probabilistic forecasting
- Correlation Matrix - Asset correlation heatmaps
- Attribution Charts - Visual decomposition
- Stress Testing - Scenario analysis
- Information Ratio - Risk-adjusted alpha
- Tracking Error - Benchmark deviation measurement
- Real-time Updates - WebSocket streaming metrics
drizzle-orm- Database queriesmarketDataservice - Historical price data- Existing
portfolioSnapshotsinfrastructure - Existing
benchmarkPricesandbenchmarkComparisonstables
- Service methods implemented
- API routes created
- Database schema verified
- Error handling added
- Unit tests written
- Integration tests added
- API documentation updated
- Frontend integration points defined
- Performance benchmarking completed
- Monitoring/logging configured
All endpoints include Swagger annotations for automatic API documentation generation.
- No database migrations required (uses existing tables)
- No breaking changes to existing endpoints
- Backward compatible with current analytics
- Can be deployed incrementally
Users now have complete visibility into:
✅ Which assets drive portfolio performance
✅ Portfolio risk profile (volatility, max loss potential)
✅ Performance vs major market benchmarks
✅ Historical trends and momentum
✅ Risk-adjusted returns (Sharpe, Sortino)
✅ Market correlation (beta)
- Closes #694
- Enhances #653 (Portfolio Analytics)
- Complements existing asset tracking
backend/services/performanceAttributionService.js- Extended with 500+ linesbackend/routes/analytics.js- Added 5 new endpoints
- Service additions: ~600 lines
- Route additions: ~100 lines
- Total: ~700 lines of production code
Implementation Status: ✅ COMPLETE
Date: March 3, 2026
Issue: #694
Feature: Portfolio Performance Attribution & Risk Analytics Engine