Skip to main content
Glama
Ademscodeisnotsobad

Quant Companion MCP

blackScholes.ts5.24 kB
/** * Black-Scholes pricing and Greeks */ import { BlackScholesParams, BlackScholesResult, Greeks, GreeksExtended, } from "./types"; import { normalCDF, normalPDF, TRADING_DAYS_PER_YEAR, CALENDAR_DAYS_PER_YEAR } from "./utils"; /** * Compute d1 and d2 parameters for Black-Scholes */ function computeD1D2( spot: number, strike: number, rate: number, vol: number, timeToMaturity: number, dividendYield: number ): { d1: number; d2: number } { const sqrtT = Math.sqrt(timeToMaturity); const d1 = (Math.log(spot / strike) + (rate - dividendYield + 0.5 * vol * vol) * timeToMaturity) / (vol * sqrtT); const d2 = d1 - vol * sqrtT; return { d1, d2 }; } /** * Price a European option using Black-Scholes formula * * @param params - Black-Scholes parameters * @returns Price and d1/d2 values */ export function priceBlackScholes(params: BlackScholesParams): BlackScholesResult { const { spot, strike, rate, vol, timeToMaturity, dividendYield = 0, optionType, } = params; // Edge cases if (timeToMaturity <= 0) { // At expiry const intrinsic = optionType === "call" ? Math.max(spot - strike, 0) : Math.max(strike - spot, 0); return { price: intrinsic, d1: 0, d2: 0 }; } if (vol <= 0) { // Zero vol: deterministic outcome const forward = spot * Math.exp((rate - dividendYield) * timeToMaturity); const df = Math.exp(-rate * timeToMaturity); const price = optionType === "call" ? Math.max(forward - strike, 0) * df : Math.max(strike - forward, 0) * df; return { price, d1: Infinity, d2: Infinity }; } const { d1, d2 } = computeD1D2( spot, strike, rate, vol, timeToMaturity, dividendYield ); const df = Math.exp(-rate * timeToMaturity); const dfDiv = Math.exp(-dividendYield * timeToMaturity); let price: number; if (optionType === "call") { price = spot * dfDiv * normalCDF(d1) - strike * df * normalCDF(d2); } else { price = strike * df * normalCDF(-d2) - spot * dfDiv * normalCDF(-d1); } return { price: Math.max(price, 0), d1, d2 }; } /** * Compute analytical Greeks for a European option * * Units: * - Delta: absolute (e.g., 0.5 means $0.50 change per $1 spot move) * - Gamma: absolute (change in delta per $1 spot move) * - Theta: per calendar day (365 days/year) in $ * - Vega: per 1% (0.01) change in volatility in $ * - Rho: per 1% (0.01) change in interest rate in $ * * @param params - Black-Scholes parameters * @returns Greeks object with delta, gamma, theta, vega, rho */ export function greeksBlackScholes(params: BlackScholesParams): Greeks { const { spot, strike, rate, vol, timeToMaturity, dividendYield = 0, optionType, } = params; // Edge cases if (timeToMaturity <= 0 || vol <= 0) { return { delta: optionType === "call" ? (spot > strike ? 1 : 0) : (spot < strike ? -1 : 0), gamma: 0, theta: 0, vega: 0, rho: 0, }; } const { d1, d2 } = computeD1D2( spot, strike, rate, vol, timeToMaturity, dividendYield ); const sqrtT = Math.sqrt(timeToMaturity); const df = Math.exp(-rate * timeToMaturity); const dfDiv = Math.exp(-dividendYield * timeToMaturity); const pdf_d1 = normalPDF(d1); // Delta let delta: number; if (optionType === "call") { delta = dfDiv * normalCDF(d1); } else { delta = -dfDiv * normalCDF(-d1); } // Gamma (same for call and put) const gamma = (dfDiv * pdf_d1) / (spot * vol * sqrtT); // Theta (annual) - then convert to per calendar day let thetaAnnual: number; const term1 = (-spot * dfDiv * pdf_d1 * vol) / (2 * sqrtT); if (optionType === "call") { thetaAnnual = term1 - rate * strike * df * normalCDF(d2) + dividendYield * spot * dfDiv * normalCDF(d1); } else { thetaAnnual = term1 + rate * strike * df * normalCDF(-d2) - dividendYield * spot * dfDiv * normalCDF(-d1); } // Convert to per calendar day (standard convention) const theta = thetaAnnual / CALENDAR_DAYS_PER_YEAR; // Vega (per 1% move in vol, so divide by 100) const vega = (spot * dfDiv * sqrtT * pdf_d1) / 100; // Rho (per 1% move in rate, so divide by 100) let rho: number; if (optionType === "call") { rho = (strike * timeToMaturity * df * normalCDF(d2)) / 100; } else { rho = (-strike * timeToMaturity * df * normalCDF(-d2)) / 100; } return { delta, gamma, theta, vega, rho }; } /** * Compute extended Greeks with multiple theta representations * * @param params - Black-Scholes parameters * @returns Extended Greeks with thetaPerTradingDay, thetaPerCalendarDay, and thetaAnnual */ export function greeksBlackScholesExtended(params: BlackScholesParams): GreeksExtended { const baseGreeks = greeksBlackScholes(params); // Theta per calendar day is already computed in baseGreeks const thetaPerCalendarDay = baseGreeks.theta; const thetaAnnual = thetaPerCalendarDay * CALENDAR_DAYS_PER_YEAR; const thetaPerTradingDay = thetaAnnual / TRADING_DAYS_PER_YEAR; return { ...baseGreeks, thetaPerTradingDay, thetaPerCalendarDay, thetaAnnual, }; }

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