Skip to main content
Glama
dun999

FinSight

analyze_compare

Compare two investment portfolios across 9 key risk and performance metrics to identify superior strategies or evaluate rebalancing options.

Instructions

Side-by-side comparison of two portfolios across 9 key metrics: Sharpe ratio, Sortino ratio, VaR, CVaR, max drawdown, diversification score, stress test loss, market beta, and overall risk tier. Returns winner per metric and delta values. Useful for A/B testing portfolio strategies or comparing current vs. rebalanced allocation. Costs $0.05 USDC.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
portfolio_aYesFirst portfolio to compare.
portfolio_bYesSecond portfolio to compare against portfolio_a.

Implementation Reference

  • The implementation of the `analyzeCompare` tool handler, which computes and compares various risk, VaR, and diversification metrics between two portfolios to determine an overall recommendation.
    export function analyzeCompare(portfolioA: Portfolio, portfolioB: Portfolio): CompareResult {
      const riskA = analyzeRisk(portfolioA)
      const riskB = analyzeRisk(portfolioB)
      const varA  = analyzeVaR(portfolioA)
      const varB  = analyzeVaR(portfolioB)
      const divA  = analyzeDiversification(portfolioA)
      const divB  = analyzeDiversification(portfolioB)
    
      const metrics: MetricComparison[] = [
        {
          metric: 'Sharpe Ratio',
          portfolio_a: riskA.portfolioSharpe,
          portfolio_b: riskB.portfolioSharpe,
          winner: winner(riskA.portfolioSharpe, riskB.portfolioSharpe, true, 0.02),
          delta: riskA.portfolioSharpe - riskB.portfolioSharpe,
          description: 'Risk-adjusted return per unit of total volatility. Higher is better.',
        },
        {
          metric: 'Sortino Ratio',
          portfolio_a: riskA.portfolioSortino,
          portfolio_b: riskB.portfolioSortino,
          winner: winner(riskA.portfolioSortino, riskB.portfolioSortino, true, 0.02),
          delta: riskA.portfolioSortino - riskB.portfolioSortino,
          description: 'Return relative to downside risk only. Higher is better.',
        },
        {
          metric: 'Calmar Ratio',
          portfolio_a: riskA.portfolioCalmar,
          portfolio_b: riskB.portfolioCalmar,
          winner: winner(riskA.portfolioCalmar, riskB.portfolioCalmar, true, 0.02),
          delta: riskA.portfolioCalmar - riskB.portfolioCalmar,
          description: 'Return relative to max drawdown. Higher is better.',
        },
        {
          metric: 'Annual Volatility',
          portfolio_a: riskA.portfolioVolatility,
          portfolio_b: riskB.portfolioVolatility,
          winner: winner(riskA.portfolioVolatility, riskB.portfolioVolatility, false, 0.005),
          delta: riskA.portfolioVolatility - riskB.portfolioVolatility,
          description: 'Annualised price fluctuation. Lower is better for capital-preservation goals.',
        },
        {
          metric: 'Market Beta',
          portfolio_a: riskA.portfolioBeta,
          portfolio_b: riskB.portfolioBeta,
          winner: winner(Math.abs(riskA.portfolioBeta - 1), Math.abs(riskB.portfolioBeta - 1), false, 0.05),
          delta: riskA.portfolioBeta - riskB.portfolioBeta,
          description: 'Sensitivity to broad market movements. Lower = more defensive.',
        },
        {
          metric: 'VaR 95% Daily',
          portfolio_a: varA.confidence95.dailyVaR,
          portfolio_b: varB.confidence95.dailyVaR,
          winner: winner(varA.confidence95.dailyVaR, varB.confidence95.dailyVaR, false, 0.001),
          delta: varA.confidence95.dailyVaR - varB.confidence95.dailyVaR,
          description: 'Daily downside at 95% confidence (loss fraction). Lower is better.',
        },
        {
          metric: 'CVaR 99% Annual',
          portfolio_a: varA.confidence99.annualCVaR,
          portfolio_b: varB.confidence99.annualCVaR,
          winner: winner(varA.confidence99.annualCVaR, varB.confidence99.annualCVaR, false, 0.005),
          delta: varA.confidence99.annualCVaR - varB.confidence99.annualCVaR,
          description: 'Expected annual loss in worst 1% of years (loss fraction). Lower is better.',
        },
        {
          metric: 'HHI Concentration',
          portfolio_a: divA.hhi,
          portfolio_b: divB.hhi,
          winner: winner(divA.hhi, divB.hhi, false, 100),
          delta: divA.hhi - divB.hhi,
          description: 'Herfindahl-Hirschman concentration index (0–10000). Lower = better diversified.',
        },
        {
          metric: 'Effective Assets',
          portfolio_a: divA.effectiveAssets,
          portfolio_b: divB.effectiveAssets,
          winner: winner(divA.effectiveAssets, divB.effectiveAssets, true, 0.1),
          delta: divA.effectiveAssets - divB.effectiveAssets,
          description: 'Equivalent independent positions. Higher = better diversification.',
        },
      ]
    
      const aWins = metrics.filter((m) => m.winner === 'a').length
      const bWins = metrics.filter((m) => m.winner === 'b').length
      const total = metrics.length
    
      const overall_winner: 'a' | 'b' | 'tie' =
        aWins > bWins ? 'a' : bWins > aWins ? 'b' : 'tie'
    
      const a_advantages = metrics.filter((m) => m.winner === 'a').map((m) => m.metric)
      const b_advantages = metrics.filter((m) => m.winner === 'b').map((m) => m.metric)
    
      let recommendation: string
      if (overall_winner === 'a') {
        recommendation =
          `Portfolio A is stronger overall (wins ${aWins}/${total} metrics). ` +
          `Key advantages: ${a_advantages.join(', ')}.`
      } else if (overall_winner === 'b') {
        recommendation =
          `Portfolio B is stronger overall (wins ${bWins}/${total} metrics). ` +
          `Key advantages: ${b_advantages.join(', ')}.`
      } else {
        const aStr = a_advantages.length > 0 ? `A leads: ${a_advantages.join(', ')}` : ''
        const bStr = b_advantages.length > 0 ? `B leads: ${b_advantages.join(', ')}` : ''
        recommendation =
          `Portfolios are evenly matched. Choose based on your primary objective. ` +
          [aStr, bStr].filter(Boolean).join('. ') + '.'
      }
    
      return { metrics, overall_winner, a_advantages, b_advantages, recommendation }
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. Discloses critical behavioral traits: costs $0.05 USDC, returns 'winner per metric and delta values.' Lacks explicit read-only/non-destructive status and rate limit details, but cost transparency is valuable for a financial operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences with zero waste: first defines operation and metrics, second specifies return format, third gives use case and cost. Front-loaded with core functionality and appropriately sized for the complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

High complexity tool with rich nested input schema. Description adequately covers the 9 calculated metrics, return format (winner/delta), and cost without output schema. Minor gap: could specify return structure type (nested object vs array) for complete invocation confidence.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, establishing baseline 3. Description references 'two portfolios' aligning with portfolio_a and portfolio_b, but does not add semantic detail beyond the comprehensive schema (e.g., no guidance on constructing the holdings arrays or weight summing constraints beyond schema).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb (side-by-side comparison), resource (portfolios), and detailed scope (9 named metrics: Sharpe ratio, Sortino ratio, VaR, etc.). Explicitly references 'two portfolios' which distinguishes it from single-portfolio sibling tools like analyze_risk or analyze_diversification.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit use cases: 'A/B testing portfolio strategies' and 'comparing current vs. rebalanced allocation.' Clear context for when to invoke, though it does not explicitly name sibling alternatives or state when NOT to use (e.g., for single portfolio analysis).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dun999/finsight-mpp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server