diff --git a/CMakeLists.txt b/CMakeLists.txt index 6962be6..7a61822 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,18 @@ cmake_minimum_required(VERSION 3.0.0) project(OptionPricing VERSION 0.1.0) +set(CMAKE_CXX_COMPILER "clang++") +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -c") + include(CTest) enable_testing() -add_executable(OptionPricing main.cpp) +add_library(CallPut CallPut.cpp) + +add_executable(OptionPricing main.cpp ) +target_link_libraries(OptionPricing PRIVATE CallPut) + + set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) diff --git a/CallPut.cpp b/CallPut.cpp index ba5ecea..f80d6fd 100644 --- a/CallPut.cpp +++ b/CallPut.cpp @@ -1,15 +1,17 @@ #include "CallPut.h" -CallOption::CallOption(double _expiry, double _strike): VanillaOption(_expiry, _strike){}; +CallOption::CallOption(double _expiry, double _strike): VanillaOption(_expiry, _strike) { }; -double CallOption::payoff(double spot) const +double CallOption::payoff(double spot) const { double pf = spot - strike; return pf > 0. ? pf : 0.; } -PutOption::PutOption(double _expiry, double _strike): VanillaOption(_expiry, _strike){}; + + +PutOption::PutOption(double _expiry, double _strike): VanillaOption(_expiry, _strike) { }; double PutOption::payoff(double spot) const { diff --git a/CallPut.h b/CallPut.h index c3a1eed..2e13824 100644 --- a/CallPut.h +++ b/CallPut.h @@ -1,13 +1,14 @@ #ifndef CALLPUT_H #define CALLPUT_H +#include "PayOff.h" #include "VanillaOption.h" class CallOption: public PayOff, public VanillaOption { public: CallOption(double _expiry, double _strike); - ~CallOption(); + virtual ~CallOption() {}; double payoff(double spot) const; @@ -18,11 +19,13 @@ class PutOption: public PayOff, public VanillaOption { public: PutOption(double _expiry, double _strike); - ~PutOption(); + virtual ~PutOption() {}; double payoff(double spot) const; private: }; + + #endif //CALLPUT_H \ No newline at end of file diff --git a/MCEstimator.h b/MCEstimator.h new file mode 100644 index 0000000..441d047 --- /dev/null +++ b/MCEstimator.h @@ -0,0 +1,38 @@ +#ifndef MCESTIMATOR_H +#define MCESTIMATOR_H + +#include"PayOff.h" + +double MCEstimator( + const PayOff & claim, + const double T, + const double r, + const double sigma, + const double S_0, + const unsigned int sample ) +{ + + RandVar r_var; + + + const double drift = (r - 0.5 * sigma * sigma) * T; + const double std_dev = sigma * sqrt(T); + + double P_avg = 0; + double S_T, n; + + + for(int i = 0; i< sample; i++) + { + n = r_var.getNormal(); + S_T = S_0 * exp( drift + std_dev * n ); + P_avg += claim.payoff(S_T); + } + + P_avg = exp(- r * T) * P_avg / sample; + + return P_avg; +} + + +#endif // MCESTIMATOR_H \ No newline at end of file diff --git a/PayOff.h b/PayOff.h index c8e4026..df0cb4d 100644 --- a/PayOff.h +++ b/PayOff.h @@ -5,9 +5,10 @@ class PayOff { public: PayOff(){}; - virtual double payoff(double spot_price) const = 0; - virtual ~PayOff(){}; + virtual double payoff(double ) const = 0; + virtual ~PayOff() {}; private: }; + #endif // PAYOFF_H \ No newline at end of file diff --git a/RandomVariable.h b/RandomVariable.h new file mode 100644 index 0000000..02fb500 --- /dev/null +++ b/RandomVariable.h @@ -0,0 +1,77 @@ +#ifndef RANDOMVARIABLE_H +#define RANDOMVARIABLE_H + +#include +#include + +class RandVar +{ +public: + RandVar(); + RandVar(unsigned int seed); + ~RandVar() {}; + + double getUniform() ; + double getNormal() ; + + std::vector getUniform(const unsigned int N) ; + std::vector getNormal(const unsigned int N) ; + + +}; + +RandVar::RandVar() {} + +RandVar::RandVar(unsigned int seed) +{ + std::srand(seed); +} + +double RandVar::getUniform() +{ + return (double) std::rand()/RAND_MAX; +} + +double RandVar::getNormal() +{ + /* To be improved. + - Wasting one variable + - check for machine 0 + */ + double u1 = getUniform(); + double u2 = getUniform(); + + double r = std::sqrt( -2 * std::log(u1) ); + double n1 = r * cos(2* M_PI * u2); + + return n1; +} + + +std::vector RandVar::getUniform(const unsigned int N) +{ + std::vector res; + + for(int i = 0; i RandVar::getNormal(const unsigned int N) +{ + std::vector res; + + for(int i = 0; i +#include "Stock.h" +#include "RandomVariable.h" + +class StockPath : public Stock +{ +public: + StockPath(const Stock & _stock, double _period, unsigned long _steps); + + std::vector generatePath(); + +private: + unsigned long steps; + double period_length; + double dt; +}; + +StockPath::StockPath(const Stock & _stock, double _period, unsigned long _steps) + :Stock(_stock) +{ + steps = _steps; + period_length = _period; + dt = period_length / steps; +} + +std::vector StockPath::generatePath() +{ + RandVar rng; + + std::vector res; + + double vol = getVol() * sqrt(dt); + double square_vol = getVol() * getVol() * dt; + double drift = getReturn() * dt - 0.5 * square_vol; + + double last = getSpot(); + res.push_back(last); + + for(int i = 0; i< steps; i++) + { + last = last * exp(drift + vol * rng.getNormal()); + res.push_back(last); + } + + return res; +} + + +#endif //STOCKPATH_H \ No newline at end of file diff --git a/VanillaOption.h b/VanillaOption.h index 7afec21..810c437 100644 --- a/VanillaOption.h +++ b/VanillaOption.h @@ -1,24 +1,21 @@ #ifndef VANILLAOPTION_H #define VANILLAOPTION_H -#include "PayOff.h" - class VanillaOption { public: - VanillaOption(double, double); + VanillaOption(double _expiry, double _strike): strike(_strike), expiry(_expiry){}; + ~VanillaOption() {} - inline const double getExpiry() {return expiry;} - inline const double getStrike() {return strike;} + inline double getExpiry() const {return expiry;} + inline double getStrike() const {return strike;} protected: double expiry; double strike; }; -VanillaOption::VanillaOption(double _expiry, double _strike) : strike(_strike), expiry(_expiry) -{} diff --git a/main.cpp b/main.cpp index 548aa1b..4d35bd8 100644 --- a/main.cpp +++ b/main.cpp @@ -1,54 +1,58 @@ #include #include + +#include "RandomVariable.h" +#include "MCEstimator.h" +#include "Stock.h" +#include "StockPath.h" #include "CallPut.h" -double NormalRand(); + int main() { - const int SAMPLE_SIZE = 100000000; + const int SAMPLE_SIZE = 10000000; // Pricing constants - const double r = 0.05; - const double sigma = 0.1; - const double S_0 = 1.0; - const double K = 1.0; - const double T = 1.0; + const double r = 0.05; // Risk-free rate + const double sigma = 0.05; // root variance + const double S_0 = 3.0; // initial stock value - const double drift = (r - 0.5 * sigma * sigma) * T; - const double std_dev = sigma * sqrt(T); - double P_avg = 0; - double S_T, n; + const double strike = 3.0; + const double expiry = 1.0; - CallOption call(T, K); + const CallOption call(expiry, strike); + const PutOption put(expiry, strike); - for(int i = 0; i< SAMPLE_SIZE; i++) - { - n = NormalRand(); - S_T = S_0 * exp( drift + std_dev * n ); - P_avg += call.payoff(S_T); - } + // const Stock stck; - P_avg = exp(r * T) * P_avg / SAMPLE_SIZE; + double resCall = MCEstimator( + call, + expiry, + r, + sigma, + S_0, + SAMPLE_SIZE + ); - std::cout << P_avg << '\n'; + double resPut = MCEstimator( + put, + expiry, + r, + sigma, + S_0, + SAMPLE_SIZE + ); -} -double UniformRand() -{ - return (double) std::rand()/RAND_MAX; -} -double NormalRand() -{ - double u1 = UniformRand(); - double u2 = UniformRand(); + std::cout << "Call price: " << resCall << '\n'; + // std::cout << "Put price: " << resPut << '\n'; + // std::cout << "Strike PV: " << strike * exp(-r * expiry) << '\n'; + // std::cout << "Check put/call parity:" << resCall - resPut + strike * exp(-r * expiry) << '\n'; - double r = std::sqrt( -2 * std::log(u1) ); - double n1 = r * cos(2* M_PI * u2); - return n1; -} \ No newline at end of file +} +