Adapt Yield Curve and Volatility Surface and Market Data, to be better compatible with unit test.
Some checks failed
C++ CI / build (push) Has been cancelled

This commit is contained in:
David Doebel
2026-03-12 12:10:13 +01:00
parent 08298439ea
commit f98de4d0a3
13 changed files with 50 additions and 80 deletions

View File

@@ -24,9 +24,8 @@ FetchContent_MakeAvailable(googletest)
add_executable(qengine_tests add_executable(qengine_tests
tests/test_black_scholes.cpp tests/test_black_scholes.cpp
tests/stubs/FlatYieldCurve.cpp tests/stubs/FlatYieldCurve.cpp
tests/stubs/FlatVolatilitySurface.cpp tests/stubs/FlatVolatilitySurface.cpp)
tests/stubs/FakeMarketData.cpp)
target_link_libraries(qengine_tests qengine GTest::gtest_main) target_link_libraries(qengine_tests qengine GTest::gtest_main)
include(GoogleTest) include(GoogleTest)
gtest_discover_tests(qengine_tests) gtest_discover_tests(qengine_tests)

View File

@@ -9,8 +9,7 @@
class BlackScholesProcess : public StochasticProcess{ class BlackScholesProcess : public StochasticProcess{
public: public:
BlackScholesProcess() = default; explicit BlackScholesProcess(MarketData data) : StochasticProcess(std::move(data)){}
BlackScholesProcess(std::unique_ptr<MarketData> data) : StochasticProcess(std::move(data)){}
double drift(double t, double s) override; double drift(double t, double s) override;
@@ -21,4 +20,4 @@ public:
}; };
#endif //QUANTENGINE_BLACKSCHOLESPROCESS_HPP #endif //QUANTENGINE_BLACKSCHOLESPROCESS_HPP

View File

@@ -5,5 +5,5 @@
#include "MarketData.hpp" #include "MarketData.hpp"
double MarketData::spot() const { return spot_; } double MarketData::spot() const { return spot_; }
YieldCurve& MarketData::yield_curve() { return *yield_curve_; } const YieldCurve& MarketData::yield_curve() const { return *yield_curve_; }
VolatilitySurface& MarketData::volatility_surface() { return *volatility_surface_; } const VolatilitySurface& MarketData::volatility_surface() const { return *volatility_surface_; }

View File

@@ -10,24 +10,24 @@
class MarketData { class MarketData {
public: public:
MarketData() = default; MarketData() = delete;
MarketData(double spot, std::unique_ptr<YieldCurve> yield_curve, MarketData(double spot, std::shared_ptr<const YieldCurve> yield_curve,
std::unique_ptr<VolatilitySurface> volatility_surface) std::shared_ptr<const VolatilitySurface> volatility_surface)
: spot_(spot), : spot_(spot),
yield_curve_(std::move(yield_curve)), yield_curve_(std::move(yield_curve)),
volatility_surface_(std::move(volatility_surface)) { volatility_surface_(std::move(volatility_surface)) {
} }
double spot() const; double spot() const;
YieldCurve& yield_curve(); const YieldCurve& yield_curve() const;
VolatilitySurface& volatility_surface(); const VolatilitySurface& volatility_surface() const;
private: private:
double spot_; double spot_;
std::unique_ptr<YieldCurve> yield_curve_; std::shared_ptr<const YieldCurve> yield_curve_;
std::unique_ptr<VolatilitySurface> volatility_surface_; std::shared_ptr<const VolatilitySurface> volatility_surface_;
}; };
#endif //QUANTENGINE_MARKETDATA_HPP #endif //QUANTENGINE_MARKETDATA_HPP

View File

@@ -9,7 +9,7 @@
class Statistics { class Statistics {
public: public:
Statistics() : moments_({0., 0., 0.}), max_(0.), min_(0.) {} Statistics() : moments_({0., 0., 0.}), n(0), max_(0.), min_(0.) {}
void dump(double value); void dump(double value);
void clear(); void clear();
double mean(); double mean();
@@ -27,4 +27,4 @@ private:
}; };
#endif //QUANTENGINE_STATISTICS_HPP #endif //QUANTENGINE_STATISTICS_HPP

View File

@@ -9,20 +9,20 @@
class StochasticProcess { class StochasticProcess {
public: public:
StochasticProcess() = default; StochasticProcess() = delete;
StochasticProcess(std::unique_ptr<MarketData> data) : data_(std::move(data)){} explicit StochasticProcess(MarketData data) : data_(std::move(data)){}
virtual ~StochasticProcess() = default; virtual ~StochasticProcess() = default;
virtual double drift(double t, double s) = 0; virtual double drift(double t, double s) = 0;
virtual double diffusion(double t, double s) = 0; virtual double diffusion(double t, double s) = 0;
virtual double step(double t, double s, double dt, double dW) = 0; virtual double step(double t, double s, double dt, double dW) = 0;
MarketData& data() const {return *data_;} const MarketData& data() const {return data_;}
private: private:
std::shared_ptr<MarketData> data_; MarketData data_;
}; };
#endif //QUANTENGINE_STOCHASTICPROCESS_HPP #endif //QUANTENGINE_STOCHASTICPROCESS_HPP

View File

@@ -9,10 +9,10 @@
class VolatilitySurface { class VolatilitySurface {
public: public:
virtual ~VolatilitySurface() = default; virtual ~VolatilitySurface() = default;
virtual double sigma(double K, double T) = 0; virtual double sigma(double K, double T) const = 0;
private: private:
}; };
#endif //QUANTENGINE_VOLATILITYSURFACE_HPP #endif //QUANTENGINE_VOLATILITYSURFACE_HPP

View File

@@ -28,10 +28,10 @@ public:
return *this; return *this;
} }
virtual ~YieldCurve() = default; virtual ~YieldCurve() = default;
virtual double discount(double t) = 0; virtual double discount(double t) const = 0;
virtual double zeroRate(double t) = 0; virtual double zeroRate(double t) const = 0;
}; };
#endif //QUANTENGINE_YIELDCURVE_HPP #endif //QUANTENGINE_YIELDCURVE_HPP

View File

@@ -1,2 +0,0 @@
// Minimal TU to satisfy CMake for test stubs
#include "FakeMarketData.hpp"

View File

@@ -1,38 +0,0 @@
//
// Created by David Doebel on 07.03.2026.
//
#ifndef QUANTENGINE_FAKEMARKETDATA_HPP
#define QUANTENGINE_FAKEMARKETDATA_HPP
#include "MarketData.hpp"
#include "FlatYieldCurve.hpp"
#include "FlatVolatilitySurface.hpp"
class FakeMarketData : public MarketData {
public:
FakeMarketData() = default;
FakeMarketData(const FakeMarketData &other)
{
}
FakeMarketData(FakeMarketData &&other) noexcept
{
}
FakeMarketData & operator=(const FakeMarketData &other) {
return *this;
}
FakeMarketData & operator=(FakeMarketData &&other) noexcept {
return *this;
}
double spot() const {return 100.0;}
YieldCurve& yield_curve(){return *yieldCurve_; };
VolatilitySurface& volatility_surface(){return *volatilitySurface_; };
private:
std::unique_ptr<FlatYieldCurve> yieldCurve_ = std::make_unique<FlatYieldCurve>();
std::unique_ptr<FlatVolatilitySurface> volatilitySurface_ = std::make_unique<FlatVolatilitySurface>();
};
#endif

View File

@@ -6,6 +6,12 @@
#include "VolatilitySurface.hpp" #include "VolatilitySurface.hpp"
class FlatVolatilitySurface : public VolatilitySurface { class FlatVolatilitySurface : public VolatilitySurface {
double sigma(double K, double T) {return 0.2;} public:
explicit FlatVolatilitySurface(double sigma = 0.2) : sigma_(sigma) {}
double sigma(double K, double T) const override {return sigma_;}
private:
double sigma_;
}; };
#endif #endif

View File

@@ -7,10 +7,12 @@
#include <cmath> #include <cmath>
class FlatYieldCurve : public YieldCurve{ class FlatYieldCurve : public YieldCurve{
public:
explicit FlatYieldCurve(double rate = 0.01) : rate_(rate) {}
double discount(double t) override {return std::exp(-rate_ * t); }; double discount(double t) const override {return std::exp(-rate_ * t); };
double zeroRate(double t) override {return rate_; } double zeroRate(double t) const override {return rate_; }
private: private:
double rate_ = 0.01; double rate_ = 0.01;
}; };
#endif #endif

View File

@@ -11,7 +11,6 @@
#include "stubs/FlatYieldCurve.hpp" #include "stubs/FlatYieldCurve.hpp"
#include "stubs/FlatVolatilitySurface.hpp" #include "stubs/FlatVolatilitySurface.hpp"
#include "stubs/FakeMarketData.hpp"
TEST(BlackScholesProcess, ExpectedValue) { TEST(BlackScholesProcess, ExpectedValue) {
// Market setup (via test stubs): S0=100, r=1%, sigma=20% // Market setup (via test stubs): S0=100, r=1%, sigma=20%
@@ -19,9 +18,14 @@ TEST(BlackScholesProcess, ExpectedValue) {
const double T = 1.0; const double T = 1.0;
const int numPaths = 300000; // enough for stable MC estimate const int numPaths = 300000; // enough for stable MC estimate
// Build Black-Scholes process with fake flat market data const MarketData marketData(
auto processCall = std::make_unique<BlackScholesProcess>(std::make_unique<FakeMarketData>()); 100.0,
auto processPut = std::make_unique<BlackScholesProcess>(std::make_unique<FakeMarketData>()); std::make_shared<FlatYieldCurve>(0.01),
std::make_shared<FlatVolatilitySurface>(0.2));
// Build Black-Scholes process from an immutable market snapshot
auto processCall = std::make_unique<BlackScholesProcess>(marketData);
auto processPut = std::make_unique<BlackScholesProcess>(marketData);
// RNG shared between engines is fine // RNG shared between engines is fine
auto rng = std::make_shared<MersenneTwister>(); auto rng = std::make_shared<MersenneTwister>();
@@ -38,12 +42,12 @@ TEST(BlackScholesProcess, ExpectedValue) {
const double putPrice = putInstr.price(); const double putPrice = putInstr.price();
// Ground truth BlackScholes prices provided // Ground truth BlackScholes prices provided
const double callGT = 10.450583572; const double callGT = 8.4333186901;
const double putGT = 5.573526022; const double putGT = 7.4383020650;
// Monte Carlo tolerance // Monte Carlo tolerance
const double tol = 0.10; // 10 cents tolerance const double tol = 0.10; // 10 cents tolerance
ASSERT_NEAR(callPrice, callGT, tol); ASSERT_NEAR(callPrice, callGT, tol);
ASSERT_NEAR(putPrice, putGT, tol); ASSERT_NEAR(putPrice, putGT, tol);
} }