/**
* Tests for Monte Carlo pricing
*/
import { describe, it, expect } from "vitest";
import { priceOptionMonteCarlo } from "./monteCarlo";
import { priceBlackScholes } from "./blackScholes";
describe("priceOptionMonteCarlo", () => {
it("converges to Black-Scholes for European call", () => {
const params = {
spot: 100,
strike: 100,
rate: 0.05,
vol: 0.2,
timeToMaturity: 1,
optionType: "call" as const,
};
const bsPrice = priceBlackScholes(params).price;
const mcResult = priceOptionMonteCarlo({ ...params, paths: 100000 });
// MC should be within ~1% of BS with high path count
const tolerance = 0.02 * bsPrice;
expect(Math.abs(mcResult.price - bsPrice)).toBeLessThan(tolerance);
});
it("converges to Black-Scholes for European put", () => {
const params = {
spot: 100,
strike: 110,
rate: 0.05,
vol: 0.25,
timeToMaturity: 0.5,
optionType: "put" as const,
};
const bsPrice = priceBlackScholes(params).price;
const mcResult = priceOptionMonteCarlo({ ...params, paths: 100000 });
const tolerance = 0.02 * bsPrice;
expect(Math.abs(mcResult.price - bsPrice)).toBeLessThan(tolerance);
});
it("standard error decreases with more paths", () => {
const params = {
spot: 100,
strike: 100,
rate: 0.05,
vol: 0.2,
timeToMaturity: 1,
optionType: "call" as const,
};
const result1k = priceOptionMonteCarlo({ ...params, paths: 1000 });
const result100k = priceOptionMonteCarlo({ ...params, paths: 100000 });
// SE should be ~10x smaller with 100x more paths
expect(result100k.standardError).toBeLessThan(result1k.standardError);
});
it("returns 0 for deeply OTM call at expiry", () => {
const result = priceOptionMonteCarlo({
spot: 100,
strike: 200,
rate: 0.05,
vol: 0.2,
timeToMaturity: 0,
optionType: "call",
paths: 1000,
});
expect(result.price).toBe(0);
});
it("handles dividend yield", () => {
const params = {
spot: 100,
strike: 100,
rate: 0.05,
vol: 0.2,
timeToMaturity: 1,
optionType: "call" as const,
paths: 50000,
};
const withDiv = priceOptionMonteCarlo({ ...params, dividendYield: 0.02 });
const withoutDiv = priceOptionMonteCarlo({ ...params, dividendYield: 0 });
// Dividend yield reduces call price
expect(withDiv.price).toBeLessThan(withoutDiv.price);
});
});