/**
* MCP Tool: price_option_monte_carlo
*
* Monte Carlo pricer with distribution summary.
*/
import { z } from "zod";
import {
priceOptionMonteCarlo as mcPricer,
MonteCarloParams,
ConfidenceInterval,
} from "@quant-companion/core";
import { LIMITS } from "../errors";
export const priceOptionMonteCarloSchema = z.object({
spot: z.number().positive().describe("Current spot price of the underlying"),
strike: z.number().positive().describe("Strike price of the option"),
rate: z
.number()
.describe("Risk-free interest rate (annualized, e.g., 0.05 for 5%)"),
vol: z.number().positive().describe("Volatility (annualized, e.g., 0.25 for 25%)"),
timeToMaturity: z
.number()
.positive()
.describe("Time to maturity in years (e.g., 0.5 for 6 months)"),
optionType: z.enum(["call", "put"]).describe("Option type: 'call' or 'put'"),
paths: z
.number()
.int()
.positive()
.max(LIMITS.MAX_PATHS)
.default(LIMITS.DEFAULT_PATHS)
.describe(`Number of simulation paths (default ${LIMITS.DEFAULT_PATHS}, max ${LIMITS.MAX_PATHS})`),
dividendYield: z
.number()
.optional()
.default(0)
.describe("Dividend yield (annualized, default 0)"),
});
export type PriceOptionMonteCarloInput = z.infer<
typeof priceOptionMonteCarloSchema
>;
export interface MonteCarloSummary {
meanPayoff: number;
stdDevPayoff: number;
minPayoff: number;
maxPayoff: number;
}
export interface PriceOptionMonteCarloOutput {
price: number;
standardError: number;
confidenceInterval: ConfidenceInterval;
summary: MonteCarloSummary;
}
export function priceOptionMonteCarlo(
input: PriceOptionMonteCarloInput
): PriceOptionMonteCarloOutput {
// Enforce limits
if (input.paths > LIMITS.MAX_PATHS) {
throw new Error(`paths must be <= ${LIMITS.MAX_PATHS}`);
}
const params: MonteCarloParams = {
spot: input.spot,
strike: input.strike,
rate: input.rate,
vol: input.vol,
timeToMaturity: input.timeToMaturity,
optionType: input.optionType,
paths: input.paths,
dividendYield: input.dividendYield,
};
const result = mcPricer(params);
// Compute summary statistics from payoffs if available
let summary: MonteCarloSummary;
if (result.payoffs && result.payoffs.length > 0) {
const payoffs = result.payoffs;
const n = payoffs.length;
const meanPayoff = payoffs.reduce((a, b) => a + b, 0) / n;
const variance = payoffs.reduce((sum, p) => sum + (p - meanPayoff) ** 2, 0) / (n - 1);
summary = {
meanPayoff,
stdDevPayoff: Math.sqrt(variance),
minPayoff: Math.min(...payoffs),
maxPayoff: Math.max(...payoffs),
};
} else {
// Estimate from price and standard error
summary = {
meanPayoff: result.price * Math.exp(input.rate * input.timeToMaturity),
stdDevPayoff: result.standardError * Math.sqrt(input.paths) * Math.exp(input.rate * input.timeToMaturity),
minPayoff: 0,
maxPayoff: input.spot * 3, // Rough estimate
};
}
return {
price: result.price,
standardError: result.standardError,
confidenceInterval: result.confidenceInterval,
summary,
};
}
export const priceOptionMonteCarloDefinition = {
name: "price_option_monte_carlo",
description:
`Price a European option using Monte Carlo simulation. Returns the estimated price, standard error, confidence interval, and payoff distribution summary. Use this for validation against Black-Scholes or when exploring price distributions. Max ${LIMITS.MAX_PATHS} paths.`,
inputSchema: {
type: "object",
properties: {
spot: {
type: "number",
description: "Current spot price of the underlying asset",
},
strike: {
type: "number",
description: "Strike price of the option",
},
rate: {
type: "number",
description:
"Risk-free interest rate (annualized decimal, e.g., 0.05 for 5%)",
},
vol: {
type: "number",
description: "Volatility (annualized decimal, e.g., 0.25 for 25%)",
},
timeToMaturity: {
type: "number",
description: "Time to expiration in years (e.g., 0.5 for 6 months)",
},
optionType: {
type: "string",
enum: ["call", "put"],
description: "Option type: 'call' or 'put'",
},
paths: {
type: "number",
description:
`Number of simulation paths (default ${LIMITS.DEFAULT_PATHS}, max ${LIMITS.MAX_PATHS}). More paths = higher accuracy but slower.`,
},
dividendYield: {
type: "number",
description: "Dividend yield (annualized decimal, default 0)",
},
},
required: ["spot", "strike", "rate", "vol", "timeToMaturity", "optionType"],
},
};