Skip to main content
Glama
Ademscodeisnotsobad

Quant Companion MCP

utils.ts3.92 kB
/** * Math utilities for the quant engine */ /** * Standard normal CDF using Abramowitz & Stegun approximation * Accurate to about 7.5e-8 */ export function normalCDF(x: number): number { const a1 = 0.254829592; const a2 = -0.284496736; const a3 = 1.421413741; const a4 = -1.453152027; const a5 = 1.061405429; const p = 0.3275911; const sign = x < 0 ? -1 : 1; x = Math.abs(x) / Math.SQRT2; const t = 1.0 / (1.0 + p * x); const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-x * x); return 0.5 * (1.0 + sign * y); } /** * Standard normal PDF */ export function normalPDF(x: number): number { return Math.exp(-0.5 * x * x) / Math.sqrt(2 * Math.PI); } /** * Generate a standard normal random variable using Box-Muller transform */ export function randomNormal(): number { let u1: number, u2: number; do { u1 = Math.random(); u2 = Math.random(); } while (u1 === 0); return Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2); } /** * Compute mean of an array */ export function mean(arr: number[]): number { if (arr.length === 0) return 0; return arr.reduce((sum, val) => sum + val, 0) / arr.length; } /** * Compute sample standard deviation */ export function stdDev(arr: number[], useSample = true): number { if (arr.length < 2) return 0; const avg = mean(arr); const squaredDiffs = arr.map((val) => (val - avg) ** 2); const divisor = useSample ? arr.length - 1 : arr.length; return Math.sqrt(squaredDiffs.reduce((sum, val) => sum + val, 0) / divisor); } /** * Compute log returns from price series */ export function logReturns(prices: number[]): number[] { const returns: number[] = []; for (let i = 1; i < prices.length; i++) { returns.push(Math.log(prices[i] / prices[i - 1])); } return returns; } /** * Compute simple returns from price series */ export function simpleReturns(prices: number[]): number[] { const returns: number[] = []; for (let i = 1; i < prices.length; i++) { returns.push(prices[i] / prices[i - 1] - 1); } return returns; } /** * Trading days per year (standard assumption for US equities) */ export const TRADING_DAYS_PER_YEAR = 252; /** * Calendar days per year (for theta conversion) */ export const CALENDAR_DAYS_PER_YEAR = 365; /** * Compute percentile of a sorted or unsorted array * @param arr - Array of numbers * @param p - Percentile in [0, 1] (e.g., 0.95 for 95th percentile) * @returns The value at the given percentile */ export function percentile(arr: number[], p: number): number { if (arr.length === 0) { throw new Error("Cannot compute percentile of empty array"); } if (p < 0 || p > 1) { throw new Error("Percentile must be between 0 and 1"); } const sorted = [...arr].sort((a, b) => a - b); const index = p * (sorted.length - 1); const lower = Math.floor(index); const upper = Math.ceil(index); if (lower === upper) { return sorted[lower]; } // Linear interpolation const weight = index - lower; return sorted[lower] * (1 - weight) + sorted[upper] * weight; } /** * Compute multiple percentiles at once (more efficient for sorted data) */ export function percentiles( arr: number[], ps: number[] ): Record<number, number> { if (arr.length === 0) { throw new Error("Cannot compute percentiles of empty array"); } const sorted = [...arr].sort((a, b) => a - b); const result: Record<number, number> = {}; for (const p of ps) { if (p < 0 || p > 1) { throw new Error(`Percentile ${p} must be between 0 and 1`); } const index = p * (sorted.length - 1); const lower = Math.floor(index); const upper = Math.ceil(index); if (lower === upper) { result[p] = sorted[lower]; } else { const weight = index - lower; result[p] = sorted[lower] * (1 - weight) + sorted[upper] * weight; } } return result; }

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