analyze_correlation
Calculate correlation matrices and diversification ratios for multi-asset portfolios to identify concentration risks and optimize allocation.
Instructions
Cross-asset correlation matrix and diversification ratio. Returns the full N×N correlation matrix, average pairwise correlation, diversification ratio (DR>1 = benefit), and asset-class pair correlations. Payment: $0.02 USDC on Tempo chain.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| holdings | Yes | ||
| profile | No | Risk profile — affects rebalance targets and scoring. Default: balanced. | |
| benchmarkReturn | No | Annual benchmark return for Sharpe calculation, e.g. 0.08 = 8%. Default: 0.08. | |
| riskFreeRate | No | Annual risk-free rate for Sortino and VaR excess return, e.g. 0.05 = 5%. Default: 0.05. | |
| rebalanceMethod | No | Portfolio construction method for rebalance recommendations. Default: profile. | |
| marketIndicators | No | Optional macro indicators — improves market regime detection confidence to HIGH when 3+ provided. |
Implementation Reference
- src/analyze/correlation.ts:200-256 (handler)The `analyzeCorrelation` function computes the correlation matrix and diversification metrics for a given portfolio, optionally utilizing historical price series data.
export function analyzeCorrelation( portfolio: Portfolio, returnSeries?: Record<string, number[]>, ): CorrelationResult { const holdings = portfolio.holdings // Track whether we used any real price data const hasRealData = returnSeries ? holdings.some((h) => returnSeries[h.asset.toUpperCase()]?.length >= MIN_SERIES_LENGTH) : false // Build full N×N correlation matrix const matrix: CorrelationEntry[] = holdings.map((hi) => { const correlations: Record<string, number> = {} for (const hj of holdings) { const corr = resolvePairCorrelation( hi.asset, hj.asset, hi.assetClass, hj.assetClass, hi.sector, hj.sector, returnSeries, ) correlations[hj.asset] = Number(corr.toFixed(4)) } return { asset: hi.asset, assetClass: hi.assetClass, correlations } }) // Weighted average pairwise correlation (off-diagonal only) let weightedCorrSum = 0 let totalPairWeight = 0 for (let i = 0; i < holdings.length; i++) { for (let j = i + 1; j < holdings.length; j++) { const corr = resolvePairCorrelation( holdings[i].asset, holdings[j].asset, holdings[i].assetClass, holdings[j].assetClass, holdings[i].sector, holdings[j].sector, returnSeries, ) const pairWeight = holdings[i].weight * holdings[j].weight weightedCorrSum += corr * pairWeight totalPairWeight += pairWeight } } const avgPairwiseCorrelation = totalPairWeight > 0 ? Number((weightedCorrSum / totalPairWeight).toFixed(4)) : 1 const pVol = portfolioVol(portfolio, returnSeries) const diversificationRatio = computeDiversificationRatio(portfolio, pVol) const assetClassCorrelations = assetClassCorrelationSummary(portfolio, returnSeries) return { matrix, avgPairwiseCorrelation, diversificationRatio, assetClassCorrelations, interpretation: buildInterpretation(avgPairwiseCorrelation, diversificationRatio, hasRealData), } }