analyze_risk
Assess crypto portfolio risk using live market data. Calculates Sharpe ratio, risk tier, and per-asset scores based on holdings and weights.
Instructions
Crypto portfolio risk profiling using live CoinGecko market data. For known tickers (BTC, ETH, SOL, AVAX, ARB, etc.) you only need { asset, weight } — volatility, returns, and drawdown are auto-fetched from 365-day real price history. Returns Sharpe ratio, Sortino ratio, Calmar ratio, market beta, risk tier (low/moderate/high/very high), and per-asset risk scores. Payment: $0.01 USDC on Tempo chain (~500ms).
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/risk-profile.ts:169-207 (handler)The main implementation of analyzeRisk which calculates risk metrics for a portfolio including volatility, sharpe ratio, sortino ratio, and beta.
export function analyzeRisk( portfolio: Portfolio, returnSeries?: Record<string, number[]>, ): RiskResult { const portVol = portfolioVolatility(portfolio.holdings, returnSeries) const assets: AssetRisk[] = portfolio.holdings.map((h) => { const effectiveBeta = resolveEffectiveBeta(h, returnSeries) return { asset: h.asset, assetClass: h.assetClass, riskScore: Number(assetRiskScore(h.volatility, h.maxDrawdown, h.isStable).toFixed(1)), sharpe: sharpeRatio(h.avgReturn, portfolio.benchmarkReturn, h.volatility), sortino: sortinoRatio(h.avgReturn, portfolio.riskFreeRate, h.volatility), beta: Number(effectiveBeta.toFixed(4)), } }) const portfolioRisk = portfolio.holdings.reduce( (acc, h, i) => acc + h.weight * assets[i].riskScore, 0, ) const weightedReturn = portfolio.holdings.reduce((acc, h) => acc + h.weight * h.avgReturn, 0) const weightedMaxDD = portfolio.holdings.reduce((acc, h) => acc + h.weight * h.maxDrawdown, 0) const portfolioBeta = assets.reduce((acc, a, i) => acc + portfolio.holdings[i].weight * a.beta, 0) return { portfolioRisk: Number(portfolioRisk.toFixed(1)), portfolioVolatility: Number(portVol.toFixed(4)), portfolioSharpe: sharpeRatio(weightedReturn, portfolio.benchmarkReturn, portVol), portfolioSortino: sortinoRatio(weightedReturn, portfolio.riskFreeRate, portVol), portfolioCalmar: calmarRatio(weightedReturn, weightedMaxDD), portfolioBeta: Number(portfolioBeta.toFixed(4)), riskTier: riskTier(portfolioRisk), assets, } }