Skip to main content
Glama
Ademscodeisnotsobad

Quant Companion MCP

heston.test.ts4.99 kB
/** * Tests for Heston model */ import { describe, it, expect } from "vitest"; import { simulateHestonPaths, priceOptionHestonMonteCarlo, hestonDistributionStats, } from "./heston"; describe("simulateHestonPaths", () => { const baseParams = { spot: 100, rate: 0.05, kappa: 2.0, theta: 0.04, // Long-term variance (20% vol) xi: 0.3, rho: -0.7, v0: 0.04, // Initial variance (20% vol) timeToMaturityYears: 1, steps: 50, paths: 10000, }; it("produces positive terminal prices", () => { const result = simulateHestonPaths(baseParams); expect(result.terminalPrices.length).toBe(baseParams.paths); result.terminalPrices.forEach(price => { expect(price).toBeGreaterThan(0); }); }); it("produces positive terminal variances", () => { const result = simulateHestonPaths(baseParams); result.terminalVariances.forEach(v => { expect(v).toBeGreaterThanOrEqual(0); }); }); it("has mean near forward price", () => { const result = simulateHestonPaths({ ...baseParams, paths: 50000 }); const meanPrice = result.terminalPrices.reduce((a, b) => a + b, 0) / result.terminalPrices.length; // Expected forward ≈ spot * exp(r * T) const expectedForward = baseParams.spot * Math.exp(baseParams.rate * baseParams.timeToMaturityYears); // Allow 5% error due to Monte Carlo variance expect(meanPrice).toBeGreaterThan(expectedForward * 0.95); expect(meanPrice).toBeLessThan(expectedForward * 1.05); }); it("throws for too many paths", () => { expect(() => simulateHestonPaths({ ...baseParams, paths: 300000 }) ).toThrow(); }); it("produces higher vol with higher xi", () => { const result1 = simulateHestonPaths({ ...baseParams, xi: 0.2, paths: 20000 }); const result2 = simulateHestonPaths({ ...baseParams, xi: 0.6, paths: 20000 }); const std1 = standardDeviation(result1.terminalPrices); const std2 = standardDeviation(result2.terminalPrices); // Higher vol of vol should produce higher price dispersion expect(std2).toBeGreaterThan(std1 * 0.8); }); }); describe("priceOptionHestonMonteCarlo", () => { const baseParams = { spot: 100, rate: 0.05, kappa: 2.0, theta: 0.04, xi: 0.3, rho: -0.7, v0: 0.04, timeToMaturityYears: 0.5, steps: 30, paths: 30000, }; it("prices ATM call reasonably", () => { const result = priceOptionHestonMonteCarlo({ ...baseParams, strike: 100, optionType: "call", }); // ATM call should have positive value expect(result.price).toBeGreaterThan(0); // Should be in reasonable range (roughly BS-like) expect(result.price).toBeLessThan(20); // Standard error should be small relative to price expect(result.standardError).toBeLessThan(result.price * 0.1); }); it("prices OTM put cheaper than ATM", () => { const atmResult = priceOptionHestonMonteCarlo({ ...baseParams, strike: 100, optionType: "put", }); const otmResult = priceOptionHestonMonteCarlo({ ...baseParams, strike: 85, optionType: "put", }); expect(otmResult.price).toBeLessThan(atmResult.price); }); it("produces tighter CI with more paths", () => { const result1 = priceOptionHestonMonteCarlo({ ...baseParams, strike: 100, optionType: "call", paths: 10000, }); const result2 = priceOptionHestonMonteCarlo({ ...baseParams, strike: 100, optionType: "call", paths: 50000, }); const ciWidth1 = result1.confidenceInterval.upper - result1.confidenceInterval.lower; const ciWidth2 = result2.confidenceInterval.upper - result2.confidenceInterval.lower; // More paths should give tighter CI expect(ciWidth2).toBeLessThan(ciWidth1); }); }); describe("hestonDistributionStats", () => { it("computes distribution statistics", () => { const params = { spot: 100, rate: 0.05, kappa: 2.0, theta: 0.04, xi: 0.3, rho: -0.7, v0: 0.04, timeToMaturityYears: 0.5, steps: 30, paths: 20000, }; const stats = hestonDistributionStats(params); // Basic sanity checks expect(stats.mean).toBeGreaterThan(0); expect(stats.median).toBeGreaterThan(0); expect(stats.std).toBeGreaterThan(0); // Percentiles should be ordered expect(stats.percentile5).toBeLessThan(stats.percentile25); expect(stats.percentile25).toBeLessThan(stats.median); expect(stats.median).toBeLessThan(stats.percentile75); expect(stats.percentile75).toBeLessThan(stats.percentile95); }); }); // Helper function function standardDeviation(arr: number[]): number { const n = arr.length; const mean = arr.reduce((a, b) => a + b, 0) / n; const variance = arr.reduce((sum, val) => sum + (val - mean) ** 2, 0) / (n - 1); return Math.sqrt(variance); }

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