├── LectureSlides ├── .gitkeep └── CppCon_2019_Math_in_Cpp_FINAL.pdf ├── README.md └── SourceCode ├── .gitkeep ├── BoostExamples ├── .gitkeep ├── Accumulators.cpp ├── CircularBuffers.cpp ├── EuroTree.cpp ├── EuroTree.h ├── IntegrationAndDifferentiation.cpp ├── MultiArray.cpp ├── Node.h ├── RealFunction.h ├── TestClassForMultiArray.h ├── TimeSeries.cpp └── TimeSeries.h ├── CppCon2019.vcxproj ├── ExampleFunctionsHeader.h ├── Main.cpp ├── MonteCarloOptions ├── .gitkeep ├── EquityPriceGenerator.cpp ├── EquityPriceGenerator.h ├── MCEuroOptPricer.cpp └── MCEuroOptPricer.h ├── RootFinding ├── .gitkeep ├── Bisection.h └── Steffenson.h └── RootFindingExamples.cpp /LectureSlides/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LectureSlides/CppCon_2019_Math_in_Cpp_FINAL.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantDevHacks/CppCon2019Backup/2de390b23cd8276642280c5c165b1f7c4829a6c4/LectureSlides/CppCon_2019_Math_in_Cpp_FINAL.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CppCon2019 2 | Sample Code to accompany _Leveraging Modern C++ in Quantitative Finance_. 3 | -------------------------------------------------------------------------------- /SourceCode/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/Accumulators.cpp: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2018, Daniel Hanson 2 | // See license details at bottom of file 3 | 4 | #include "../ExampleFunctionsHeader.h" 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include // bind.hpp and ref.hpp are needed 14 | #include // for using accumulator calculations from a std::vector 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | using namespace boost::accumulators; 22 | 23 | using std::vector; 24 | using std::for_each; 25 | using std::move; 26 | 27 | using std::cout; 28 | using std::endl; 29 | 30 | void minMaxAccumulator() 31 | { 32 | cout << "*** minMaxAccumulator() ***" << endl; 33 | accumulator_set > acc; 34 | // push in some data . . . 35 | acc(5.8); 36 | acc(-1.7); 37 | acc(2.9); 38 | // Display the range 39 | cout << '(' << extract::min(acc) << ", " << extract::max(acc) << ")\n"; 40 | cout << endl; 41 | } 42 | 43 | void meanAndVarAccumulator() 44 | { 45 | cout << "*** meanAndVarAccumulator() ***" << endl; 46 | accumulator_set > acc; 47 | // push in some data . . . 48 | acc(1.2); 49 | acc(2.3); 50 | acc(3.4); 51 | acc(4.5); 52 | // Display the range 53 | cout << '(' << extract::mean(acc) << ", " << extract::variance(acc) << ")\n"; 54 | cout << endl; 55 | } 56 | 57 | void vectorAndAccumulator() 58 | { 59 | cout << "*** vectorAndAccumulator() ***" << endl; 60 | vector v{ -0.7196, -3.5214 , 16.3332, 19.5379, 61 | 2.6357, 5.1342 , -7.4481 }; 62 | 63 | accumulator_set > acc; 64 | 65 | // Just know this pattern; scope with boost:: 66 | std::for_each(v.cbegin(), v.cend(), boost::bind(boost::ref(acc), _1)); 67 | 68 | // Display the range (same as before): 69 | cout << '(' << extract::min(acc) << ", " << extract::max(acc) << ")\n"; 70 | cout << endl; 71 | } 72 | 73 | /* 74 | Copyright 2019 Daniel Hanson 75 | 76 | Licensed under the Apache License, Version 2.0 (the "License"); 77 | you may not use this file except in compliance with the License. 78 | You may obtain a copy of the License at 79 | 80 | http://www.apache.org/licenses/LICENSE-2.0 81 | 82 | Unless required by applicable law or agreed to in writing, software 83 | distributed under the License is distributed on an "AS IS" BASIS, 84 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 85 | See the License for the specific language governing permissions and 86 | limitations under the License. 87 | */ 88 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/CircularBuffers.cpp: -------------------------------------------------------------------------------- 1 | #include "../ExampleFunctionsHeader.h" 2 | #include "TimeSeries.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void simple_example() 9 | { 10 | std::cout << "***** circular_buffer: simple_example() *****" << std::endl; 11 | boost::circular_buffer cb(3); 12 | 13 | // Insert threee elements into the buffer. 14 | cb.push_back(1); 15 | cb.push_back(2); 16 | cb.push_back(3); 17 | 18 | int a = cb[0]; // a == 1 19 | int b = cb[1]; // b == 2 20 | int c = cb[2]; // c == 3 21 | 22 | std::cout << "Our buffer initially contains " << a << ", " << b << ", and " << c << std::endl; 23 | 24 | // The buffer is full now, so pushing subsequent 25 | // elements will overwrite the front-most elements. 26 | 27 | cb.push_back(4); // Overwrite 1 with 4. 28 | cb.push_back(5); // Overwrite 2 with 5. 29 | 30 | // The buffer now contains 3, 4 and 5. Note we can also use the at(.) function. 31 | a = cb.at(0); // a == 3 32 | b = cb.at(1); // b == 4 33 | c = cb.at(2); // c == 5 34 | 35 | std::cout << "After pushing back 4 and 5 into our buffer, we now have: " << a << ", " << b << ", and " << c << std::endl; 36 | 37 | // Elements can be popped from either the front or the back. 38 | cb.pop_back(); // 5 is removed. 39 | cb.pop_front(); // 3 is removed. 40 | 41 | // Leaving only one element with value = 4. 42 | int d = cb[0]; // d == 4 43 | 44 | std::cout << "After popping off the front and back elements, we are left with a buffer of size " << cb.size() 45 | << ", and lone element = " << d << std::endl << std::endl; 46 | } 47 | 48 | void time_series_example() 49 | { 50 | std::vector vts = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; 51 | TimeSeries ts(vts); 52 | double ma3 = ts.movingAverage(3); 53 | std::cout << "Value in 3rd element (idx = 2) is " << ts.value(2) << std::endl; 54 | std::cout << "Value in last element (idx = 10) is " << ts.value(10) << std::endl; 55 | double ma = ts.movingAverage(); 56 | std::cout << "moving average of last 3 elements = " << ma3 << std::endl; 57 | std::cout << "moving average of all elements = " << ma << std::endl; 58 | 59 | ts.append(25.0); 60 | std::cout << "1st element is now " << ts.value(0) << std::endl; 61 | std::cout << "last element is now " << ts.value(10) << std::endl; 62 | std::cout << "ma is now " << ts.movingAverage() << std::endl; 63 | } 64 | 65 | /* 66 | Copyright 2019 Daniel Hanson 67 | 68 | Licensed under the Apache License, Version 2.0 (the "License"); 69 | you may not use this file except in compliance with the License. 70 | You may obtain a copy of the License at 71 | 72 | http://www.apache.org/licenses/LICENSE-2.0 73 | 74 | Unless required by applicable law or agreed to in writing, software 75 | distributed under the License is distributed on an "AS IS" BASIS, 76 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 77 | See the License for the specific language governing permissions and 78 | limitations under the License. 79 | */ 80 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/EuroTree.cpp: -------------------------------------------------------------------------------- 1 | #include "EuroTree.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using std::exp; 7 | using std::sqrt; 8 | using std::max; 9 | using std::min; 10 | 11 | using std::tuple; 12 | using std::make_tuple; 13 | 14 | /*EuroTree::EuroTree(double mktPrice, double mktRate, double mktVol, double divRate, double strike, 15 | const Date& valueDate, const Date& expireDate, Porc porc, int numTimePoints, 16 | const DayCount& dayCount) 17 | 18 | { 19 | calcPrice_(); 20 | }*/ 21 | 22 | EuroTree::EuroTree(double mktPrice, double mktRate, double mktVol, double divRate, double strike, 23 | double expiry, Porc porc, int numTimePoints) :mktPrice_(mktPrice), mktRate_(mktRate), mktVol_(mktVol), 24 | divRate_(divRate), strike_(strike), expiry_(expiry), porc_(porc), 25 | numTimePoints_(numTimePoints) 26 | { 27 | calcPrice_(); 28 | } 29 | 30 | Node EuroTree::operator()(int i, int j) const 31 | { 32 | return grid_[i][j]; 33 | } 34 | 35 | /*boost::multi_array EuroTree::grid() const 36 | { 37 | return grid_; 38 | }*/ 39 | 40 | double EuroTree::optionPrice() const 41 | { 42 | return optionPrice_; 43 | } 44 | 45 | double EuroTree::calcDelta(double shift) 46 | { 47 | double origMktPrice = mktPrice_; 48 | double upPrice = mktPrice_ * (1 + shift / 2.0); 49 | double downPrice = mktPrice_ * (1 - shift / 2.0); 50 | 51 | mktPrice_ = upPrice; 52 | calcPrice_(); 53 | double upOptPrice = this->operator()(0, 0).payoff; 54 | 55 | mktPrice_ = downPrice; 56 | calcPrice_(); 57 | double downOptPrice = this->operator()(0, 0).payoff; 58 | 59 | mktPrice_ = origMktPrice; 60 | 61 | double delta = (upOptPrice - downOptPrice) / optionPrice_; 62 | return delta; 63 | } 64 | 65 | double EuroTree::resetMktPrice(double newMktPrice) 66 | { 67 | mktPrice_ = newMktPrice; 68 | calcPrice_(); 69 | return optionPrice_; 70 | } 71 | 72 | double EuroTree::resetMktRate(double newMktRate) 73 | { 74 | mktRate_ = newMktRate; 75 | calcPrice_(); 76 | return optionPrice_; 77 | } 78 | 79 | double EuroTree::resetMktVol(double newMktVol) 80 | { 81 | mktVol_ = newMktVol; 82 | calcPrice_(); 83 | return optionPrice_; 84 | } 85 | 86 | void EuroTree::calcPrice_() 87 | { 88 | gridSetup_(); 89 | paramInit_(); 90 | projectPrices_(); 91 | calcPayoffs_(); 92 | optionPrice_ = this->operator()(0, 0).payoff; 93 | } 94 | 95 | void EuroTree::gridSetup_() 96 | { 97 | grid_.resize(boost::extents[numTimePoints_][numTimePoints_]); 98 | } 99 | 100 | void EuroTree::paramInit_() 101 | { 102 | // double yfToExpiry = dayCount_(valueDate_, expireDate_); 103 | dt_ = expiry_ / static_cast(numTimePoints_ - 1); 104 | u_ = exp(mktVol_ * sqrt(dt_)); 105 | d_ = 1.0 / u_; 106 | p_ = 0.5*(1.0 + (mktRate_ - divRate_ - 0.5*mktVol_*mktVol_)*sqrt(dt_) / mktVol_); 107 | discFctr_ = exp(-mktRate_ * dt_); 108 | } 109 | 110 | void EuroTree::projectPrices_() 111 | { 112 | grid_[0][0].underlying = mktPrice_; 113 | 114 | for (auto j = 1; j < numTimePoints_; ++j) 115 | { 116 | for (auto i = 0; i <= j; ++i) 117 | { 118 | if (i < j) 119 | { 120 | grid_[i][j].underlying = d_ * grid_[i][j - 1].underlying; 121 | } 122 | else 123 | { 124 | grid_[i][j].underlying = u_ * grid_[i - 1][j - 1].underlying; 125 | } 126 | } 127 | } 128 | } 129 | 130 | void EuroTree::calcPayoffs_() 131 | { 132 | auto payoff = [this](double underlying) 133 | { 134 | if (porc_ == Porc::CALL) 135 | return max(underlying - strike_, 0.0); 136 | else 137 | return max(strike_ - underlying, 0.0); 138 | }; 139 | 140 | for (auto j = numTimePoints_ - 1; j >= 0; --j) 141 | { 142 | for (auto i = 0; i <= j; ++i) 143 | { 144 | if (j == numTimePoints_ - 1) 145 | { 146 | grid_[i][j].payoff = payoff(grid_[i][j].underlying); 147 | } 148 | else 149 | { 150 | grid_[i][j].payoff = discFctr_ * (p_*grid_[i + 1][j + 1].payoff + (1.0 - p_)*grid_[i][j + 1].payoff); 151 | } 152 | } 153 | } 154 | } 155 | 156 | /* 157 | Copyright 2019 Daniel Hanson 158 | 159 | Licensed under the Apache License, Version 2.0 (the "License"); 160 | you may not use this file except in compliance with the License. 161 | You may obtain a copy of the License at 162 | 163 | http://www.apache.org/licenses/LICENSE-2.0 164 | 165 | Unless required by applicable law or agreed to in writing, software 166 | distributed under the License is distributed on an "AS IS" BASIS, 167 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 168 | See the License for the specific language governing permissions and 169 | limitations under the License. 170 | */ 171 | 172 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/EuroTree.h: -------------------------------------------------------------------------------- 1 | #ifndef EURO_TREE_H 2 | #define EURO_TREE_H 3 | 4 | #include 5 | #include "Node.h" 6 | // #include "Date.h" 7 | // #include "DayCount.h" 8 | 9 | class EuroTree 10 | { 11 | public: 12 | // One should verify invariants: a) val date < exp date; mktPrice & mktVol > 0, 13 | // but not required for this exercise. 14 | /* EuroTree(double mktPrice, double mktRate, double mktVol, double divRate, double strike, 15 | const Date& valueDate, const Date& expireDate, Porc porc, int numTimePoints, 16 | const DayCount& dayCount = Act365()); // Use default day count of Act/365*/ 17 | 18 | EuroTree(double mktPrice, double mktRate, double mktVol, double divRate, double strike, 19 | double expiry, Porc porc, int numTimePoints); 20 | 21 | double calcDelta(double shift); // Save and restore mktPrice_ as part of this operation 22 | double resetMktPrice(double newMktPrice); // Reset underlying mkt price; recalculate option price and return 23 | double resetMktRate(double newMktRate); // Reset mkt risk free rate; recalculate option price and return 24 | double resetMktVol(double newMktVol); // Reset mkt volatility; recalculate option price and return 25 | 26 | 27 | // Accessors: 28 | double optionPrice() const; 29 | Node operator()(int i, int j) const; 30 | 31 | private: 32 | // Mkt Data: 33 | double mktPrice_, mktRate_, mktVol_; // Market prices for underlying security, risk-free rate, and volatility 34 | 35 | // Product/Contract Data: 36 | double divRate_, strike_; 37 | double expiry_; // Time to expiration as a year fraction 38 | Porc porc_; // Put or Call enum class 39 | 40 | // Model Settings: 41 | int numTimePoints_; 42 | // const DayCount& dayCount_; // Stored as reference to handle polymorphic object 43 | 44 | // Calculated member variables: 45 | boost::multi_array grid_; 46 | double dt_, u_, d_, p_; // delta t, u, d, and p parameters, a la James book 47 | double discFctr_; // Discount factor (fixed for each time step, a la James) 48 | double optionPrice_; // Store result as member 49 | 50 | // 5th double value will be time value (replaces two dates) 51 | std::tuple data_; 52 | 53 | // Helper functions: 54 | void calcPrice_(); // This function refactors the next five into one call 55 | void gridSetup_(); 56 | void paramInit_(); // Determine delta t, u, d, and p, a la James book 57 | void projectPrices_(); 58 | void calcPayoffs_(); 59 | }; 60 | 61 | #endif // !EURO_TREE_H 62 | 63 | /* 64 | Copyright 2019 Daniel Hanson 65 | 66 | Licensed under the Apache License, Version 2.0 (the "License"); 67 | you may not use this file except in compliance with the License. 68 | You may obtain a copy of the License at 69 | 70 | http://www.apache.org/licenses/LICENSE-2.0 71 | 72 | Unless required by applicable law or agreed to in writing, software 73 | distributed under the License is distributed on an "AS IS" BASIS, 74 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 75 | See the License for the specific language governing permissions and 76 | limitations under the License. 77 | */ 78 | 79 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/IntegrationAndDifferentiation.cpp: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2018, Daniel Hanson 2 | // See license details at bottom of file 3 | 4 | #include "../ExampleFunctionsHeader.h" 5 | #include "RealFunction.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using boost::math::quadrature::trapezoidal; 18 | using boost::math::differentiation::finite_difference_derivative; 19 | using boost::math::double_constants::pi; 20 | using boost::math::double_constants::two_pi; 21 | 22 | using std::vector; 23 | using std::pair; 24 | using std::make_pair; 25 | using std::future; 26 | using std::exp; 27 | using std::cout; 28 | using std::endl; 29 | using std::unique_ptr; 30 | using std::make_unique; 31 | 32 | 33 | void finiteDifferences() 34 | { 35 | cout << "*** finiteDifferences() ***" << endl; 36 | // Using a lambda: 37 | auto f = [](double x) {return exp(x); }; 38 | 39 | double x = 1.7; 40 | double dfdx = finite_difference_derivative(f, x); 41 | 42 | cout << "(Using a lambda): d/dx exp(" << x << ") = " << dfdx << endl; 43 | 44 | // Using a function object: 45 | 46 | BoostQuadratic q(0.5, 1.0, 1.0); 47 | x = 1.0; 48 | double dquad = finite_difference_derivative(q, x); 49 | cout << "(Using a function object): d/dx (Boost)Quadratic(" << x << ") = " << dquad << endl << endl; 50 | 51 | } 52 | 53 | void trapezoidal() 54 | { 55 | cout << "*** trapezoidal() ***" << endl; 56 | auto f = [](double x) 57 | { 58 | return 4.0 / (1.0 + x * x); 59 | }; 60 | 61 | double appPi = trapezoidal(f, 0.0, 1.0); 62 | 63 | double tol = 1e-6; 64 | int max_refinements = 20; 65 | double appPi2 = trapezoidal(f, 0.0, 1.0, tol, max_refinements); 66 | 67 | cout << "Trapezoid Rule results for computing pi by integration" << endl; 68 | cout << "a) with defaults, and b) with tol and max_refine set : " << endl; 69 | cout << appPi << ", " << appPi2 << endl << endl; 70 | 71 | BoostCubic cubic(-1.0, 1.0, -1.0, 1.0); 72 | double cubeInt = trapezoidal(cubic, 0.0, 2.0, tol, max_refinements); 73 | cout << "Trapezoid Rule results for computing integral of cubic polynomial:" << endl; 74 | cout << cubeInt << endl << endl; 75 | 76 | SineFunction sf(1.0, 1.0, 0.0); 77 | cout << "Trapezoid Rule results for computing integral of simple" << endl; 78 | cout << "sine function on 0 to 2pi (note the use of the Boost two_pi constant):" << endl; 79 | double sineInt = trapezoidal(sf, 0.0, two_pi, tol, max_refinements); 80 | cout << sineInt << endl << endl; 81 | 82 | auto psf = make_unique(1.0, 1.0, 0.0); 83 | cout << "Trapezoid Rule results for computing integral of simple" << endl; 84 | cout << "sine function on 0 to 2pi, with unique_ptr to the function:" << endl; 85 | double pSineInt = trapezoidal(*psf, 0.0, two_pi); 86 | cout << pSineInt << endl << endl; 87 | 88 | // NOTE: Added the section from here to end of the function 89 | // AFTER original sample code was released to the class, CFRM 524 Summer 2018. 90 | vector > vfcns; 91 | vfcns.push_back(make_unique(1.0, 1.0, 0.0)); 92 | vfcns.push_back(make_unique(-1.0, 1.0, -1.0, 1.0)); 93 | 94 | // double w = trapezoidal((*vfcns.at(0)), 0.0, two_pi); // Not supported (trapezoidal is compile-time only) 95 | 96 | // Need to trick it with a lambda: 97 | cout << "Trapezoid Rule results for computing integral of simple" << endl; 98 | cout << "sine function on 0 to 2pi, as polymorphic function object:" << endl; 99 | auto g = [&vfcns](double x) 100 | { 101 | return (*vfcns.at(0))(x); 102 | }; 103 | 104 | double vecUnqPtrFcn = trapezoidal(g, 0.0, two_pi); 105 | cout << vecUnqPtrFcn << endl << endl; 106 | } 107 | 108 | 109 | 110 | /* 111 | Copyright 2019 Daniel Hanson 112 | 113 | Licensed under the Apache License, Version 2.0 (the "License"); 114 | you may not use this file except in compliance with the License. 115 | You may obtain a copy of the License at 116 | 117 | http://www.apache.org/licenses/LICENSE-2.0 118 | 119 | Unless required by applicable law or agreed to in writing, software 120 | distributed under the License is distributed on an "AS IS" BASIS, 121 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 122 | See the License for the specific language governing permissions and 123 | limitations under the License. 124 | */ 125 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/MultiArray.cpp: -------------------------------------------------------------------------------- 1 | #include "../ExampleFunctionsHeader.h" 2 | #include "TestClassForMultiArray.h" 3 | #include "EuroTree.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | void TestLattice() 10 | { 11 | std::cout << std::endl << "***** multi_array: TestLattice() *****" << std::endl; 12 | // boost::extents in 2D represent number of rows and columns 13 | // in the generic matrix; ie, extents[numRows][numCols]. 14 | boost::multi_array mtx(boost::extents[4][6]); 15 | 16 | // 1st quick test: compiles and runs OK 17 | mtx[0][0].calc(3.0, 4.0); 18 | 19 | // Populate the old fashioned way with a loop. 20 | // Use the mutator calc(double, double) to 21 | // set each element. Note: the shape() method 22 | // on boost::multi_array gives us access to the 23 | // bounds on each dimension (rows and columns 24 | // (in the 2D matrix case). 25 | for (auto i = 0; i < mtx.shape()[0]; ++i) 26 | { 27 | for (auto j = 0; j < mtx.shape()[1]; ++j) 28 | { 29 | mtx[i][j].calc(static_cast(i), static_cast(j)); 30 | } 31 | } 32 | 33 | // Verify element type (TestClass): 34 | std::cout << mtx[1][1]() << " " << typeid(mtx[1][1]).name() << std::endl << std::endl; 35 | 36 | // Use to print each element: 37 | auto print = [](const TestClassForMultiArray& tc) 38 | { 39 | // Function object returns real value stored on object: 40 | std::cout << tc() << " "; 41 | }; 42 | 43 | // Display all elements, in one row, buy using std::for_each(.): 44 | std::for_each(mtx.data(), mtx.data() + mtx.num_elements(), print); 45 | 46 | std::cout << std::endl << std::endl; 47 | } 48 | 49 | void eurology() 50 | { 51 | std::cout << std::endl << "***** multi_array: eurology() (Lattice option pricer) *****" << std::endl; 52 | EuroTree myTree(100.0, 0.10, 0.2, 0.04, 100.0, 53 | 0.5, Porc::CALL, 4); 54 | 55 | 56 | std::cout << std::endl << std::endl; 57 | 58 | std::cout << "Display terminal underlying and payoff prices:" << std::endl; 59 | for (int i = 3; i >= 0; --i) 60 | { 61 | std::cout << i << ": " << myTree(i, 3).underlying << ", " << myTree(i, 3).payoff << std::endl; 62 | } 63 | 64 | } 65 | 66 | /* 67 | Copyright 2019 Daniel Hanson 68 | 69 | Licensed under the Apache License, Version 2.0 (the "License"); 70 | you may not use this file except in compliance with the License. 71 | You may obtain a copy of the License at 72 | 73 | http://www.apache.org/licenses/LICENSE-2.0 74 | 75 | Unless required by applicable law or agreed to in writing, software 76 | distributed under the License is distributed on an "AS IS" BASIS, 77 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 78 | See the License for the specific language governing permissions and 79 | limitations under the License. 80 | */ 81 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/Node.h: -------------------------------------------------------------------------------- 1 | #ifndef NODE_H 2 | #define NODE_H 3 | 4 | struct Node 5 | { 6 | double underlying; 7 | double payoff; 8 | }; 9 | 10 | enum class Porc 11 | { 12 | CALL, PUT 13 | }; 14 | 15 | #endif // !NODE_H 16 | 17 | /* 18 | Copyright 2019 Daniel Hanson 19 | 20 | Licensed under the Apache License, Version 2.0 (the "License"); 21 | you may not use this file except in compliance with the License. 22 | You may obtain a copy of the License at 23 | 24 | http://www.apache.org/licenses/LICENSE-2.0 25 | 26 | Unless required by applicable law or agreed to in writing, software 27 | distributed under the License is distributed on an "AS IS" BASIS, 28 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 29 | See the License for the specific language governing permissions and 30 | limitations under the License. 31 | */ 32 | 33 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/RealFunction.h: -------------------------------------------------------------------------------- 1 | #ifndef REAL_FUNCTION_H 2 | #define REAL_FUNCTION_H 3 | 4 | #include 5 | 6 | class RealFunction 7 | { 8 | public: 9 | virtual double operator()(double x) const = 0; 10 | virtual double fcnValue(double x) const = 0; 11 | virtual ~RealFunction() = default; 12 | }; 13 | 14 | // Classes BoostQuadratic and BoostCubic are used for the Boost 15 | // numerical differentiation and trapezoid method integration 16 | // examples. There are also quadratic and cubic function examples 17 | // in RootFindingExamples.cpp, but these are different. At a 18 | // later date, these will be consolidated. 19 | class BoostQuadratic :public RealFunction 20 | { 21 | public: 22 | // ax^2 + bx + c 23 | BoostQuadratic(double a, double b, double c) : 24 | a_(a), b_(b), c_(c) {} 25 | 26 | virtual double operator()(double x) const override 27 | { 28 | return a_ * x*x + b_ * x + c_; 29 | } 30 | 31 | virtual double fcnValue(double x) const override 32 | { 33 | return x * (a_*x + b_) + c_; 34 | } 35 | 36 | private: 37 | double a_ = 1.0, b_ = 1.0, c_ = 1.0; 38 | 39 | }; 40 | 41 | class BoostCubic :public RealFunction 42 | { 43 | public: 44 | // ax^3 + bx2 + cx + d 45 | BoostCubic(double a, double b, double c, double d) : 46 | a_(a), b_(b), c_(c), d_(d) {} 47 | 48 | virtual double operator()(double x) const override 49 | { 50 | return x*x*(a_*x + b_) + c_*x + d_; 51 | } 52 | 53 | virtual double fcnValue(double x) const override 54 | { 55 | return x*x*(a_*x + b_) + c_*x + d_; 56 | } 57 | 58 | private: 59 | double a_, b_, c_, d_; 60 | }; 61 | 62 | class SineFunction :public RealFunction 63 | { 64 | public: 65 | SineFunction() :a_(1.0), b_(1.0), c_(0.0) {} 66 | SineFunction(double a, double b, double c) : 67 | a_(a), b_(b), c_(c) {} 68 | 69 | virtual double operator()(double x) const override 70 | { 71 | return fcnValue(x); 72 | } 73 | 74 | virtual double fcnValue(double x) const override 75 | { 76 | return a_ * std::sin(b_*x + c_); 77 | } 78 | 79 | private: 80 | double a_ = 1.0, b_ = 1.0, c_ = 1.0; 81 | 82 | }; 83 | 84 | 85 | #endif // !REAL_FUNCTION_H 86 | 87 | /* 88 | Copyright 2019 Daniel Hanson 89 | 90 | Licensed under the Apache License, Version 2.0 (the "License"); 91 | you may not use this file except in compliance with the License. 92 | You may obtain a copy of the License at 93 | 94 | http://www.apache.org/licenses/LICENSE-2.0 95 | 96 | Unless required by applicable law or agreed to in writing, software 97 | distributed under the License is distributed on an "AS IS" BASIS, 98 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 99 | See the License for the specific language governing permissions and 100 | limitations under the License. 101 | */ 102 | 103 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/TestClassForMultiArray.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_CLASS_H 2 | #define TEST_CLASS_H 3 | 4 | class TestClassForMultiArray 5 | { 6 | public: 7 | void calc(double x, double y) 8 | { 9 | result_ = x * y; 10 | } 11 | 12 | double operator()() const 13 | { 14 | return result_; 15 | } 16 | 17 | private: 18 | double result_; 19 | }; 20 | 21 | 22 | #endif // !TEST_CLASS_H 23 | 24 | /* 25 | Copyright 2019 Daniel Hanson 26 | 27 | Licensed under the Apache License, Version 2.0 (the "License"); 28 | you may not use this file except in compliance with the License. 29 | You may obtain a copy of the License at 30 | 31 | http://www.apache.org/licenses/LICENSE-2.0 32 | 33 | Unless required by applicable law or agreed to in writing, software 34 | distributed under the License is distributed on an "AS IS" BASIS, 35 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 36 | See the License for the specific language governing permissions and 37 | limitations under the License. 38 | */ 39 | 40 | 41 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/TimeSeries.cpp: -------------------------------------------------------------------------------- 1 | #include "TimeSeries.h" 2 | #include // Need this for std::accumulate, rather than 3 | #include // For copy(.) 4 | 5 | using boost::circular_buffer; 6 | 7 | TimeSeries::TimeSeries(Unsigned length) :ts_(circular_buffer(length)){} 8 | TimeSeries::TimeSeries(const boost::circular_buffer& ts) :ts_(ts){} 9 | TimeSeries::TimeSeries(const std::vector& ts) 10 | { 11 | ts_.set_capacity(ts.size()); 12 | std::copy(ts.begin(), ts.end(), back_inserter(ts_)); 13 | } 14 | 15 | void TimeSeries::append(double x) 16 | { 17 | ts_.push_back(x); 18 | } 19 | 20 | double TimeSeries::value(Unsigned k) const 21 | { 22 | return ts_.at(k); 23 | } 24 | 25 | double TimeSeries::movingAverage(Unsigned t) const 26 | { 27 | Unsigned offset = 0; 28 | double ma = 0.0; 29 | if (t > ts_.size()) // if set beyond number of elements, 30 | { // just compute MA of the entire set. 31 | t = ts_.size() - 1; 32 | } 33 | else if ((t > 0)&&(t <= ts_.size())) 34 | { 35 | offset = ts_.size() - t; 36 | } 37 | else // The case t <= 0 should be handled with an exception. 38 | { // when the public movingAverage(.) method is called. 39 | offset = 0; 40 | t = ts_.size(); 41 | } 42 | double den = static_cast(t); 43 | return std::accumulate(ts_.begin() + offset, ts_.end(), 0.0) / den; 44 | } 45 | 46 | double TimeSeries::volatility(Unsigned t) const 47 | { 48 | double vol = 0.0; // Implementation is an exercise 49 | 50 | return vol; 51 | } 52 | 53 | boost::circular_buffer TimeSeries::buffer() const 54 | { 55 | return ts_; 56 | } 57 | 58 | double TimeSeries::mean_(Unsigned t) const 59 | { 60 | Unsigned offset = 0; 61 | if (t > 0) 62 | { 63 | offset = ts_.size() - t; 64 | } 65 | else // The case t <= 0 should be handled with an exception. 66 | { // when the public movingAverage(.) method is called. 67 | offset = 0; 68 | t = ts_.size(); 69 | } 70 | double den = static_cast(t); 71 | return std::accumulate(ts_.begin() + offset, ts_.end(), 0.0) / den; 72 | } 73 | 74 | /* 75 | Copyright 2019 Daniel Hanson 76 | 77 | Licensed under the Apache License, Version 2.0 (the "License"); 78 | you may not use this file except in compliance with the License. 79 | You may obtain a copy of the License at 80 | 81 | http://www.apache.org/licenses/LICENSE-2.0 82 | 83 | Unless required by applicable law or agreed to in writing, software 84 | distributed under the License is distributed on an "AS IS" BASIS, 85 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 86 | See the License for the specific language governing permissions and 87 | limitations under the License. 88 | */ 89 | -------------------------------------------------------------------------------- /SourceCode/BoostExamples/TimeSeries.h: -------------------------------------------------------------------------------- 1 | #ifndef TIME_SERIES_H 2 | #define TIME_SERIES_H 3 | 4 | #include 5 | #include 6 | using Unsigned = size_t; 7 | 8 | class TimeSeries 9 | { 10 | public: 11 | TimeSeries(Unsigned length); 12 | TimeSeries(const boost::circular_buffer& ts); 13 | TimeSeries(const std::vector& ts); 14 | void append(double x); 15 | double value(Unsigned k) const; 16 | double movingAverage(Unsigned t = 0) const; 17 | double volatility(Unsigned t = 0) const; // Exercise 18 | boost::circular_buffer buffer() const; 19 | 20 | private: 21 | boost::circular_buffer ts_; 22 | double mean_(Unsigned t = 0) const; 23 | }; 24 | 25 | #endif 26 | 27 | /* 28 | Copyright 2019 Daniel Hanson 29 | 30 | Licensed under the Apache License, Version 2.0 (the "License"); 31 | you may not use this file except in compliance with the License. 32 | You may obtain a copy of the License at 33 | 34 | http://www.apache.org/licenses/LICENSE-2.0 35 | 36 | Unless required by applicable law or agreed to in writing, software 37 | distributed under the License is distributed on an "AS IS" BASIS, 38 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 39 | See the License for the specific language governing permissions and 40 | limitations under the License. 41 | */ 42 | -------------------------------------------------------------------------------- /SourceCode/CppCon2019.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 15.0 47 | {55C7E00E-66C6-4422-A9B0-90D01FADE649} 48 | Win32Proj 49 | CppCon2019 50 | 10.0.17763.0 51 | 52 | 53 | 54 | Application 55 | true 56 | v141 57 | Unicode 58 | 59 | 60 | Application 61 | false 62 | v141 63 | true 64 | Unicode 65 | 66 | 67 | Application 68 | true 69 | v141 70 | Unicode 71 | 72 | 73 | Application 74 | false 75 | v141 76 | true 77 | Unicode 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | true 99 | 100 | 101 | true 102 | C:\local\boost_1_70_0;$(IncludePath) 103 | 104 | 105 | false 106 | 107 | 108 | false 109 | C:\local\boost_1_70_0;$(IncludePath) 110 | 111 | 112 | 113 | Level3 114 | Disabled 115 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 116 | true 117 | 118 | 119 | true 120 | Console 121 | 122 | 123 | 124 | 125 | Level3 126 | Disabled 127 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 128 | true 129 | stdcpp17 130 | 131 | 132 | true 133 | Console 134 | 135 | 136 | 137 | 138 | Level3 139 | MaxSpeed 140 | true 141 | true 142 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | true 144 | 145 | 146 | true 147 | true 148 | true 149 | Console 150 | 151 | 152 | 153 | 154 | Level3 155 | MaxSpeed 156 | true 157 | true 158 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 159 | true 160 | stdcpp17 161 | 162 | 163 | true 164 | true 165 | true 166 | Console 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /SourceCode/ExampleFunctionsHeader.h: -------------------------------------------------------------------------------- 1 | #ifndef EXAMPLE_FUNCTIONS_HEADER_H 2 | #define EXAMPLE_FUNCTIONS_HEADER_H 3 | 4 | // --- Root finding examples --- 5 | void bisectionExamples(); 6 | void steffensonExamples(); 7 | 8 | 9 | class Quadratic 10 | { 11 | public: 12 | double operator()(double x) const; 13 | }; 14 | 15 | class SineFcn 16 | { 17 | public: 18 | double operator()(double x) const; 19 | }; 20 | 21 | 22 | // --- Boost examples --- 23 | // Differentiation 24 | void finiteDifferences(); 25 | 26 | // Integration 27 | void trapezoidal(); 28 | 29 | // Circular Buffers 30 | void simple_example(); 31 | void time_series_example(); 32 | 33 | // Accumulators 34 | void minMaxAccumulator(); 35 | void meanAndVarAccumulator(); 36 | void vectorAndAccumulator(); 37 | 38 | // MultiArray 39 | void TestLattice(); 40 | void eurology(); // Binary lattice option pricing 41 | 42 | 43 | #endif 44 | 45 | /* 46 | Copyright 2019 Daniel Hanson 47 | 48 | Licensed under the Apache License, Version 2.0 (the "License"); 49 | you may not use this file except in compliance with the License. 50 | You may obtain a copy of the License at 51 | 52 | http://www.apache.org/licenses/LICENSE-2.0 53 | 54 | Unless required by applicable law or agreed to in writing, software 55 | distributed under the License is distributed on an "AS IS" BASIS, 56 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 57 | See the License for the specific language governing permissions and 58 | limitations under the License. 59 | */ 60 | 61 | -------------------------------------------------------------------------------- /SourceCode/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "MonteCarloOptions/EquityPriceGenerator.h" 2 | #include "MonteCarloOptions/MCEuroOptPricer.h" 3 | #include "ExampleFunctionsHeader.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using std::vector; 13 | using std::cout; 14 | using std::endl; 15 | using std::for_each; 16 | using std::transform; 17 | using std::generate; 18 | using std::generate_n; 19 | using std::fill; 20 | using std::fill_n; 21 | using std::mt19937_64; 22 | using std::normal_distribution; 23 | 24 | void stdNormalGenerationTest(int n, int seed); 25 | void generalNormalGenerationTest(int n, int seed, double mean, double stdDev); 26 | 27 | void equityScenarioTest(double initEquityPrice, unsigned numTimeSteps, double timeToMaturity, 28 | double riskFreeRate, double volatility, int seed); 29 | void mcOptionTestNotParallel(double tau, int numTimeSteps, int numScenarios, int initSeed = 100); 30 | void mcOptionTestRunParallel(double tau, int numTimeSteps, int numScenarios, int initSeed = 100); 31 | 32 | void transformPar(size_t n, int terms, int seed); 33 | void printDouble(double x); 34 | 35 | int main() 36 | { 37 | stdNormalGenerationTest(10, 100); 38 | generalNormalGenerationTest(10, 106, 8.74, 5.863); 39 | 40 | double initEquityPrice = 100.0; 41 | unsigned numTimeSteps = 12; // 5 years, quarterly time steps 42 | double timeToMaturity = 1.0; 43 | 44 | double drift = 0.025; // risk-free interest rate 45 | double volatility = 0.06; 46 | int seed = -106; 47 | equityScenarioTest(initEquityPrice, numTimeSteps, timeToMaturity, drift, volatility, seed); 48 | 49 | mcOptionTestNotParallel(1.0, 12, 10000); 50 | mcOptionTestRunParallel(1.0, 12, 10000); 51 | 52 | /*mcOptionTestNotParallel(1.0, 120, 50000); 53 | mcOptionTestRunParallel(1.0, 120, 50000); 54 | 55 | mcOptionTestNotParallel(5.0, 120, 50000); 56 | mcOptionTestRunParallel(5.0, 120, 50000); 57 | 58 | mcOptionTestNotParallel(5.0, 600, 50000); 59 | mcOptionTestRunParallel(5.0, 600, 50000); 60 | 61 | mcOptionTestNotParallel(5.0, 600, 100000); 62 | mcOptionTestRunParallel(5.0, 600, 100000); 63 | 64 | mcOptionTestNotParallel(10.0, 600, 100000); 65 | mcOptionTestRunParallel(10.0, 600, 100000); 66 | 67 | mcOptionTestNotParallel(10.0, 1200, 100000); 68 | mcOptionTestRunParallel(10.0, 1200, 100000);*/ 69 | 70 | // Parallel STL Algorithms: 71 | transformPar(5000000, 400, 106); // num variates, num series terms, seed 72 | transformPar(5000000, 400, -106); 73 | 74 | // Warning: These can take a long time on a basic laptop... 75 | /* transformPar(50000000, 200, 5863); 76 | transformPar(50000000, 200, -5863); 77 | 78 | transformPar(100000000, 200, 874); 79 | transformPar(100000000, 200, -874);*/ 80 | 81 | // Call root finding examples: 82 | bisectionExamples(); 83 | steffensonExamples(); 84 | 85 | // Call Boost examples: 86 | // Numerical differentiation: 87 | finiteDifferences(); 88 | 89 | // Numerical integration: 90 | trapezoidal(); 91 | 92 | // Circular Buffers 93 | simple_example(); 94 | time_series_example(); 95 | 96 | // Accumulators 97 | minMaxAccumulator(); 98 | meanAndVarAccumulator(); 99 | vectorAndAccumulator(); 100 | 101 | // MultiArray example: 102 | TestLattice(); 103 | eurology(); 104 | 105 | return 0; 106 | } 107 | 108 | void stdNormalGenerationTest(int n, int seed) 109 | { 110 | cout << endl << "----- stdNormalGenerationTest(.), n = " << n << "; seed = " << seed << " -----" << endl; 111 | mt19937_64 mtre(seed); // mtre = mersenne twister random engine 112 | normal_distribution<> stnd; // stnd = standard normal distribution 113 | vector stdNorms(n); 114 | 115 | generate_n(stdNorms.begin(), stdNorms.size(), [&mtre, &stnd]() {return stnd(mtre);}); 116 | for_each(stdNorms.cbegin(), stdNorms.cend(), printDouble); 117 | cout << endl << endl; 118 | 119 | } 120 | 121 | void generalNormalGenerationTest(int n, int seed, double mean, double stdDev) 122 | { 123 | cout << endl << "----- generalNormalGenerationTest(.), n = " << n << "; seed = " << seed 124 | << "; mean = " << mean << "; std dev = " << stdDev << "-----" << endl; 125 | 126 | mt19937_64 mtre(seed); 127 | // Specify mean and std dev for general case: 128 | normal_distribution<> nd(mean, stdDev); // nd = normal distribution 129 | vector norms(n); 130 | 131 | generate_n(norms.begin(), n, [&mtre, &nd]() {return nd(mtre); }); 132 | for_each(norms.cbegin(), norms.cend(), printDouble); 133 | cout << endl << endl; 134 | 135 | } 136 | 137 | void equityScenarioTest(double initEquityPrice, unsigned numTimeSteps, double timeToMaturity, double riskFreeRate, double volatility, int seed) 138 | { 139 | cout << endl << "----- equityScenarioTest(.), seed = " << seed << " -----" << endl; 140 | 141 | 142 | // EquityPriceGenerator(double initEquityPrice, unsigned numTimeSteps, double timeToMaturity, double drift, double volatility); 143 | EquityPriceGenerator epg(initEquityPrice, numTimeSteps, timeToMaturity, riskFreeRate, volatility); 144 | vector synPrices = epg(seed); 145 | 146 | for_each(synPrices.begin(), synPrices.end(), printDouble); 147 | cout << endl << endl; 148 | } 149 | 150 | void mcOptionTestNotParallel(double tau, int numTimeSteps, int numScenarios, int initSeed) 151 | { 152 | cout << endl << "--- mcOptionTestNotParallel(tau = " << tau 153 | << ", numTimeSteps = " << numTimeSteps 154 | << ", numScenarios = " << numScenarios << ") ---" << endl; 155 | double strike = 102.0; 156 | double spot = 100.0; 157 | double riskFreeRate = 0.025; 158 | double volatility = 0.06; 159 | double quantity = 7000.00; // 1.0; 160 | 161 | /* 162 | // Constructor signature: 163 | MCEuroOptPricer(double strike, double spot, double riskFreeRate, double volatility, 164 | double tau, OptionType optionType, int numTimeSteps, int numScenarios, 165 | bool runParallel, int initSeed, double quantity); 166 | */ 167 | 168 | MCEuroOptPricer qlCall(strike, spot, riskFreeRate, volatility, tau, 169 | OptionType::CALL, numTimeSteps, numScenarios, false, initSeed, quantity); 170 | double res = qlCall(); 171 | cout << "Number of time steps = " << numTimeSteps << "; number of scenarios = " << numScenarios << endl; 172 | cout << "Runtime (NOT in parallel) = " << qlCall.time() << "; price = " << res << endl << endl; 173 | } 174 | 175 | void mcOptionTestRunParallel(double tau, int numTimeSteps, int numScenarios, int initSeed) 176 | { 177 | cout << endl << "--- mcOptionTestRunParallel(.) ---" << endl; 178 | double strike = 102.0; 179 | double spot = 100.0; 180 | double riskFreeRate = 0.025; 181 | double volatility = 0.06; 182 | double quantity = 7000.00; // 1.0; (Number of contracts) 183 | OptionType call = OptionType::CALL; 184 | 185 | MCEuroOptPricer qlCall(strike, spot, riskFreeRate, volatility, tau, 186 | call, numTimeSteps, numScenarios, true, initSeed, quantity); 187 | 188 | double res = qlCall(); 189 | cout << "Number of time steps = " << numTimeSteps << "; number of scenarios = " << numScenarios << endl; 190 | cout << "Runtime (IS RUN in parallel) = " << qlCall.time() << "; price = " << res << endl << endl; 191 | } 192 | 193 | // For testing parallel STL algorithm transform(.): 194 | void transformPar(size_t n, int terms, int seed) 195 | { 196 | cout << endl << "--- transformPar(.) ---" << endl; 197 | std::mt19937_64 mtre(seed); 198 | std::normal_distribution<> nd; 199 | vector v(n); 200 | 201 | auto nextNorm = [&mtre, &nd](double x) 202 | { 203 | return nd(mtre); 204 | }; 205 | 206 | std::transform(v.begin(), v.end(), v.begin(), nextNorm); 207 | auto u = v; 208 | 209 | cout << endl; 210 | 211 | auto expSeries = [terms](double x) { 212 | double num = x; 213 | double den = 1.0; 214 | double res = 1.0 + x; 215 | for (int k = 2; k < terms; ++k) 216 | { 217 | num *= x; 218 | den *= static_cast(k); 219 | res += num / den; 220 | } 221 | return res; 222 | }; 223 | 224 | cout << "Sanity check: " << endl; 225 | cout << "exp(0) = " << expSeries(0.0) << " - should = 1.0" << endl; 226 | cout << "exp(1) = " << expSeries(1.0) << " - should = 2.71828" << endl << endl; 227 | cout << "Number of elements = " << n << "; number of terms = " << terms << endl << endl; 228 | 229 | // Use std::transform to run exponential power series on each element in v: 230 | clock_t begin = clock(); // begin time with threads 231 | std::transform(u.begin(), u.end(), u.begin(), expSeries); 232 | clock_t end = clock(); // end transform time with no par 233 | auto time = (end - begin) / CLOCKS_PER_SEC; 234 | 235 | auto mean = (1.0 / u.size())*std::reduce(u.cbegin(), u.cend(), 0.0); 236 | 237 | cout << "Time required for serialized calculations = " 238 | << time << " seconds." << endl; 239 | cout << "Mean exponential value = " << mean << endl << endl; 240 | 241 | 242 | // Use std::transform with std::par execution policy 243 | // to run exponential power series on each element in v: 244 | begin = clock(); // begin time with threads 245 | std::transform(std::execution::par, v.begin(), v.end(), v.begin(), expSeries); 246 | end = clock(); // end transform time with par 247 | time = (end - begin) / CLOCKS_PER_SEC; 248 | 249 | auto meanPar = (1.0 / v.size())*std::reduce(v.cbegin(), v.cend(), 0.0); 250 | 251 | cout << "Time required for parallel algorithm calculations = " 252 | << time << " seconds." << endl; 253 | cout << "Mean exponential value (par) = " << meanPar << endl << endl; 254 | } 255 | 256 | // Auxiliary print function for std::for_each(.) 257 | void printDouble(double x) 258 | { 259 | cout << x << " "; 260 | } 261 | /* 262 | Copyright 2019 Daniel Hanson 263 | 264 | Licensed under the Apache License, Version 2.0 (the "License"); 265 | you may not use this file except in compliance with the License. 266 | You may obtain a copy of the License at 267 | 268 | http://www.apache.org/licenses/LICENSE-2.0 269 | 270 | Unless required by applicable law or agreed to in writing, software 271 | distributed under the License is distributed on an "AS IS" BASIS, 272 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 273 | See the License for the specific language governing permissions and 274 | limitations under the License. 275 | */ 276 | -------------------------------------------------------------------------------- /SourceCode/MonteCarloOptions/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /SourceCode/MonteCarloOptions/EquityPriceGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "EquityPriceGenerator.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using std::vector; 8 | using std::mt19937_64; 9 | using std::normal_distribution; 10 | 11 | using std::exp; 12 | 13 | using std::vector; 14 | 15 | EquityPriceGenerator::EquityPriceGenerator(double initEquityPrice, unsigned numTimeSteps, double timeToExpiry, double drift, double volatility) : 16 | initEquityPrice_(initEquityPrice), numTimeSteps_(numTimeSteps), drift_(drift), volatility_(volatility), 17 | dt_(timeToExpiry/numTimeSteps) {} 18 | 19 | vector EquityPriceGenerator::operator()(int seed) const 20 | { 21 | vector v; 22 | 23 | mt19937_64 mtEngine(seed); 24 | normal_distribution<> nd; 25 | 26 | auto newPrice = [this](double previousEquityPrice, double norm) 27 | { 28 | double price = 0.0; 29 | 30 | double expArg1 = (drift_ - ((volatility_ * volatility_) / 2.0)) * dt_; 31 | double expArg2 = volatility_ * norm * sqrt(dt_); 32 | price = previousEquityPrice * exp(expArg1 + expArg2); 33 | 34 | return price; 35 | }; 36 | 37 | v.push_back(initEquityPrice_); // put initial equity price into the 1st position in the vector 38 | double equityPrice = initEquityPrice_; 39 | 40 | for (int i = 1; i <= numTimeSteps_; ++i) // i <= numTimeSteps_ since we need a price at the end of the 41 | { // final time step. 42 | equityPrice = newPrice(equityPrice, nd(mtEngine)); // norm = nd(mtEngine) 43 | v.push_back(equityPrice); 44 | } 45 | 46 | return v; 47 | 48 | } 49 | 50 | /* 51 | Copyright 2019 Daniel Hanson 52 | 53 | Licensed under the Apache License, Version 2.0 (the "License"); 54 | you may not use this file except in compliance with the License. 55 | You may obtain a copy of the License at 56 | 57 | http://www.apache.org/licenses/LICENSE-2.0 58 | 59 | Unless required by applicable law or agreed to in writing, software 60 | distributed under the License is distributed on an "AS IS" BASIS, 61 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 62 | See the License for the specific language governing permissions and 63 | limitations under the License. 64 | */ 65 | -------------------------------------------------------------------------------- /SourceCode/MonteCarloOptions/EquityPriceGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef EQUITY_PRICE_GENERATOR_H 2 | #define EQUITY_PRICE_GENERATOR_H 3 | 4 | #include 5 | 6 | class EquityPriceGenerator 7 | { 8 | public: 9 | // A more robust approach would be to add in a stub period at beginning 10 | EquityPriceGenerator(double initEquityPrice, unsigned numTimeSteps, double timeToExpiry, double drift, double volatility); 11 | 12 | // We could also have another ctor that takes in a TermStructure object in place of a constant drift or risk free rate, 13 | // as well as a time path determined by a schedule based on dates and a daycount rule; viz, 14 | // EquityPriceGenerator(double initEquityPrice, const RealSchedule& realSchedule, const TermStructure& ts, double volatility); 15 | 16 | std::vector operator()(int seed) const; 17 | 18 | private: 19 | double dt_; 20 | const double initEquityPrice_; 21 | const int numTimeSteps_; 22 | const double drift_; 23 | const double volatility_; 24 | }; 25 | 26 | #endif 27 | 28 | /* 29 | Copyright 2019 Daniel Hanson 30 | 31 | Licensed under the Apache License, Version 2.0 (the "License"); 32 | you may not use this file except in compliance with the License. 33 | You may obtain a copy of the License at 34 | 35 | http://www.apache.org/licenses/LICENSE-2.0 36 | 37 | Unless required by applicable law or agreed to in writing, software 38 | distributed under the License is distributed on an "AS IS" BASIS, 39 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 40 | See the License for the specific language governing permissions and 41 | limitations under the License. 42 | */ 43 | -------------------------------------------------------------------------------- /SourceCode/MonteCarloOptions/MCEuroOptPricer.cpp: -------------------------------------------------------------------------------- 1 | #include "MCEuroOptPricer.h" 2 | #include "EquityPriceGenerator.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | MCEuroOptPricer::MCEuroOptPricer(double strike, double spot, double riskFreeRate, double volatility, 12 | double timeToExpiry, OptionType porc, int numTimeSteps, int numScenarios, 13 | bool runParallel, int initSeed, double quantity) :strike_(strike), spot_(spot), 14 | riskFreeRate_(riskFreeRate), volatility_(volatility), timeToExpiry_(timeToExpiry), porc_(porc), 15 | numTimeSteps_(numTimeSteps), numScenarios_(numScenarios), runParallel_(runParallel), 16 | initSeed_(initSeed), quantity_(quantity) 17 | { 18 | discFactor_ = std::exp(-riskFreeRate_ * timeToExpiry_); 19 | calculate_(); 20 | } 21 | 22 | double MCEuroOptPricer::operator()() const 23 | { 24 | return price_; 25 | } 26 | 27 | double MCEuroOptPricer::time() const 28 | { 29 | return time_; 30 | } 31 | 32 | void MCEuroOptPricer::calculate_() 33 | { 34 | std::clock_t begin = std::clock(); // begin time with threads 35 | computePrice_(); 36 | std::clock_t end = std::clock(); // end time with threads 37 | time_ = double(end - begin) / CLOCKS_PER_SEC; 38 | } 39 | 40 | // Private helper functions: 41 | void MCEuroOptPricer::computePrice_() 42 | { 43 | if (runParallel_) 44 | { 45 | computePriceAsync_(); 46 | } 47 | else 48 | { 49 | computePriceNoParallel_(); 50 | } 51 | } 52 | 53 | void MCEuroOptPricer::computePriceNoParallel_() 54 | { 55 | EquityPriceGenerator epg(spot_, numTimeSteps_, timeToExpiry_, riskFreeRate_, volatility_); 56 | generateSeeds_(); 57 | std::vector discountedPayoffs; 58 | discountedPayoffs.reserve(numScenarios_); 59 | 60 | for (auto& seed : seeds_) 61 | { 62 | double terminalPrice = (epg(seed)).back(); 63 | double payoff = payoff_(terminalPrice); 64 | 65 | discountedPayoffs.push_back(discFactor_ * payoff); 66 | } 67 | 68 | // numScenarios_ should = discountedPayoffs.size() 69 | double numScens = static_cast(numScenarios_); 70 | price_ = quantity_ * (1.0 / numScens) * 71 | std::accumulate(discountedPayoffs.begin(), discountedPayoffs.end(), 0.0); 72 | } 73 | 74 | void MCEuroOptPricer::computePriceAsync_() 75 | { 76 | EquityPriceGenerator epg(spot_, numTimeSteps_, timeToExpiry_, riskFreeRate_, volatility_); 77 | generateSeeds_(); 78 | 79 | using realVector = std::vector; 80 | std::vector > futures; 81 | futures.reserve(numScenarios_); 82 | 83 | for (auto& seed : seeds_) 84 | { 85 | futures.push_back(std::async(epg, seed)); 86 | } 87 | 88 | realVector discountedPayoffs; 89 | discountedPayoffs.reserve(numScenarios_); 90 | 91 | for (auto& future : futures) 92 | { 93 | double terminalPrice = future.get().back(); 94 | double payoff = payoff_(terminalPrice); 95 | discountedPayoffs.push_back(discFactor_ * payoff); 96 | } 97 | 98 | double numScens = static_cast(numScenarios_); 99 | price_ = quantity_ * (1.0 / numScens) * 100 | std::accumulate(discountedPayoffs.begin(), discountedPayoffs.end(), 0.0); 101 | } 102 | 103 | void MCEuroOptPricer::generateSeeds_() 104 | { 105 | seeds_.resize(numScenarios_); 106 | 107 | // This is a contrived way of setting a different seed for 108 | // each scenario. There are more robust ways to do this if desired. 109 | std::iota(seeds_.begin(), seeds_.end(), initSeed_); 110 | } 111 | 112 | double MCEuroOptPricer::payoff_(double terminalPrice) 113 | { 114 | double payoff = 0.0; 115 | switch (porc_) 116 | { 117 | case OptionType::CALL: 118 | payoff = std::max(terminalPrice - strike_, 0.0); 119 | break; 120 | case OptionType::PUT: 121 | payoff = std::max(strike_ - terminalPrice, 0.0); 122 | break; 123 | default: // This case should NEVER happen 124 | payoff = std::numeric_limits::quiet_NaN(); 125 | break; 126 | } 127 | return payoff; 128 | } 129 | 130 | /* 131 | Copyright 2019 Daniel Hanson 132 | 133 | Licensed under the Apache License, Version 2.0 (the "License"); 134 | you may not use this file except in compliance with the License. 135 | You may obtain a copy of the License at 136 | 137 | http://www.apache.org/licenses/LICENSE-2.0 138 | 139 | Unless required by applicable law or agreed to in writing, software 140 | distributed under the License is distributed on an "AS IS" BASIS, 141 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142 | See the License for the specific language governing permissions and 143 | limitations under the License. 144 | */ 145 | -------------------------------------------------------------------------------- /SourceCode/MonteCarloOptions/MCEuroOptPricer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Daniel Hanson 3 | University of Washington 4 | Dept of Applied Mathematics 5 | Computational Finance & Risk Management (CFRM) 6 | */ 7 | 8 | #ifndef MC_EURO_OPT_PRICER_H 9 | #define MC_EURO_OPT_PRICER_H 10 | 11 | #include "EquityPriceGenerator.h" 12 | enum class OptionType 13 | { 14 | CALL, 15 | PUT 16 | }; 17 | 18 | class MCEuroOptPricer 19 | { 20 | public: 21 | MCEuroOptPricer(double strike, double spot, double riskFreeRate, double volatility, 22 | double timeToExpiry, OptionType optionType, int numTimeSteps, int numScenarios, 23 | bool runParallel, int initSeed, double quantity); 24 | 25 | double operator()() const; 26 | double time() const; // Time required to run calcutions (for comparison using concurrency) 27 | 28 | private: 29 | void calculate_(); // Start calculation of option price 30 | 31 | // Private helper functions: 32 | void computePrice_(); 33 | void generateSeeds_(); 34 | double payoff_(double terminalPrice); 35 | 36 | // Compare results: non-parallel vs in-parallel with async and futures 37 | void computePriceNoParallel_(); 38 | void computePriceAsync_(); 39 | 40 | // Inputs to model: 41 | double strike_; 42 | double spot_; 43 | double riskFreeRate_; 44 | double volatility_; 45 | double timeToExpiry_; // Time to expiration (as year fraction) 46 | OptionType porc_; // porc_: put or call 47 | int numTimeSteps_; 48 | int numScenarios_; 49 | bool runParallel_ = true; 50 | int initSeed_ = 106; // Initial seed setting 51 | double quantity_ = 1.0; // Number of contracts 52 | 53 | // Computed values: 54 | double discFactor_; 55 | double price_; 56 | 57 | // Vector storing generated seeds for the MC scenarios: 58 | std::vector seeds_; 59 | 60 | // Runtime comparison using concurrency 61 | double time_; 62 | }; 63 | 64 | #endif 65 | 66 | /* 67 | Copyright 2019 Daniel Hanson 68 | 69 | Licensed under the Apache License, Version 2.0 (the "License"); 70 | you may not use this file except in compliance with the License. 71 | You may obtain a copy of the License at 72 | 73 | http://www.apache.org/licenses/LICENSE-2.0 74 | 75 | Unless required by applicable law or agreed to in writing, software 76 | distributed under the License is distributed on an "AS IS" BASIS, 77 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 78 | See the License for the specific language governing permissions and 79 | limitations under the License. 80 | */ 81 | -------------------------------------------------------------------------------- /SourceCode/RootFinding/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /SourceCode/RootFinding/Bisection.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Daniel Hanson, Tania Luo 3 | University of Washington 4 | Dept of Applied Mathematics 5 | Computational Finance & Risk Management (CFRM) 6 | For instructional purposes only 7 | */ 8 | 9 | #ifndef BISECTION_H 10 | #define BISECTION_H 11 | 12 | #include 13 | #include 14 | 15 | namespace qdh { 16 | namespace root_finding { 17 | 18 | using Real = double; 19 | 20 | template 21 | auto bisection(F f, Real a, Real b, Real tol = std::sqrt(std::numeric_limits::epsilon()), 22 | unsigned int maxIterations = 1000, Real guessZero = std::sqrt(std::numeric_limits::epsilon())) 23 | { 24 | //Check that the two inital guesses are not zeroes already 25 | if (std::abs(f(a)) < guessZero) 26 | { 27 | return a; 28 | } 29 | if (std::abs(f(b)) < guessZero) 30 | { 31 | return b; 32 | } 33 | if (f(b) * f(a) > 0) 34 | { 35 | // Error condition; must have f(b) * f(a) < 0; 36 | // otherwise, does not converge: 37 | return std::numeric_limits::infinity(); 38 | } 39 | // Algorithm for bisection method adapted from Numerical Analysis, 5th Edition, Burden and Faires, 1993 40 | // and An Introduction to Numerical Analysis, 2nd Eidtion, K. Atkinson, 1989 41 | for (unsigned int i = 0; i < maxIterations; ++i) 42 | { 43 | Real c = (a + b) / 2; 44 | if ((std::abs(b-c)/std::abs(b)) < tol) 45 | { 46 | return c; 47 | } 48 | 49 | if (f(b) * f(c) <= 0) 50 | { 51 | a = c; 52 | } 53 | else 54 | { 55 | b = c; 56 | } 57 | } 58 | // Error condition: does not converge: 59 | return std::numeric_limits::infinity(); 60 | } 61 | } } 62 | 63 | #endif // !BISECTION_H 64 | 65 | /* 66 | Copyright 2019 Daniel Hanson, Tania Luo 67 | 68 | Licensed under the Apache License, Version 2.0 (the "License"); 69 | you may not use this file except in compliance with the License. 70 | You may obtain a copy of the License at 71 | 72 | http://www.apache.org/licenses/LICENSE-2.0 73 | 74 | Unless required by applicable law or agreed to in writing, software 75 | distributed under the License is distributed on an "AS IS" BASIS, 76 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 77 | See the License for the specific language governing permissions and 78 | limitations under the License. 79 | */ 80 | -------------------------------------------------------------------------------- /SourceCode/RootFinding/Steffenson.h: -------------------------------------------------------------------------------- 1 | #ifndef STEFFENSON_H 2 | #define STEFFENSON_H 3 | 4 | #include 5 | #include 6 | 7 | namespace qdh 8 | { 9 | namespace root_finding 10 | { 11 | using Real = double; 12 | 13 | template 14 | auto steffensonMethod(F f, Real initialGuess, Real tol = std::sqrt(std::numeric_limits::epsilon()), unsigned int maxIterations = 100000, 15 | Real guessZero = std::sqrt(std::numeric_limits::epsilon())) 16 | { 17 | //We first check to see if the initial guess is already a root of the target function 18 | if (std::abs(f(initialGuess)) < guessZero) 19 | { 20 | return initialGuess; 21 | } 22 | 23 | Real x_n_1 = initialGuess; 24 | Real x_n = 0.0; 25 | 26 | for (unsigned int i = 0; i < maxIterations; ++i) 27 | { 28 | //Formula for Steffensen's method from An Introduction to Numerical Analysis, 2nd ed., Atkinson 1989 29 | Real D = f(x_n_1 + f(x_n_1)) - f(x_n_1); 30 | x_n = x_n_1 - ((f(x_n_1)*f(x_n_1)) / D); 31 | if (std::abs(x_n_1 - x_n) < tol) 32 | { 33 | return x_n; 34 | } 35 | x_n_1 = x_n; 36 | } 37 | 38 | return std::numeric_limits::infinity(); 39 | } 40 | } 41 | } 42 | 43 | /* 44 | Copyright 2019 Daniel Hanson, Tania Luo 45 | 46 | Licensed under the Apache License, Version 2.0 (the "License"); 47 | you may not use this file except in compliance with the License. 48 | You may obtain a copy of the License at 49 | 50 | http://www.apache.org/licenses/LICENSE-2.0 51 | 52 | Unless required by applicable law or agreed to in writing, software 53 | distributed under the License is distributed on an "AS IS" BASIS, 54 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 55 | See the License for the specific language governing permissions and 56 | limitations under the License. 57 | */ 58 | 59 | 60 | #endif // !STEFFENSON_H 61 | 62 | -------------------------------------------------------------------------------- /SourceCode/RootFindingExamples.cpp: -------------------------------------------------------------------------------- 1 | #include "ExampleFunctionsHeader.h" 2 | #include "RootFinding/Bisection.h" 3 | #include "RootFinding/Steffenson.h" 4 | #include 5 | #include 6 | 7 | using qdh::root_finding::bisection; 8 | using qdh::root_finding::steffensonMethod; 9 | using qdh::root_finding::Real; // typedef for double 10 | using std::log; 11 | using std::cout; 12 | using std::endl; 13 | 14 | void bisectionExamples() 15 | { 16 | cout << endl << "*** bisectionExamples() ***" << endl; 17 | // First, represent functions as function objects: 18 | Quadratic qdr; 19 | SineFcn sf; 20 | 21 | auto qdrRoot = bisection(qdr, -3.0, -1.5, 0.0001, 1000); 22 | auto sinRoot = bisection(sf, -1.0, 3.0); 23 | 24 | cout << "Passing function objects:" << endl; 25 | cout << "Root of quadratic function = " << qdrRoot << endl; 26 | cout << "Root of sine function = " << sinRoot << endl << endl; 27 | 28 | // Passing function objects // (both OK): 29 | // Root of quadratic function = -2 30 | // Root of sine function = 1.52815e-162 -- essentially zero 31 | 32 | // Next, use lambdas: 33 | auto cubic = [](double x) {return x * x * x + 1; }; //, -10.0, 0.0) 34 | auto powSeven = [](double x) {return std::pow(x, 7.0); }; // , -3.0, 3.0) 35 | 36 | auto cubicRoot = bisection(cubic, -10.0, 3.0, 0.0001, 1000); 37 | // Put in larger tolerance and fewer max iterations, to demonstrate: 38 | auto powRoot = bisection(powSeven, -3.0, 3.0, 0.0001, 100); 39 | cout << "Passing lambda expressions:" << endl; 40 | cout << "Root of cubic function = " << cubicRoot << endl; 41 | cout << "Root of power function = " << powRoot << endl << endl; 42 | 43 | // Passing lambda expressions // (both OK): 44 | // Root of cubic function = -1 45 | // Root of power function = 7.44402e-24 -- essentially zero 46 | } 47 | 48 | void steffensonExamples() 49 | { 50 | cout << endl << "*** steffensonExamples() ***" << endl; 51 | // First, represent functions as function objects: 52 | Quadratic qdr; 53 | SineFcn sf; 54 | 55 | auto qdrRoot = steffensonMethod(qdr, -1.5); 56 | auto sinRoot = steffensonMethod(sf, -0.5); 57 | 58 | cout << "Passing function objects:" << endl; 59 | cout << "Root of quadratic function = " << qdrRoot << endl; 60 | cout << "Root of sine function = " << sinRoot << endl << endl; 61 | 62 | // Passing function objects // (both OK): 63 | // Root of quadratic function = -2 64 | // Root of sine function = 1.52815e-162 -- essentially zero 65 | 66 | // Next, use lambdas: 67 | auto cubic = [](double x) {return x * x * x + 1; }; //, -10.0, 0.0) 68 | auto logFcn = [](double x) {return log(x - 3.5); }; // , -3.0, 3.0) 69 | 70 | auto cubRoot = steffensonMethod(cubic, -10.0); 71 | // Put in larger tolerance and fewer max iterations, to demonstrate: 72 | auto logRoot = steffensonMethod(logFcn, 5.0, 0.001, 1000000); 73 | cout << "Passing lambda expressions:" << endl; 74 | cout << "Root of cubic function = " << cubRoot << endl; 75 | cout << "Root of log function = " << logRoot << endl << endl; 76 | 77 | // Passing lambda expressions : // Both OK 78 | // Root of cubic function = -1 79 | // Root of log function = 4.5 80 | 81 | } 82 | 83 | // Class member functions below: 84 | double Quadratic::operator()(double x) const 85 | { 86 | return x * (x + 3.0) + 2.0; 87 | } 88 | 89 | double SineFcn::operator()(double x) const 90 | { 91 | return sin(x); 92 | } 93 | 94 | /* 95 | Copyright 2019 Daniel Hanson 96 | 97 | Licensed under the Apache License, Version 2.0 (the "License"); 98 | you may not use this file except in compliance with the License. 99 | You may obtain a copy of the License at 100 | 101 | http://www.apache.org/licenses/LICENSE-2.0 102 | 103 | Unless required by applicable law or agreed to in writing, software 104 | distributed under the License is distributed on an "AS IS" BASIS, 105 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 106 | See the License for the specific language governing permissions and 107 | limitations under the License. 108 | */ 109 | 110 | --------------------------------------------------------------------------------