Skip to main content
Glama
Ademscodeisnotsobad

Quant Companion MCP

volatility.ts3.52 kB
/** * Historical volatility calculations */ import { HistoricalVolResult } from "./types"; import { logReturns, stdDev, TRADING_DAYS_PER_YEAR } from "./utils"; const DEFAULT_WINDOW = 30; /** * Compute historical (realized) volatility from price series * * Uses log returns and annualizes using √252 convention. * * @param prices - Array of prices (e.g., daily closes) * @param window - Number of returns to use (default 30) * @returns Annualized volatility and window used */ export function computeHistoricalVol( prices: number[], window?: number ): HistoricalVolResult { if (prices.length < 2) { throw new Error("Need at least 2 prices to compute volatility"); } // Compute all log returns const returns = logReturns(prices); // Use the specified window or all available returns const actualWindow = window ? Math.min(window, returns.length) : Math.min(DEFAULT_WINDOW, returns.length); if (actualWindow < 2) { throw new Error("Need at least 2 returns to compute volatility"); } // Take the most recent returns const windowReturns = returns.slice(-actualWindow); // Compute daily volatility (sample std dev) const dailyVol = stdDev(windowReturns, true); // Annualize const annualizedVol = dailyVol * Math.sqrt(TRADING_DAYS_PER_YEAR); return { volatility: annualizedVol, window: actualWindow, }; } /** * Compute rolling historical volatility * * @param prices - Array of prices * @param window - Rolling window size * @returns Array of {timestamp index, volatility} pairs */ export function computeRollingVol( prices: number[], window: number = DEFAULT_WINDOW ): { index: number; volatility: number }[] { const returns = logReturns(prices); const results: { index: number; volatility: number }[] = []; for (let i = window; i <= returns.length; i++) { const windowReturns = returns.slice(i - window, i); const dailyVol = stdDev(windowReturns, true); const annualizedVol = dailyVol * Math.sqrt(TRADING_DAYS_PER_YEAR); results.push({ index: i, // corresponds to prices[i+1] (since returns has one less element) volatility: annualizedVol, }); } return results; } /** * Compute Parkinson volatility (using high-low range) * More efficient estimator than close-to-close * * @param highs - Array of high prices * @param lows - Array of low prices * @param window - Number of periods to use * @returns Annualized Parkinson volatility */ export function computeParkinsonVol( highs: number[], lows: number[], window?: number ): HistoricalVolResult { if (highs.length !== lows.length) { throw new Error("highs and lows arrays must have same length"); } if (highs.length < 1) { throw new Error("Need at least 1 data point"); } const actualWindow = window ? Math.min(window, highs.length) : Math.min(DEFAULT_WINDOW, highs.length); // Use most recent data const recentHighs = highs.slice(-actualWindow); const recentLows = lows.slice(-actualWindow); // Parkinson formula: σ = sqrt(1/(4*n*ln(2)) * Σ(ln(H/L))²) const logRanges = recentHighs.map((h, i) => Math.log(h / recentLows[i])); const sumSquaredLogRanges = logRanges.reduce((sum, lr) => sum + lr * lr, 0); const factor = 1 / (4 * actualWindow * Math.LN2); const dailyVol = Math.sqrt(factor * sumSquaredLogRanges); const annualizedVol = dailyVol * Math.sqrt(TRADING_DAYS_PER_YEAR); return { volatility: annualizedVol, window: actualWindow, }; }

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