// // Created by David Doebel on 06.03.2026. // #include #include "BlackScholesClosedFormEngine.hpp" #include "BlackScholesProcess.hpp" #include "MonteCarloEngine.hpp" #include "Instrument.hpp" #include "Option.hpp" #include "Payoff.hpp" #include "stubs/FlatYieldCurve.hpp" #include "stubs/FlatVolatilitySurface.hpp" TEST(BlackScholesProcess, ExpectedValue) { // Market setup (via test stubs): S0=100, r=1%, sigma=20% const double K = 100.0; const double T = 1.0; const int numPaths = 300000; // enough for stable MC estimate const MarketData marketData( 100.0, std::make_shared(0.01), std::make_shared(0.2)); // Build Black-Scholes process from an immutable market snapshot auto processCall = std::make_unique(marketData); auto processPut = std::make_unique(marketData); // RNG shared between engines is fine auto rng = std::make_shared(); // Pricing engines auto mcCall = std::make_unique(numPaths, std::move(processCall), rng); auto mcPut = std::make_unique(numPaths, std::move(processPut), rng); // Instruments (European vanilla) with call and put payoffs Instrument callInstr(T, std::make_unique(K), std::move(mcCall)); Instrument putInstr(T, std::make_unique(K), std::move(mcPut)); const double callPrice = callInstr.price(); const double putPrice = putInstr.price(); // Ground truth Black–Scholes prices provided const double callGT = 8.4333186901; const double putGT = 7.4383020650; // Monte Carlo tolerance const double tol = 0.10; // 10 cents tolerance ASSERT_NEAR(callPrice, callGT, tol); ASSERT_NEAR(putPrice, putGT, tol); } TEST(BlackScholesClosedForm, MatchesReference) { const double K = 100.0; const double T = 1.0; const MarketData marketData( 100.0, std::make_shared(0.01), std::make_shared(0.2)); auto processCall = std::make_unique(marketData); auto processPut = std::make_unique(marketData); auto analyticCall = std::make_unique(std::move(processCall)); auto analyticPut = std::make_unique(std::move(processPut)); Instrument callInstr(T, std::make_unique(K), std::move(analyticCall)); Instrument putInstr(T, std::make_unique(K), std::move(analyticPut)); const double callGT = 8.4333186901; const double putGT = 7.4383020650; ASSERT_NEAR(callInstr.price(), callGT, 1e-9); ASSERT_NEAR(putInstr.price(), putGT, 1e-9); }