Skip to main content
Glama
gtorreal
by gtorreal

get_market_sentiment

Compute a composite sentiment score (−100 to +100) for a Buda market using 24h price change, volume ratio, and spread. Returns a bearish/neutral/bullish label and component breakdown.

Instructions

Computes a composite sentiment score (−100 to +100) for a Buda.com market based on 24h price variation (40%), volume vs 7-day average (35%), and bid/ask spread vs baseline (25%). Returns a score, a label (bearish/neutral/bullish), and a full component breakdown. Example: 'Is the BTC-CLP market currently bullish or bearish?'

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
market_idYesMarket ID (e.g. 'BTC-CLP', 'ETH-BTC', 'BTC-USDT').

Implementation Reference

  • The main handler function that computes market sentiment: fetches ticker and volume data, calculates weighted scores from price variation (40%), volume ratio vs 7d avg (35%), and spread (25%), returning a composite score from -100 to +100 with a bearish/neutral/bullish label.
    export async function handleMarketSentiment(
      { market_id }: MarketSentimentArgs,
      client: BudaClient,
      cache: MemoryCache,
    ): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> {
      const validationError = validateMarketId(market_id);
      if (validationError) {
        return {
          content: [{ type: "text", text: JSON.stringify({ error: validationError, code: "INVALID_MARKET_ID" }) }],
          isError: true,
        };
      }
    
      try {
        const id = market_id.toLowerCase();
    
        const [tickerData, volumeData] = await Promise.all([
          cache.getOrFetch<TickerResponse>(
            `ticker:${id}`,
            CACHE_TTL.TICKER,
            () => client.get<TickerResponse>(`/markets/${id}/ticker`),
          ),
          client.get<VolumeResponse>(`/markets/${id}/volume`),
        ]);
    
        const ticker = tickerData.ticker;
        const vol = volumeData.volume;
    
        const bid = parseFloat(ticker.max_bid[0]);
        const ask = parseFloat(ticker.min_ask[0]);
        const priceVariation24h = parseFloat(ticker.price_variation_24h);
    
        const ask24h = parseFloat(vol.ask_volume_24h[0]);
        const bid24h = parseFloat(vol.bid_volume_24h[0]);
        const ask7d = parseFloat(vol.ask_volume_7d[0]);
        const bid7d = parseFloat(vol.bid_volume_7d[0]);
    
        const spreadPct = ask > 0 ? ((ask - bid) / ask) * 100 : 0;
        const spreadBaseline = isStablecoinPair(market_id) ? 0.3 : 1.0;
    
        const volume24h = ask24h + bid24h;
        const volume7d = ask7d + bid7d;
        const volumeRatio = volume7d > 0 ? (volume24h * 7) / volume7d : 1;
    
        // Price component: ±5% daily change → ±100 on this sub-score
        const priceRaw = clamp(priceVariation24h * 2000, -100, 100);
        const priceScore = parseFloat((priceRaw * 0.4).toFixed(4));
    
        // Volume component: ratio vs 7d daily average
        const volumeRaw = clamp((volumeRatio - 1) * 100, -100, 100);
        const volumeScore = parseFloat((volumeRaw * 0.35).toFixed(4));
    
        // Spread component: tighter spread is bullish
        const spreadRaw = clamp((1 - spreadPct / spreadBaseline) * 100, -100, 100);
        const spreadScore = parseFloat((spreadRaw * 0.25).toFixed(4));
    
        const score = parseFloat((priceScore + volumeScore + spreadScore).toFixed(1));
        const label: "bearish" | "neutral" | "bullish" =
          score < -20 ? "bearish" : score > 20 ? "bullish" : "neutral";
    
        const result = {
          market_id: ticker.market_id,
          score,
          label,
          component_breakdown: {
            price_variation_24h_pct: parseFloat((priceVariation24h * 100).toFixed(4)),
            volume_ratio: parseFloat(volumeRatio.toFixed(4)),
            spread_pct: parseFloat(spreadPct.toFixed(4)),
            spread_baseline_pct: spreadBaseline,
            price_score: priceScore,
            volume_score: volumeScore,
            spread_score: spreadScore,
          },
          data_timestamp: new Date().toISOString(),
          disclaimer:
            "Sentiment is derived from market microstructure data only. Not investment advice.",
        };
    
        return {
          content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
        };
      } catch (err) {
        const msg = formatApiError(err);
        return {
          content: [{ type: "text", text: JSON.stringify(msg) }],
          isError: true,
        };
      }
    }
  • Schema definition for the tool: name 'get_market_sentiment', description, and input schema requiring a 'market_id' string parameter.
    export const toolSchema = {
      name: "get_market_sentiment",
      description:
        "Computes a composite sentiment score (−100 to +100) for a Buda.com market based on " +
        "24h price variation (40%), volume vs 7-day average (35%), and bid/ask spread vs baseline (25%). " +
        "Returns a score, a label (bearish/neutral/bullish), and a full component breakdown. " +
        "Example: 'Is the BTC-CLP market currently bullish or bearish?'",
      inputSchema: {
        type: "object" as const,
        properties: {
          market_id: {
            type: "string",
            description: "Market ID (e.g. 'BTC-CLP', 'ETH-BTC', 'BTC-USDT').",
          },
        },
        required: ["market_id"],
      },
    };
  • Registration function that calls server.tool() with the schema name, description, market_id parameter (using zod), and a handler callback that delegates to handleMarketSentiment.
    export function register(server: McpServer, client: BudaClient, cache: MemoryCache): void {
      server.tool(
        toolSchema.name,
        toolSchema.description,
        {
          market_id: z
            .string()
            .describe("Market ID (e.g. 'BTC-CLP', 'ETH-BTC', 'BTC-USDT')."),
        },
        (args) => handleMarketSentiment(args, client, cache),
      );
    }
  • Helper functions: clamp() for numeric range limits, and isStablecoinPair() to detect stablecoin markets (USDT/USDC/DAI/TUSD) for adjusting spread baseline.
    function clamp(value: number, min: number, max: number): number {
      return Math.min(max, Math.max(min, value));
    }
    
    function isStablecoinPair(marketId: string): boolean {
      return /-(USDT|USDC|DAI|TUSD)$/i.test(marketId);
    }
Behavior5/5

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

With no annotations, the description fully discloses the three components and their weights, output details (score, label, breakdown), and the score range, offering complete transparency.

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?

Two sentences efficiently convey the formula, output, and an example, with no wasted words.

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

Completeness5/5

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

Despite missing annotations and output schema, the description thoroughly covers input, computation, and output structure, making it fully actionable.

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

Parameters4/5

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

Schema coverage is 100% and the description adds meaningful context (e.g., Buda.com market, example values) beyond the schema's minimal description.

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?

The description clearly specifies a composite sentiment score with a detailed formula, distinguishing it from sibling tools like get_market_summary or get_ticker.

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 an example question ("Is the BTC-CLP market currently bullish or bearish?") that implies the tool's use case, though it does not explicitly contrast with alternatives.

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/gtorreal/buda-mcp'

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