/*
GBMgen_B.cpp
A GBM algorithm
algo_link: https://codereview.stackexchange.com/questions/177574/generating-stock-prices-using-geometric-brownian-motion/177677#177677
2023-07-27-Th: converted to this simple C++ pgm (as a simple C function) by @earth_imperator for posting on ET for discussion
Status: Algorithm is maybe incorrect --> check & test & verify...
IMO _one_ of the causes is a missing "reset after each sequence"
(IMO missing in nearly all GBM implementations & descriptions)
Compile: g++ -Wall -Wextra -O2 -std=c++11 -o GBMgen_B.exe GBMgen_B.cpp -lm
Example run:
$ ./GBMgen_B.exe
Cmdline: ./GBMgen_B.exe
GBMgen_B:
algo_link: https://codereview.stackexchange.com/questions/177574/generating-stock-prices-using-geometric-brownian-motion/177677#177677
params: r=0.040000 s=0.200000 t=0.750000 n=2 S=100.000000 nGen=30 fPrint=1 seed=1690554792
internals: drift=1.007528 vol=0.122474
gen_algo: St = St * drift * exp(vol * rndSND)
98.367702
91.369361
81.443924
89.576659
99.130322
94.066995
102.134197
104.453017
80.286436
99.622408
100.212109
124.228467
130.914490
135.390449
152.850097
172.552860
179.420843
162.930775
171.451668
144.015227
137.126149
145.258968
141.828304
106.580764
92.925408
93.851267
95.736064
96.592048
83.877916
98.405973
*/
#include <cstdio>
#include <ctime>
#include <cmath>
#include <random>
using namespace std;
/*-------------------------------------------------------------------------------------------
Example call:
GBMgen_B(0.04, // r: drift, ie. "riskless interest rate" / 100
0.20, // s: volatility / 100
0.75, // t: time (expiry) in years
2, // n: "number of time steps" ??? CHECK: IMO used wrongly in the code
100.0, // S: initial stock price
30, // nGen: generate that many stock prices
true, // fPrint: print to screen yes
0 // seed: 0 means to use a random seed, else the user given seed will be used
); // (useful in repeating the same sequence, esp. when debugging)
*/
void GBMgen_B(const double r, const double s, const double t, const size_t n, const double S,
const size_t nGen, const bool fPrint, size_t seed)
{
const char* algo_link = "https://codereview.stackexchange.com/questions/177574/generating-stock-prices-using-geometric-brownian-motion/177677#177677";
// if seed is zero then take a random seed, else use the given seed
if (!seed) seed = time(0);
const double drift = exp((r - 0.5 * s * s) * t / n);
const double vol = s * sqrt(t / n); // MATH TRICK: it's equal to "sqrt(s * s * t / n)"
default_random_engine rndgen;
rndgen.seed(seed);
normal_distribution<double> stdND(0.0, 1.0); // u=0.0 s=1.0
double St = S;
printf("GBMgen_B:\n"
" algo_link: %s\n"
" params: r=%lf s=%lf t=%lf n=%zu S=%lf nGen=%zu fPrint=%d seed=%zu\n"
" internals: drift=%lf vol=%lf\n"
" gen_algo: St = St * drift * exp(vol * rndSND)\n",
algo_link,
r, s, t, n, S, nGen, fPrint, seed,
drift, vol);
// generate nGen random stock prices:
for (size_t i = 0; i < nGen; ++i)
{
const double rndSND = stdND(rndgen);
St *= drift * exp(vol * rndSND);
//...do something with the generated price in St,
// f.e. add to an external array/vector or write to file and/or screen etc.
if (fPrint) printf("%lf\n", St);
}
}
void print_cmdline(const int argc, char* argv[])
{
printf("Cmdline:");
for (int i = 0; i < argc; ++i)
printf(" %s", argv[i]);
printf("\n");
}
int main(int argc, char* argv[])
{ // Usage: ./GBMgen_B.exe [nGen [seed]]
// The defaults are nGen=30 and seed=0
// Passing a seed != 0 generates the same sequence
print_cmdline(argc, argv);
const size_t nGen = argc > 1 ? atoi(argv[1]) : 30;
const size_t seed = argc > 2 ? atoi(argv[2]) : 0;
//...
GBMgen_B(0.04, // r: drift, ie. "riskless interest rate" / 100
0.20, // s: volatility / 100
0.75, // t: time (expiry) in years
2, // n: "number of time steps" ??? CHECK: IMO used wrongly in the code
100.0, // S: initial stock price
nGen, // nGen: generate that many stock prices
true, // fPrint: print to screen yes
seed // seed: 0 means to use a random seed
);
return 0;
}