Simulating stock prices using GBM

Discussion in 'App Development' started by earth_imperator, Jul 27, 2023.

  1. I'm in need of a well tested code snippet (C/C++ or similar language) for generating stock prices for simulations (Monte Carlo etc).
    Although I already have a GBM implementation, but I now discovered that it unfortunately does generate buggy data, so I'm in need for one that works correctly and was well tested.

    It seems to me that either the algorithm used in GBM (for example the "Ito lemma" part) is generally incorrect, or I must have got a buggy implementation. Of course the latter case is more probable b/c
    it's hard to believe that nobody in the whole world has discovered that the GBM algorithm is incorrect.

    Today I tried this code, but it too is generating wrong results :vomit:

    gbm.png
     
    Sergio123 likes this.
  2. ph1l

    ph1l

    EASYLANGUAGE CODE TO CREATE SYNTHETIC PRICES (see attachment for context)
    Code:
    // Synthetic Price Generator
    // (c) 2014 John F. Ehlers
    Vars:
        Pink(0),
        Hi(0),
        Lo(0);
    
    //Note: Pink[1] means the value of Pink one bar ago
    
    Pink = .004*Random(100) + .996*Pink [1];
    If Currentbar = 1 Then Pink = 50;
    
    Value1 = .5*Random(.25) + .5*Value1[1];
    Value2 = .5*Random(.25) + .5*Value2[1];
    
    Hi = Pink + Value1;
    Lo = Pink - Value2;
    
    Plot1(Hi);
    Plot2(Lo);
    
     
  3. @ph1l, thanks, but this does not look to be a GBM algorithm. It uses some "wild" constants w/o any logical explanations.
    I need to generate millions of such random stock prices for Monte Carlo simulations, ie. it's not about plotting them on the screen.

    A correct GBM algorithm must behave very realistic in terms of stochastics and probability, and must use standard parameters like initial price, drift rate (r), volatility (HV or IV), time (DTE) etc. as described on the said wikipedia page on GBM.

    Btw, the Python example code (and the plot it generates) on the above wiki page is IMO similarly unusable as it looks similarly much like an unscientific trash code w/o logic in it :-(
    W/o logic, b/c who in the world would start with an initial price near zero?... Only an idiot coder or a wanna-be "scientist".
    A similar idiotic plot by a "mathematician and finance quantitative analyst", ie. a "bank expert", is here: https://quantgirluk.github.io/Understanding-Quantitative-Finance/geometric_brownian_motion.html
    dumb_GBM_plot.png
    Dumb & dumber these plots! :)
    Such authors must have lost their mind, IMO. :)
    The correct plot must be "conic", like in my OP above.
     
    Last edited: Jul 28, 2023
  4. Sergio123

    Sergio123

    What makes you think it's wrong?

    Did you check the mu and sigma parameters?
     
  5. You asked the right question! :)

    I came from a different angle to the conclusion that the GBM algorithm must be wrong.
    Or the GBM implementations I so far have tested.
    I'm almost 100% sure it's wrong, but the explanation (and proof) is not that easy... but I'll give the proof soon.

    I could write a scientific paper and it would be a sensation and I would become famous like Black, Scholes, Merton, Bachelier, Einstein, Newton et al. :) ...but the crude reality is: I'm living in wrong times in a highly ignorant sicko SHC and society... :)

    Imagine: all the GBM simulations out there in the World are wrong! Including in nuclear research... :),
    And nobody but me knows it!... :)

    Btw, I found this bug in GBM after this posting of mine in the other thread recently where we had a fruitful discussion, I must say.
     
    Last edited: Jul 28, 2023
  6. ph1l

    ph1l

    Here is one
    https://people.sc.fsu.edu/~jburkard...on_simulation/brownian_motion_simulation.html
    That implementation uses a crude pseudorandom number generator, so you might want to substitute a better one like WELL.
     
    earth_imperator likes this.
  7. Here's the said algorithm from the initial posting as a basis for analysis & discussion.
    It can be compiled with any C++11 or newer compiler:

    Code:
    /*
      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;
      }
    
    
     
    Last edited: Jul 28, 2023
  8. This stupid software reformats the source code in code block.... :mad:
    Need to post original source file, but then this stupis software does not accept the file extension .cpp --> need to zip it or so... Will try...

    Here's the ZIP file:
     
    Last edited: Jul 28, 2023
  9. M.W.

    M.W.

    Google 'jump diffusion". It's absent in the classic GBM model.

     
  10. I know jump diffusion, but it's not the cause/reason here. JD not needed here.

    Can you give me links to non-classic GBM models?
    Do you mean Black's jump diffusion model?
     
    Last edited: Jul 28, 2023
    #10     Jul 28, 2023