Skip to main content
Glama
Ademscodeisnotsobad

Quant Companion MCP

detectUnusualActivity.ts5.8 kB
/** * MCP Tool: detect_unusual_activity * * Identify unusual options activity that may indicate informed trading. */ import { z } from "zod"; import { detectUnusualActivity, type QuantError } from "@quant-companion/core"; import { getDefaultProvider } from "../marketData"; import { createError } from "../errors"; export const detectUnusualActivitySchema = z.object({ symbol: z.string().describe("Stock/ETF ticker symbol (e.g., AAPL, NVDA, SPY)"), minVolume: z .number() .min(1) .default(100) .describe("Minimum volume to consider (default: 100)"), volumeOiThreshold: z .number() .min(0) .default(0.5) .describe("Volume/OI ratio threshold for detection (default: 0.5)"), maxResults: z .number() .min(1) .max(50) .default(20) .describe("Maximum results to return (default: 20)"), }); export type DetectUnusualActivityInput = z.infer<typeof detectUnusualActivitySchema>; export interface DetectUnusualActivityOutput { symbol: string; spot: number; asOf: string; summary: { totalUnusualContracts: number; callVsPutRatio: number; dominantSentiment: "bullish" | "bearish" | "mixed" | "neutral"; topStrikes: number[]; }; activities: Array<{ optionSymbol: string; right: "call" | "put"; strike: number; expiration: string; type: string; score: number; description: string; volume: number; openInterest: number; volumeToOiRatio: number; sentiment: "bullish" | "bearish" | "neutral"; }>; interpretation: { headline: string; details: string[]; }; } export const detectUnusualActivityDefinition = { name: "detect_unusual_activity", description: `Detect unusual options activity for a symbol. Identifies: - Volume spikes (abnormally high trading) - High Vol/OI ratios (new position opening) - Wing activity (far OTM trades) - Large trades Returns: - Summary with dominant sentiment - Top unusual contracts with scores - Interpretation and headline Use this for: - Flow analysis (like Unusual Whales) - Detecting potential informed trading - Sentiment analysis from options markets`, inputSchema: { type: "object" as const, properties: { symbol: { type: "string", description: "Stock/ETF ticker symbol" }, minVolume: { type: "number", description: "Minimum volume filter (default: 100)", default: 100, }, volumeOiThreshold: { type: "number", description: "Vol/OI threshold (default: 0.5)", default: 0.5, }, maxResults: { type: "number", description: "Max results (default: 20)", default: 20, }, }, required: ["symbol"], }, }; function generateInterpretation( symbol: string, output: DetectUnusualActivityOutput ): DetectUnusualActivityOutput["interpretation"] { const { summary, activities } = output; const details: string[] = []; // Generate headline let headline: string; if (summary.totalUnusualContracts === 0) { headline = `No unusual options activity detected for ${symbol}`; } else { const sentimentWord = summary.dominantSentiment === "bullish" ? "bullish" : summary.dominantSentiment === "bearish" ? "bearish" : "mixed"; headline = `${summary.totalUnusualContracts} unusual contracts detected with ${sentimentWord} sentiment`; } // Add details if (summary.callVsPutRatio > 2) { details.push(`Heavy call activity (${summary.callVsPutRatio.toFixed(1)}x calls vs puts)`); } else if (summary.callVsPutRatio < 0.5) { details.push(`Heavy put activity (${(1 / summary.callVsPutRatio).toFixed(1)}x puts vs calls)`); } if (summary.topStrikes.length > 0) { details.push(`Key strikes: ${summary.topStrikes.slice(0, 3).join(", ")}`); } // Highlight top activities const topByScore = activities.slice(0, 3); for (const a of topByScore) { details.push(`${a.right.toUpperCase()} $${a.strike} (${a.expiration}): ${a.description}`); } // Check for wing trades const wingTrades = activities.filter((a) => a.type === "wing_activity"); if (wingTrades.length > 0) { details.push(`${wingTrades.length} wing trades detected (potential tail hedging or speculation)`); } return { headline, details }; } export async function detectUnusualActivityTool( input: DetectUnusualActivityInput ): Promise<DetectUnusualActivityOutput | { error: QuantError }> { const provider = getDefaultProvider(); try { const chain = await provider.getOptionsChain({ symbol: input.symbol.toUpperCase(), }); const report = detectUnusualActivity({ chain, minVolume: input.minVolume, volumeOiThreshold: input.volumeOiThreshold, maxResults: input.maxResults, }); const activities = report.activities.map((a) => ({ optionSymbol: a.contract.optionSymbol, right: a.contract.right, strike: a.contract.strike, expiration: a.contract.expiration, type: a.type, score: a.score, description: a.description, volume: a.contract.volume, openInterest: a.contract.openInterest, volumeToOiRatio: a.volumeToOiRatio, sentiment: a.sentiment, })); const output: DetectUnusualActivityOutput = { symbol: report.symbol, spot: report.spot, asOf: report.asOf, summary: report.summary, activities, interpretation: { headline: "", details: [] }, }; output.interpretation = generateInterpretation(input.symbol.toUpperCase(), output); return output; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; return { error: createError("DATA_NOT_FOUND", `Failed to detect unusual activity: ${message}`), }; } }

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/Ademscodeisnotsobad/Quant-Companion-MCP'

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