Create option pricing engine structure, test architecture.
Some checks failed
C++ CI / build (push) Has been cancelled
Some checks failed
C++ CI / build (push) Has been cancelled
This commit is contained in:
35
.gitea/workflows/ci.yml
Normal file
35
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: C++ CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y cmake g++ libeigen3-dev
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
make -j
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
ctest --output-on-failure
|
||||||
@@ -8,3 +8,25 @@ find_package(Eigen3 REQUIRED)
|
|||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
googletest
|
||||||
|
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
|
||||||
|
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
|
||||||
|
add_executable(qengine_tests
|
||||||
|
tests/test_black_scholes.cpp
|
||||||
|
tests/stubs/FlatYieldCurve.cpp
|
||||||
|
tests/stubs/FlatVolatilitySurface.cpp
|
||||||
|
tests/stubs/FakeMarketData.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(qengine_tests qengine GTest::gtest_main)
|
||||||
|
include(GoogleTest)
|
||||||
|
gtest_discover_tests(qengine_tests)
|
||||||
BIN
docs/mermaid-diagram.png
Normal file
BIN
docs/mermaid-diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 383 KiB |
23
src/BlackScholesProcess.cpp
Normal file
23
src/BlackScholesProcess.cpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "BlackScholesProcess.hpp"
|
||||||
|
|
||||||
|
double BlackScholesProcess::drift(double t, double s) {
|
||||||
|
double r = this->data().yield_curve().zeroRate(t);
|
||||||
|
return r * s;
|
||||||
|
}
|
||||||
|
|
||||||
|
double BlackScholesProcess::diffusion(double t, double s) {
|
||||||
|
double sigma = this->data().volatility_surface().sigma(s,t);
|
||||||
|
return sigma*s;
|
||||||
|
}
|
||||||
|
|
||||||
|
double BlackScholesProcess::step(double t, double s, double dt, double dW) {
|
||||||
|
double r = this->data().yield_curve().zeroRate(t);
|
||||||
|
double sigma = this->data().volatility_surface().sigma(s,t);
|
||||||
|
return s*exp((r-0.5*sigma*sigma)*dt + sigma*sqrt(dt)*dW);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
24
src/BlackScholesProcess.hpp
Normal file
24
src/BlackScholesProcess.hpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_BLACKSCHOLESPROCESS_HPP
|
||||||
|
#define QUANTENGINE_BLACKSCHOLESPROCESS_HPP
|
||||||
|
#include "StochasticProcess.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class BlackScholesProcess : public StochasticProcess{
|
||||||
|
public:
|
||||||
|
BlackScholesProcess() = default;
|
||||||
|
BlackScholesProcess(std::unique_ptr<MarketData> data) : StochasticProcess(std::move(data)){}
|
||||||
|
|
||||||
|
double drift(double t, double s) override;
|
||||||
|
|
||||||
|
double diffusion(double t, double s) override;
|
||||||
|
|
||||||
|
double step(double t, double s, double dt, double dW) override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_BLACKSCHOLESPROCESS_HPP
|
||||||
@@ -1,12 +1,32 @@
|
|||||||
add_library(qengine
|
add_library(qengine
|
||||||
models/black_scholes.cpp
|
Instrument.cpp
|
||||||
simulation/monte_carlo.cpp
|
Instrument.hpp
|
||||||
models/payoff.cpp
|
Payoff.cpp
|
||||||
main.cpp
|
Payoff.hpp
|
||||||
calibration/Stats.cpp
|
Option.cpp
|
||||||
calibration/Stats.hpp
|
Option.hpp
|
||||||
models/Model.cpp
|
PricingEngine.cpp
|
||||||
models/Model.hpp
|
PricingEngine.hpp
|
||||||
|
MonteCarloEngine.cpp
|
||||||
|
MonteCarloEngine.hpp
|
||||||
|
StochasticProcess.cpp
|
||||||
|
StochasticProcess.hpp
|
||||||
|
Exercise.cpp
|
||||||
|
Exercise.hpp
|
||||||
|
MarketData.cpp
|
||||||
|
MarketData.hpp
|
||||||
|
YieldCurve.cpp
|
||||||
|
YieldCurve.hpp
|
||||||
|
VolatilitySurface.cpp
|
||||||
|
VolatilitySurface.hpp
|
||||||
|
RandomGenerator.cpp
|
||||||
|
RandomGenerator.hpp
|
||||||
|
Statistics.cpp
|
||||||
|
Statistics.hpp
|
||||||
|
BlackScholesProcess.cpp
|
||||||
|
BlackScholesProcess.hpp
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(qengine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(qengine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
// Created by David Doebel on 05.03.2026.
|
// Created by David Doebel on 05.03.2026.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "Model.hpp"
|
#include "Exercise.hpp"
|
||||||
53
src/Exercise.hpp
Normal file
53
src/Exercise.hpp
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_EXERCISE_HPP
|
||||||
|
#define QUANTENGINE_EXERCISE_HPP
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Exercise {
|
||||||
|
public:
|
||||||
|
Exercise() = default;
|
||||||
|
virtual ~Exercise() = default;
|
||||||
|
enum class Type {
|
||||||
|
European,
|
||||||
|
American,
|
||||||
|
Bermudan
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual Type type() const = 0;
|
||||||
|
protected:
|
||||||
|
std::vector<double> exercise_times_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class EuropeanExercise : public Exercise {
|
||||||
|
EuropeanExercise() : type_(Type::European) {};
|
||||||
|
EuropeanExercise(double maturity) : type_(Type::European){
|
||||||
|
exercise_times_.push_back(maturity);
|
||||||
|
}
|
||||||
|
~EuropeanExercise() override = default;
|
||||||
|
[[nodiscard]] Type type() const override {
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Type type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AmericanExercise : public Exercise{
|
||||||
|
AmericanExercise() : type_(Type::American) {};
|
||||||
|
AmericanExercise(double maturity) : type_(Type::American) {
|
||||||
|
exercise_times_.push_back(0);
|
||||||
|
exercise_times_.push_back(maturity);
|
||||||
|
}
|
||||||
|
[[nodiscard]] Type type() const override {
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_EXERCISE_HPP
|
||||||
17
src/Instrument.cpp
Normal file
17
src/Instrument.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Instrument.hpp"
|
||||||
|
|
||||||
|
Instrument::Instrument(double maturity, std::unique_ptr<Payoff> payoff,
|
||||||
|
std::unique_ptr<PricingEngine> engine) : maturity_(maturity), payoff_(std::move(payoff)), engine_
|
||||||
|
(std::move(engine)){
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
double Instrument::price() const {
|
||||||
|
return engine_->calculate(*this);
|
||||||
|
}
|
||||||
|
|
||||||
34
src/Instrument.hpp
Normal file
34
src/Instrument.hpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_INSTRUMENT_HPP
|
||||||
|
#define QUANTENGINE_INSTRUMENT_HPP
|
||||||
|
#include "Payoff.hpp"
|
||||||
|
#include "PricingEngine.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class PricingEngine;
|
||||||
|
|
||||||
|
class Instrument {
|
||||||
|
public:
|
||||||
|
Instrument() = default;
|
||||||
|
Instrument(double maturity, std::unique_ptr<Payoff> payoff, std::unique_ptr<PricingEngine> engine);
|
||||||
|
double price() const;
|
||||||
|
|
||||||
|
[[nodiscard]] double maturity() const {
|
||||||
|
return maturity_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Payoff& payoff() const {
|
||||||
|
return *payoff_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
double maturity_;
|
||||||
|
std::unique_ptr<Payoff> payoff_;
|
||||||
|
std::unique_ptr<PricingEngine> engine_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_INSTRUMENT_HPP
|
||||||
9
src/MarketData.cpp
Normal file
9
src/MarketData.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "MarketData.hpp"
|
||||||
|
|
||||||
|
double MarketData::spot() const { return spot_; }
|
||||||
|
YieldCurve& MarketData::yield_curve() { return *yield_curve_; }
|
||||||
|
VolatilitySurface& MarketData::volatility_surface() { return *volatility_surface_; }
|
||||||
33
src/MarketData.hpp
Normal file
33
src/MarketData.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_MARKETDATA_HPP
|
||||||
|
#define QUANTENGINE_MARKETDATA_HPP
|
||||||
|
#include "YieldCurve.hpp"
|
||||||
|
#include "VolatilitySurface.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class MarketData {
|
||||||
|
public:
|
||||||
|
MarketData() = default;
|
||||||
|
|
||||||
|
MarketData(double spot, std::unique_ptr<YieldCurve> yield_curve,
|
||||||
|
std::unique_ptr<VolatilitySurface> volatility_surface)
|
||||||
|
: spot_(spot),
|
||||||
|
yield_curve_(std::move(yield_curve)),
|
||||||
|
volatility_surface_(std::move(volatility_surface)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
double spot() const;
|
||||||
|
YieldCurve& yield_curve();
|
||||||
|
VolatilitySurface& volatility_surface();
|
||||||
|
|
||||||
|
private:
|
||||||
|
double spot_;
|
||||||
|
std::unique_ptr<YieldCurve> yield_curve_;
|
||||||
|
std::unique_ptr<VolatilitySurface> volatility_surface_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_MARKETDATA_HPP
|
||||||
24
src/MonteCarloEngine.cpp
Normal file
24
src/MonteCarloEngine.cpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "MonteCarloEngine.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include "Instrument.hpp"
|
||||||
|
#include "Statistics.hpp"
|
||||||
|
|
||||||
|
double MonteCarloEngine::calculate(const Instrument &instrument) const {
|
||||||
|
// parameters
|
||||||
|
double T = instrument.maturity();
|
||||||
|
double spot = process_->data().spot();
|
||||||
|
Statistics stats;
|
||||||
|
|
||||||
|
auto rNumbers = rng_->nextGaussianVector(numPaths_);
|
||||||
|
std::vector<double> payoffs(numPaths_);
|
||||||
|
for (std::size_t i = 0; i < numPaths_; ++i) {
|
||||||
|
double terminalPrice = process_->step(0.0,spot,T,rNumbers[i]);
|
||||||
|
double payoff = instrument.payoff()(terminalPrice);
|
||||||
|
stats.dump(payoff);
|
||||||
|
}
|
||||||
|
return stats.mean() * process_->data().yield_curve().discount(T);
|
||||||
|
}
|
||||||
23
src/MonteCarloEngine.hpp
Normal file
23
src/MonteCarloEngine.hpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_MONTECARLOENGINE_HPP
|
||||||
|
#define QUANTENGINE_MONTECARLOENGINE_HPP
|
||||||
|
#include "PricingEngine.hpp"
|
||||||
|
#include "RandomGenerator.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class MonteCarloEngine : public PricingEngine{
|
||||||
|
public:
|
||||||
|
MonteCarloEngine() = default;
|
||||||
|
MonteCarloEngine(int numPaths, std::unique_ptr<StochasticProcess> process, std::shared_ptr<RandomGenerator> rng):
|
||||||
|
numPaths_(numPaths), PricingEngine(std::move(process)), rng_(std::move(rng)) {}
|
||||||
|
double calculate(const Instrument& instrument) const override;
|
||||||
|
private:
|
||||||
|
int numPaths_;
|
||||||
|
std::shared_ptr<RandomGenerator> rng_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_MONTECARLOENGINE_HPP
|
||||||
10
src/Option.cpp
Normal file
10
src/Option.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Option.hpp"
|
||||||
|
|
||||||
|
Option::Option(double maturity, std::unique_ptr<Exercise> exercise, std::unique_ptr<Payoff> payoff,
|
||||||
|
std::unique_ptr<PricingEngine> engine) : Instrument(maturity, std::move(payoff),
|
||||||
|
std::move(engine)), exercise_(std::move(exercise)){
|
||||||
|
}
|
||||||
33
src/Option.hpp
Normal file
33
src/Option.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_OPTION_HPP
|
||||||
|
#define QUANTENGINE_OPTION_HPP
|
||||||
|
#include "Instrument.hpp"
|
||||||
|
#include "Exercise.hpp"
|
||||||
|
|
||||||
|
class Option : public Instrument{
|
||||||
|
public:
|
||||||
|
Option() = default;
|
||||||
|
virtual ~Option() = default;
|
||||||
|
Option(double maturity, std::unique_ptr<Exercise> exercise,
|
||||||
|
std::unique_ptr<Payoff> payoff, std::unique_ptr<PricingEngine> engine);
|
||||||
|
[[nodiscard]] Exercise& exercise() const {
|
||||||
|
return *exercise_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<Exercise> exercise_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VanillaOption : public Option {
|
||||||
|
public:
|
||||||
|
using Option::Option;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_OPTION_HPP
|
||||||
18
src/Payoff.cpp
Normal file
18
src/Payoff.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Payoff.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
double CallPayoff::operator()(double S) {
|
||||||
|
return std::max(0., S - strike_);
|
||||||
|
}
|
||||||
|
|
||||||
|
double PutPayoff::operator()(double S) {
|
||||||
|
return std::max(0., strike_ - S);
|
||||||
|
}
|
||||||
|
|
||||||
|
double DigitalPayoff::operator()(double S) {
|
||||||
|
return S > strike_ ? 1. : 0.;
|
||||||
|
}
|
||||||
51
src/Payoff.hpp
Normal file
51
src/Payoff.hpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_PAYOFF_HPP
|
||||||
|
#define QUANTENGINE_PAYOFF_HPP
|
||||||
|
|
||||||
|
|
||||||
|
class Payoff {
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
Payoff() = default;
|
||||||
|
virtual ~Payoff() = default;
|
||||||
|
virtual double operator()(double S) = 0;
|
||||||
|
virtual double strike() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CallPayoff : public Payoff {
|
||||||
|
public:
|
||||||
|
CallPayoff() = default;
|
||||||
|
CallPayoff(double strike) : strike_(strike) {}
|
||||||
|
double operator()(double S) override;
|
||||||
|
double strike() override {return strike_;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
double strike_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PutPayoff : public Payoff {
|
||||||
|
public:
|
||||||
|
PutPayoff() = default;
|
||||||
|
PutPayoff(double strike) : strike_(strike) {}
|
||||||
|
double operator()(double S) override;
|
||||||
|
double strike() override {return strike_;}
|
||||||
|
private:
|
||||||
|
double strike_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DigitalPayoff : public Payoff {
|
||||||
|
public:
|
||||||
|
DigitalPayoff() = default;
|
||||||
|
DigitalPayoff(double strike) : strike_(strike) {}
|
||||||
|
double operator()(double S) override;
|
||||||
|
double strike() override {return strike_;}
|
||||||
|
private:
|
||||||
|
double strike_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_PAYOFF_HPP
|
||||||
5
src/PricingEngine.cpp
Normal file
5
src/PricingEngine.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "PricingEngine.hpp"
|
||||||
26
src/PricingEngine.hpp
Normal file
26
src/PricingEngine.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_PRICINGENGINE_HPP
|
||||||
|
#define QUANTENGINE_PRICINGENGINE_HPP
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "StochasticProcess.hpp"
|
||||||
|
|
||||||
|
class Instrument;
|
||||||
|
|
||||||
|
class PricingEngine {
|
||||||
|
public:
|
||||||
|
PricingEngine() = default;
|
||||||
|
PricingEngine(std::unique_ptr<StochasticProcess> process) : process_(std::move(process)){}
|
||||||
|
|
||||||
|
virtual ~PricingEngine() = default;
|
||||||
|
virtual double calculate(const Instrument& instrument) const = 0;
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<StochasticProcess> process_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_PRICINGENGINE_HPP
|
||||||
18
src/RandomGenerator.cpp
Normal file
18
src/RandomGenerator.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "RandomGenerator.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
double MersenneTwister::nextGaussian() {
|
||||||
|
return distr_(generator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> MersenneTwister::nextGaussianVector(std::size_t n) {
|
||||||
|
std::vector<double> v(n);
|
||||||
|
for (auto& e : v) {
|
||||||
|
e = nextGaussian();
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
28
src/RandomGenerator.hpp
Normal file
28
src/RandomGenerator.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_RANDOMGENERATOR_HPP
|
||||||
|
#define QUANTENGINE_RANDOMGENERATOR_HPP
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
class RandomGenerator {
|
||||||
|
public:
|
||||||
|
RandomGenerator() = default;
|
||||||
|
virtual ~RandomGenerator() = default;
|
||||||
|
virtual double nextGaussian() = 0;
|
||||||
|
virtual std::vector<double> nextGaussianVector(std::size_t n) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MersenneTwister : public RandomGenerator {
|
||||||
|
public:
|
||||||
|
MersenneTwister() = default;
|
||||||
|
double nextGaussian() override;
|
||||||
|
std::vector<double> nextGaussianVector(std::size_t n) override;
|
||||||
|
private:
|
||||||
|
std::mt19937 generator_;
|
||||||
|
std::normal_distribution<> distr_ {0.0, 1.0};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_RANDOMGENERATOR_HPP
|
||||||
52
src/Statistics.cpp
Normal file
52
src/Statistics.cpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Statistics.hpp"
|
||||||
|
|
||||||
|
void Statistics::dump(double value) {
|
||||||
|
for (std::size_t i = 0; i < 3; ++i) {
|
||||||
|
moments_[i] += std::pow(value, i+1);
|
||||||
|
}
|
||||||
|
++n;
|
||||||
|
max_ = std::max(max_, value);
|
||||||
|
min_ = std::min(min_, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Statistics::clear() {
|
||||||
|
n = 0;
|
||||||
|
moments_ = {0.,0.,0.};
|
||||||
|
}
|
||||||
|
|
||||||
|
double Statistics::mean() {
|
||||||
|
return moments_[0]/n;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Statistics::variance() {
|
||||||
|
return moments_[1]/n - std::pow(mean(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Statistics::standardDeviation() {
|
||||||
|
return std::sqrt(variance());
|
||||||
|
}
|
||||||
|
|
||||||
|
double Statistics::skewness() {
|
||||||
|
return moments_[2]/std::pow(n, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double Statistics::max() {
|
||||||
|
return max_;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Statistics::min() {
|
||||||
|
return min_;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Statistics::sum() {
|
||||||
|
return moments_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
double Statistics::count() {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
30
src/Statistics.hpp
Normal file
30
src/Statistics.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_STATISTICS_HPP
|
||||||
|
#define QUANTENGINE_STATISTICS_HPP
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
class Statistics {
|
||||||
|
public:
|
||||||
|
Statistics() : moments_({0., 0., 0.}), max_(0.), min_(0.) {}
|
||||||
|
void dump(double value);
|
||||||
|
void clear();
|
||||||
|
double mean();
|
||||||
|
double variance();
|
||||||
|
double standardDeviation();
|
||||||
|
double skewness();
|
||||||
|
double max();
|
||||||
|
double min();
|
||||||
|
double sum();
|
||||||
|
double count();
|
||||||
|
private:
|
||||||
|
std::vector<double> moments_;
|
||||||
|
std::size_t n;
|
||||||
|
double max_, min_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_STATISTICS_HPP
|
||||||
5
src/StochasticProcess.cpp
Normal file
5
src/StochasticProcess.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "StochasticProcess.hpp"
|
||||||
28
src/StochasticProcess.hpp
Normal file
28
src/StochasticProcess.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 05.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_STOCHASTICPROCESS_HPP
|
||||||
|
#define QUANTENGINE_STOCHASTICPROCESS_HPP
|
||||||
|
#include "MarketData.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class StochasticProcess {
|
||||||
|
public:
|
||||||
|
StochasticProcess() = default;
|
||||||
|
StochasticProcess(std::unique_ptr<MarketData> data) : data_(std::move(data)){}
|
||||||
|
|
||||||
|
virtual ~StochasticProcess() = default;
|
||||||
|
virtual double drift(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;
|
||||||
|
MarketData& data() const {return *data_;}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<MarketData> data_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_STOCHASTICPROCESS_HPP
|
||||||
5
src/VolatilitySurface.cpp
Normal file
5
src/VolatilitySurface.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "VolatilitySurface.hpp"
|
||||||
18
src/VolatilitySurface.hpp
Normal file
18
src/VolatilitySurface.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_VOLATILITYSURFACE_HPP
|
||||||
|
#define QUANTENGINE_VOLATILITYSURFACE_HPP
|
||||||
|
|
||||||
|
|
||||||
|
class VolatilitySurface {
|
||||||
|
public:
|
||||||
|
virtual ~VolatilitySurface() = default;
|
||||||
|
virtual double sigma(double K, double T) = 0;
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_VOLATILITYSURFACE_HPP
|
||||||
5
src/YieldCurve.cpp
Normal file
5
src/YieldCurve.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "YieldCurve.hpp"
|
||||||
37
src/YieldCurve.hpp
Normal file
37
src/YieldCurve.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef QUANTENGINE_YIELDCURVE_HPP
|
||||||
|
#define QUANTENGINE_YIELDCURVE_HPP
|
||||||
|
|
||||||
|
|
||||||
|
class YieldCurve {
|
||||||
|
public:
|
||||||
|
YieldCurve() = default;
|
||||||
|
|
||||||
|
YieldCurve(const YieldCurve &other) {
|
||||||
|
}
|
||||||
|
|
||||||
|
YieldCurve(YieldCurve &&other) noexcept {
|
||||||
|
}
|
||||||
|
|
||||||
|
YieldCurve & operator=(const YieldCurve &other) {
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
YieldCurve & operator=(YieldCurve &&other) noexcept {
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
virtual ~YieldCurve() = default;
|
||||||
|
virtual double discount(double t) = 0;
|
||||||
|
virtual double zeroRate(double t) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //QUANTENGINE_YIELDCURVE_HPP
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 04.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Stats.hpp"
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
void Stats::update(double x) {
|
|
||||||
running_sum_ += x;
|
|
||||||
running_square_sum_ += x * x;
|
|
||||||
n_++;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
double Stats::mean() const {
|
|
||||||
return running_sum_ / n_;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Stats::square_mean() const {
|
|
||||||
return running_square_sum_ / n_;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Stats::variance() const {
|
|
||||||
double mean = this->mean();
|
|
||||||
double square_mean = this->square_mean();
|
|
||||||
return square_mean * square_mean - mean * mean;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
double Stats::std_error() const {
|
|
||||||
return std::sqrt(variance()/n_);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<double, double> Stats::CI() const {
|
|
||||||
return std::make_pair(running_sum_ - 1.96 * std_error(), running_sum_ + 1.96 * std_error());
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 04.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef QUANTENGINE_STATS_HPP
|
|
||||||
#define QUANTENGINE_STATS_HPP
|
|
||||||
#include <cstddef>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
class Stats {
|
|
||||||
private:
|
|
||||||
size_t n_ = 0;
|
|
||||||
double running_sum_ = 0.0;
|
|
||||||
double running_square_sum_ = 0.0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Stats() = delete;
|
|
||||||
void update(double x);
|
|
||||||
double mean() const;
|
|
||||||
double square_mean() const;
|
|
||||||
double variance() const;
|
|
||||||
double std_error() const;
|
|
||||||
std::pair<double, double> CI() const; // alpha = 5%
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //QUANTENGINE_STATS_HPP
|
|
||||||
22
src/main.cpp
22
src/main.cpp
@@ -1,22 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 03.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "models/black_scholes.hpp"
|
|
||||||
#include "simulation/monte_carlo.hpp"
|
|
||||||
#include "models/payoff.hpp"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
BlackScholes model(100.0, 0.05, 0.2, 1.0);
|
|
||||||
CallPayoff payoff(100.0);
|
|
||||||
|
|
||||||
MonteCarloEngine mc;
|
|
||||||
|
|
||||||
double price = mc.price(model, payoff, 1000000);
|
|
||||||
|
|
||||||
std::cout << "MC Price: " << price << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 05.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef QUANTENGINE_MODEL_HPP
|
|
||||||
#define QUANTENGINE_MODEL_HPP
|
|
||||||
|
|
||||||
|
|
||||||
class Model {
|
|
||||||
public:
|
|
||||||
Model() = default;
|
|
||||||
virtual ~Model() = 0;
|
|
||||||
[[nodiscard]] virtual double terminal_price(double Z) const = 0;
|
|
||||||
[[nodiscard]] virtual double discount() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //QUANTENGINE_MODEL_HPP
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 03.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "black_scholes.hpp"
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 03.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef OPTION_PRICING_BLACK_SCHOLES_HPP
|
|
||||||
#define OPTION_PRICING_BLACK_SCHOLES_HPP
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include "Model.hpp"
|
|
||||||
|
|
||||||
class BlackScholes : public Model{
|
|
||||||
public:
|
|
||||||
BlackScholes(double S0, double r, double sigma, double T)
|
|
||||||
: Model(), S0_(S0), r_(r), sigma_(sigma), T_(T) {
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double terminal_price(double Z) const override{
|
|
||||||
return S0_ * std::exp(
|
|
||||||
(r_ - 0.5 * sigma_ * sigma_) * T_
|
|
||||||
+ sigma_ * std::sqrt(T_) * Z
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double discount() const override{
|
|
||||||
return std::exp(-r_ * T_);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
double S0_, r_, sigma_, T_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //OPTION_PRICING_BLACK_SCHOLES_HPP
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 03.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "payoff.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
double CallPayoff::operator()(double ST) const {
|
|
||||||
return std::max(ST - K_, 0.0);
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 03.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef OPTION_PRICING_PAYOFF_HPP
|
|
||||||
#define OPTION_PRICING_PAYOFF_HPP
|
|
||||||
class Payoff {
|
|
||||||
public:
|
|
||||||
virtual double operator()(double ST) const = 0;
|
|
||||||
virtual ~Payoff() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CallPayoff : public Payoff {
|
|
||||||
public:
|
|
||||||
CallPayoff(double K) : K_(K) {}
|
|
||||||
|
|
||||||
double operator()(double ST) const override;
|
|
||||||
private:
|
|
||||||
double K_;
|
|
||||||
};
|
|
||||||
#endif //OPTION_PRICING_PAYOFF_HPP
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 03.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "monte_carlo.hpp"
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by David Doebel on 03.03.2026.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef OPTION_PRICING_MONTE_CARLO_HPP
|
|
||||||
#define OPTION_PRICING_MONTE_CARLO_HPP
|
|
||||||
#pragma once
|
|
||||||
#include <random>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class MonteCarloEngine {
|
|
||||||
public:
|
|
||||||
MonteCarloEngine(unsigned long seed = 42)
|
|
||||||
: gen_(seed), dist_(0.0, 1.0) {}
|
|
||||||
|
|
||||||
template<typename Model, typename Payoff>
|
|
||||||
double price(const Model& model,
|
|
||||||
const Payoff& payoff,
|
|
||||||
std::size_t N) {
|
|
||||||
|
|
||||||
double sum = 0.0;
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < N; ++i) {
|
|
||||||
double Z = dist_(gen_);
|
|
||||||
double ST = model.terminal_price(Z);
|
|
||||||
sum += payoff(ST);
|
|
||||||
}
|
|
||||||
|
|
||||||
return model.discount() * sum / N;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::mt19937_64 gen_;
|
|
||||||
std::normal_distribution<> dist_;
|
|
||||||
};
|
|
||||||
#endif //OPTION_PRICING_MONTE_CARLO_HPP
|
|
||||||
2
tests/stubs/FakeMarketData.cpp
Normal file
2
tests/stubs/FakeMarketData.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Minimal TU to satisfy CMake for test stubs
|
||||||
|
#include "FakeMarketData.hpp"
|
||||||
38
tests/stubs/FakeMarketData.hpp
Normal file
38
tests/stubs/FakeMarketData.hpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
2
tests/stubs/FlatVolatilitySurface.cpp
Normal file
2
tests/stubs/FlatVolatilitySurface.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Minimal TU to satisfy CMake for test stubs
|
||||||
|
#include "FlatVolatilitySurface.hpp"
|
||||||
11
tests/stubs/FlatVolatilitySurface.hpp
Normal file
11
tests/stubs/FlatVolatilitySurface.hpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 07.03.2026.
|
||||||
|
//
|
||||||
|
#ifndef QUANTENGINE_FLATVOLATILITYSURFACE_HPP
|
||||||
|
#define QUANTENGINE_FLATVOLATILITYSURFACE_HPP
|
||||||
|
#include "VolatilitySurface.hpp"
|
||||||
|
|
||||||
|
class FlatVolatilitySurface : public VolatilitySurface {
|
||||||
|
double sigma(double K, double T) {return 0.2;}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
2
tests/stubs/FlatYieldCurve.cpp
Normal file
2
tests/stubs/FlatYieldCurve.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Minimal TU to satisfy CMake for test stubs
|
||||||
|
#include "FlatYieldCurve.hpp"
|
||||||
16
tests/stubs/FlatYieldCurve.hpp
Normal file
16
tests/stubs/FlatYieldCurve.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 07.03.2026.
|
||||||
|
//
|
||||||
|
#ifndef QUANTENGINE_FLATYIELDCURVE_HPP
|
||||||
|
#define QUANTENGINE_FLATYIELDCURVE_HPP
|
||||||
|
#include "YieldCurve.hpp"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
class FlatYieldCurve : public YieldCurve{
|
||||||
|
|
||||||
|
double discount(double t) override {return std::exp(-rate_ * t); };
|
||||||
|
double zeroRate(double t) override {return rate_; }
|
||||||
|
private:
|
||||||
|
double rate_ = 0.01;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
49
tests/test_black_scholes.cpp
Normal file
49
tests/test_black_scholes.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Created by David Doebel on 06.03.2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "BlackScholesProcess.hpp"
|
||||||
|
#include "MonteCarloEngine.hpp"
|
||||||
|
#include "Instrument.hpp"
|
||||||
|
#include "Option.hpp"
|
||||||
|
#include "Payoff.hpp"
|
||||||
|
|
||||||
|
#include "stubs/FlatYieldCurve.hpp"
|
||||||
|
#include "stubs/FlatVolatilitySurface.hpp"
|
||||||
|
#include "stubs/FakeMarketData.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
|
||||||
|
|
||||||
|
// Build Black-Scholes process with fake flat market data
|
||||||
|
auto processCall = std::make_unique<BlackScholesProcess>(std::make_unique<FakeMarketData>());
|
||||||
|
auto processPut = std::make_unique<BlackScholesProcess>(std::make_unique<FakeMarketData>());
|
||||||
|
|
||||||
|
// RNG shared between engines is fine
|
||||||
|
auto rng = std::make_shared<MersenneTwister>();
|
||||||
|
|
||||||
|
// Pricing engines
|
||||||
|
auto mcCall = std::make_unique<MonteCarloEngine>(numPaths, std::move(processCall), rng);
|
||||||
|
auto mcPut = std::make_unique<MonteCarloEngine>(numPaths, std::move(processPut), rng);
|
||||||
|
|
||||||
|
// Instruments (European vanilla) with call and put payoffs
|
||||||
|
Instrument callInstr(T, std::make_unique<CallPayoff>(K), std::move(mcCall));
|
||||||
|
Instrument putInstr(T, std::make_unique<PutPayoff>(K), std::move(mcPut));
|
||||||
|
|
||||||
|
const double callPrice = callInstr.price();
|
||||||
|
const double putPrice = putInstr.price();
|
||||||
|
|
||||||
|
// Ground truth Black–Scholes prices provided
|
||||||
|
const double callGT = 10.450583572;
|
||||||
|
const double putGT = 5.573526022;
|
||||||
|
|
||||||
|
// Monte Carlo tolerance
|
||||||
|
const double tol = 0.10; // 10 cents tolerance
|
||||||
|
|
||||||
|
ASSERT_NEAR(callPrice, callGT, tol);
|
||||||
|
ASSERT_NEAR(putPrice, putGT, tol);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user