analyze_rebalance
Optimize portfolio allocations using four rebalancing methods with live market data. Get target weights, current weights, and specific actions (increase/reduce/hold) for each asset.
Instructions
Portfolio rebalancing recommendations with live market data. Four methods: profile (conservative/balanced/aggressive), risk_parity (inverse-vol weighting), min_variance (inverse-variance), equal_weight (1/N). Returns target weight, current weight, action (increase/reduce/hold), and delta per asset. Known crypto tickers auto-enriched with real volatility data. Payment: $0.02 USDC on Tempo.
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/rebalance.ts:132-167 (handler)The main handler function for rebalancing logic, which calculates target weights and generates rebalance suggestions based on the portfolio's method and profile.
export function analyzeRebalance(portfolio: Portfolio): RebalanceResult { const targets = computeTargets(portfolio.holdings, portfolio.profile, portfolio.rebalanceMethod) const roundedTargets = targets.map((t) => Number(t.toFixed(4))) // Absorb rounding error into the largest-weight suggestion so client sums always equal 1.0 const roundedSum = roundedTargets.reduce((a, b) => a + b, 0) const roundingError = Number((1 - roundedSum).toFixed(4)) if (roundingError !== 0 && roundedTargets.length > 0) { const maxIdx = roundedTargets.reduce((best, v, i) => (v > roundedTargets[best] ? i : best), 0) roundedTargets[maxIdx] = Number((roundedTargets[maxIdx] + roundingError).toFixed(4)) } const suggestions: RebalanceSuggestion[] = portfolio.holdings.map((h, i) => { const delta = Number((roundedTargets[i] - h.weight).toFixed(4)) const action: RebalanceSuggestion['action'] = Math.abs(delta) < 0.02 ? 'hold' : delta > 0 ? 'increase' : 'reduce' return { asset: h.asset, currentWeight: h.weight, targetWeight: roundedTargets[i], action, delta, } }) const targetWeightsSum = Number( targets.reduce((a, b) => a + b, 0).toFixed(6), ) return { method: portfolio.rebalanceMethod, profile: portfolio.profile, suggestions, targetWeightsSum, } }