Geometric Brownian Motion; Simulation of Stock Price - c++

I made a GBM function in C++ and I believe I am getting too much of a range of stock prices when I start with an initial price of 100 the output can be from [50,400]. I am not sure what I am doing wrong in my code, I am guessing there is something wrong with the way I seed the random standard normal numbers. Please have a look at the function and let me know if there is anything I shold modify or change.
Here is the function:
std::vector<double> GBM(const int M, const int N, const double T, const double r, const double q, const double sigma, const double S0){
double dt = T/N;
std::vector<double> Z;
std::vector<double> S;
S.push_back(S0);
std::mt19937 e2(time(0));
std::normal_distribution<double> dist(0.0, 1.0);
for(int i = 0; i < M; i++){
Z.push_back(dist(e2));
}
double drift = exp(dt*((r - q)-0.5*sigma*sigma));
double vol = sqrt(sigma*sigma*dt);
for(int i = 1; i < M; i++){
S.push_back(S[i-1] * drift * exp(vol*Z[i]));
}
return S;
}
Here is the main.cpp file that utilizes the function above:
#include <iostream>
#include "LSM.h"
#include <cmath>
#include <ctime>
#include <Eigen/Core>
#include <Eigen/SVD>
#include <iostream>
#include <vector>
#include <random>
std::vector<double> GBM(const int M, const int N, const double T, const double r, const double q, const double sigma, const double S0);
int main(){
const double r = 0.04; // Riskless interest rate
const double q = 0.0; // Divident yield
const double sigma = 0.20; // Volatility of stock
const double T = 1; // Time (expiry)
const int N = 1000; // Number of time steps
const double K = 100.0; // Strike price
const double S0 = 100.0; // Initial stock price
const int M = 10000; // Number of paths
const int R = 2; // Choice of basis for Laguerre polynomial
//LSM Option_value(r,q,sigma,T,N,K,S0,M,R);
std::vector<double> s = GBM(M,N,T,r,q,sigma,S0);
for(int i = 0; i < M; i++){
std::cout << s[i] << std::endl;
}
return 0;
}
A typical output that one should get starting with an initial stock price of 100 is below:
153.5093
132.0190
96.2550
106.5196
58.8447
135.3935
107.1194
101.2022
134.2812
82.2146
87.9162
74.9333
88.9137
207.5150
123.7893
95.8526
120.0831
96.3990
103.3806
113.8258
100.6409
92.0724
81.1704
121.9925
114.3798
117.8366
86.1070
74.4885
82.6013
78.0202
97.0586
119.7626
89.0520
72.2328
92.1998
84.7180
138.9160
91.0091
105.2096
91.3323
79.0289
115.9377
75.4887
123.2049
101.1904
95.9454
82.4181
108.8314
123.0198
76.8494
94.8827
149.5911
95.6969
143.3498
87.0939
77.3033
105.8185
122.3455
79.8208
112.9913
120.1649
131.3052
136.8246
96.5455
109.0187
87.1363
103.1835
106.3896
143.9496
119.1357
99.9114
111.1409
79.0563
147.1506
105.7851
99.7089
117.8770
99.7602
73.1796
125.8698
109.4367
135.5020
88.1979
129.8502
121.1233
76.7520
86.5296
118.6721
83.2511
116.3950
99.8795
70.6895
64.9578
111.4750
102.6343
82.8765
90.3479
106.8873
106.3850
119.3399

Function GBM should simulate 1 path every time. So no need to supply M. And the path length is, in your code, defined by N instead of M.
If you implement this change, GBM return the whole simulated path.
Then you need to call GBM M times in order to calculate all the simulations.
Also there is no need to store all the random numbers generated.
Based on your sample, something like this:
#include <iostream>
#include <vector>
#include <random>
// Random generator initialize (only once).
static std::mt19937 rng(time(0));
std::vector<double> GBM(const int N, const double T, const double r,
const double q, const double sigma, const double S0)
{
double dt = T/N;
std::vector<double> S;
S.push_back(S0);
std::normal_distribution<double> dist(0.0, 1.0);
double drift = exp(dt*((r - q)-0.5*sigma*sigma));
double vol = sqrt(sigma*sigma*dt);
for(int i = 1; i < N; i++){
double Z = dist(rng);
S.push_back(S[i-1] * drift * exp(vol*Z));
}
return S;
}
int main(){
const double r = 0.04; // Riskless interest rate
const double q = 0.0; // Divident yield
const double sigma = 0.20; // Volatility of stock
const double T = 1; // Time (expiry)
const int N = 1000; // Number of time steps
const double S0 = 100.0; // Initial stock price
const int M = 100; // Number of paths
for (int sindx = 0; sindx < M; sindx++)
{
std::vector<double> s = GBM(N,T,r,q,sigma,S0);
std::cout << "Simulation " << sindx << ": "
<< s[0] << ", " << s[1] << " ... " << s[N-2] << ", " << s[N-1]
<< std::endl;
}
return 0;
}

From the comments behind the constants, you want to simulate 10000 paths of an integration from 0 to 1 using 1000 subdivision steps, i.e., a step size of 0.001.
What you are doing is integrating one path over 10000 steps of step size 0.001, that is, from 0 to 10.
If you do this correctly, the result should look like a list of
S0 * exp( ((r-q)-0.5*sigma*sigma)*T + sigma*sqrt(T)*Z[i] )
as the value of the GBM at time T only depends on W(T) which is distributed as N(0,T) or sqrt(T)*N(0,1).

Related

How to calculate sum of Pi

I posted not long ago on how to compute the sum of Pi with openmp. But it seems something's off with my code. Because manually I get the right result, but when I program it, it gives wrong results, if someone can help me?
PS : s= 1/N
#include <chrono>
#include <iostream>
double f(double x)
{
return (4 / (1 + (x * x)));
}
int main()
{
int i;
const int N = 60;
double s1=0.0; double s2=0.0; double s3=0.0;
double pi = 0.0; double s4=0.0; double s5=0.0;
for (int i=0; i<N; i++)
{
//pi+=((f(i/N)+f((i+1)/N))/2*N);
s1 = f(i/N);
s2 = f((i+1)/N);
s3 = 2 * N;
s4 = s1 + s2;
s5 = s4 / s3;
pi+=s5;
}
printf("Pi = %f",pi);
return 0;
}
The reason the value is different is because variable 'i' as well as 'N' are int's. When dividing int by int the answer will always be int.
Easiest and fastest fix is to change one of the variables to a double eg.:
#include <chrono>
#include <iostream>
double f(double x)
{
return (4 / (1 + (x * x)));
}
int main()
{
const int N = 60;
double s1=0.0; double s2=0.0; double s3=0.0;
double pi = 0.0; double s4=0.0; double s5=0.0;
for (double i=0; i<N; i++) // i changed the int to double for the 'i' declaration
{
//pi+=((f(i/N)+f((i+1)/N))/2*N);
s1 = f(i/N);
s2 = f((i+1)/N);
s3 = 2 * N;
s4 = s1 + s2;
s5 = s4 / s3;
pi+=s5;
}
//printf("Pi = %f",pi);
std::cout << "Pi = " << pi << std::endl;
return 0;
}
Also since you're programming in c++ make sure to pick the better c++ alternative to some of the code:
printf is C. It still works but c++'s cout is a better alternative that's improved and safer in most cases.
You also have an extra unneeded variable declaration. You're creating two 'i' variables. Once at the start and once in the loop.
As I got it from the answers, the problem was in (i/N). Since the i int declared as an int we need to add ((double)i/N).
pi+=((f((double)i/N)+f(((double)i+1)/N))/(2*N));

Double not being printed out

In this code, I am making a cluster of particles and assigning them x, y and z coordinates. Then, I am evaluating the force due to this cluster at some far away point. The function directSumUnregularized calculates that force.
I want to see what that force is, but for whatever reason, it is not being printed out.
This is my code:
#include <omp.h>
#include <time.h>
#include <iostream>
#include <cmath>
#include <random>
#include "unitTestFunctions.h"
int main() {
//set up cluster of particles
const int numberOfParticles = 10;
std::random_device rd{};
std::mt19937 gen{rd()};
std::normal_distribution<> d{0,1};
PARTICLE *clusterOfParticles = new PARTICLE [numberOfParticles];
double sumX{}, sumY{}, sumZ{};
for (int ind=0; ind<numberOfParticles; ind++){
clusterOfParticles[ind].x = d(gen);
clusterOfParticles[ind].y = d(gen);
clusterOfParticles[ind].z = d(gen);
}
//test position
double xTest {5}, yTest{6}, zTest {7};
double *exactForceX{nullptr}, *exactForceY{nullptr}, *exactForceZ{nullptr};
*exactForceX = 0;
*exactForceY = 0;
*exactForceZ = 0;
directSumUnregularized(numberOfParticles, exactForceX, exactForceY,
exactForceZ, xTest, yTest, zTest,
clusterOfParticles);
std::cout<<"exactForce X: "<<*exactForceX<<std::endl;
delete [] clusterOfParticles;
return 0;
}
and my function:
#include <omp.h>
#include <time.h>
#include <iostream>
#include <cmath>
#include <random>
#include "unitTestFunctions.h"
void directSumUnregularized(const int numberOfParticles, double *exactForceX,
double *exactForceY, double *exactForceZ, double xTest, double yTest, double zTest,
PARTICLE *clusterOfParticles){
double rSq{};
double r{};
double dx {}, dy {}, dz{};
const double pi = 3.1415926535897;
double inv4pi = 1/(4*pi);
for (int i=0; i<numberOfParticles; i++){
dx = xTest - clusterOfParticles[i].x;
dy = yTest - clusterOfParticles[i].y;
dz = zTest - clusterOfParticles[i].z;
rSq = dx*dx+dy*dy+dz*dz;
r = sqrt(rSq);
*exactForceX -= inv4pi*(dx/(rSq*r));
*exactForceY -= inv4pi*(dy/(rSq*r));
*exactForceZ -= inv4pi*(dz/(rSq*r));
}
return;
}
how should I go about this?
Regarding exactForceX/Y/Z, in order to work, it has to be like this:
//test position
double xTest = 6, yTest = 6, zTest = 7;
double exactForceX = 0, exactForceY = 0, exactForceZ = 0;
directSumUnregularized(umberOfParticles, &exactForceX, &exactForceY,
&exactForceZ, xTest, yTest, zTest,
clusterOfParticles);
std::cout << "exactForce X: " << exactForceX << std::endl;
1st, define (& initialize) the 3 variables:
double exactForceX = 0, exactForceY = 0, exactForceZ = 0;
2nd, deliver the 3 addresses to the function, to allow it to store the results.
The problematic section is
double *exactForceX{nullptr}, *exactForceY{nullptr}, *exactForceZ{nullptr};
*exactForceX = 0;
*exactForceY = 0;
*exactForceZ = 0;
What exactly is this doing?
double *exactForceX{nullptr};
*exactForceX = 0;
You are creating a pointer with the value of nullptr, attempting to dereference it and assign the value 0. Dereferencing a nullptr is undefined behaviour.
To fix it you need the address-of operator &
double exactForceX = 0;
double exactForceY = 0;
double exactForceZ = 0;
directSumUnregularized(numberOfParticles, &exactForceX, &exactForceY,
&exactForceZ, xTest, yTest, zTest,
clusterOfParticles);
It seems that there is some confusion on how pointers work. I like to use a simple example like this.
double value = 12345;
double *pointer_to_value = &value;
std::cout << "value " << value << std::endl;
std::cout << "&value " << &value << std::endl;
std::cout << "pointer_to_value " << pointer_to_value << std::endl;
std::cout << "*pointer_to_value " << *pointer_to_value << std::endl;
This will give the output that looks like: (The address may be different for you)
value 12345
&value 0x7ffc601869b0
pointer_to_value 0x7ffc601869b0
*pointer_to_value 12345
The point (heh) is that a pointer must point to a valid location. That is, either the location of a variable, or a call to new. In this case, the valid location is the location of the variable value.
See also: What is a segmentation fault?

Memory Overflow? std::badalloc

I have a program that solves generally for 1D brownian motion using an Euler's Method.
Being a stochastic process, I want to average it over many particles. But I find that as I ramp up the number of particles, it overloads and i get the std::badalloc error, which I understand is a memory error.
Here is my full code
#include <iostream>
#include <vector>
#include <fstream>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <ctime>
using namespace std;
// Box-Muller Method to generate gaussian numbers
double generateGaussianNoise(double mu, double sigma) {
const double epsilon = std::numeric_limits<double>::min();
const double tau = 2.0 * 3.14159265358979323846;
static double z0, z1;
static bool generate;
generate = !generate;
if (!generate) return z1 * sigma + mu;
double u1, u2;
do {
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
} while (u1 <= epsilon);
z0 = sqrt(-2.0 * log(u1)) * cos(tau * u2);
z1 = sqrt(-2.0 * log(u1)) * sin(tau * u2);
return z0 * sigma + mu;
}
int main() {
// Initialize Variables
double gg; // Gaussian Number Picked from distribution
// Integrator
double t0 = 0; // Setting the Time Window
double tf = 10;
double n = 5000; // Number of Steps
double h = (tf - t0) / n; // Time Step Size
// Set Constants
const double pii = atan(1) * 4; // pi
const double eta = 1; // viscous constant
const double m = 1; // mass
const double aa = 1; // radius
const double Temp = 30; // Temperature in Kelvins
const double KB = 1; // Boltzmann Constant
const double alpha = (6 * pii * eta * aa);
// More Constants
const double mu = 0; // Gaussian Mean
const double sigma = 1; // Gaussian Std Deviation
const double ng = n; // No. of pts to generate for Gauss distribution
const double npart = 1000; // No. of Particles
// Initial Conditions
double x0 = 0;
double y0 = 0;
double t = t0;
// Vectors
vector<double> storX; // Vector that keeps displacement values
vector<double> storY; // Vector that keeps velocity values
vector<double> storT; // Vector to store time
vector<double> storeGaussian; // Vector to store Gaussian numbers generated
vector<double> holder; // Placeholder Vector for calculation operations
vector<double> mainstore; // Vector that holds the final value desired
storT.push_back(t0);
// Prepares mainstore
for (int z = 0; z < (n+1); z++) {
mainstore.push_back(0);
}
for (int NN = 0; NN < npart; NN++) {
holder.clear();
storX.clear();
storY.clear();
storT.clear();
storT.push_back(0);
// Prepares holder
for (int z = 0; z < (n+1); z++) {
holder.push_back(0);
storX.push_back(0);
storY.push_back(0);
}
// Gaussian Generator
srand(time(NULL));
for (double iiii = 0; iiii < ng; iiii++) {
gg = generateGaussianNoise(0, 1); // generateGaussianNoise(mu,sigma)
storeGaussian.push_back(gg);
}
// Solver
for (int ii = 0; ii < n; ii++) {
storY[ii + 1] =
storY[ii] - (alpha / m) * storY[ii] * h +
(sqrt(2 * alpha * KB * Temp) / m) * sqrt(h) * storeGaussian[ii];
storX[ii + 1] = storX[ii] + storY[ii] * h;
holder[ii + 1] =
pow(storX[ii + 1], 2); // Finds the displacement squared
t = t + h;
storT.push_back(t);
}
// Updates the Main Storage
for (int z = 0; z < storX.size(); z++) {
mainstore[z] = mainstore[z] + holder[z];
}
}
// Average over the number of particles
for (int z = 0; z < storX.size(); z++) {
mainstore[z] = mainstore[z] / (npart);
}
// Outputs the data
ofstream fout("LangevinEulerTest.txt");
for (int jj = 0; jj < storX.size(); jj++) {
fout << storT[jj] << '\t' << mainstore[jj] << '\t' << storX[jj] << endl;
}
return 0;
}
As you can see, npart is the variable that I change to vary the number of particles. But after each iteration, I do clear my storage vectors like storX,storY... So on paper, the number of particles should not affect memory? I am only just calling the compiler to repeat many more times, and add onto the main storage vector mainstore. I am running my code on a computer with 4GB ram.
Would greatly appreciate it if anyone could point out my errors in logic or suggest improvements.
Edit: Currently the number of particles is set to npart = 1000.
So when I try to ramp it up to like npart = 20000 or npart = 50000, it gives me memory errors.
Edit2 I've edited the code to allocate an extra index to each of the storage vectors. But it does not seem to fix the memory overflow
There is an out of bounds exception in the solver part. storY has size n and you access ii+1 where i goes up to n-1. So for your code provided. storY has size 5000. It is allowed to access with indices between 0 and 4999 (including) but you try to access with index 5000. The same for storX, holder and mainstore.
Also, storeGaussian does not get cleared before adding new variables. It grows by n for each npart loop. You access only the first n values of it in the solver part anyway.
Please note, that vector::clear removes all elements from the vector, but does not necessarily change the vector's capacity (i.e. it's storage array), see the documentation.
This won't cause the problem here, because you'll reuse the same array in the next runs, but it's something to be aware when using vectors.

C++ Advice on manipulating output Matrix data

I have the following code.
Essentially it is creating N random normal variables, and running through an equation M times for a simulation.
The output should be an NxM matrix of data, however the only way I could do the calculation has the output as MxN. ie each M run should be a column, not a row.
I have attempted in vain to follow some of the other suggestions that have been posted on previous similar topics.
Code:
#include <iostream>
#include <time.h>
#include <random>
int main()
{
double T = 1; // End time period for simulation
int N = 4; // Number of time steps
int M = 2; // Number of simulations
double x0 = 1.00; // Starting x value
double mu = 0.00; // mu(x,t) value
double sig = 1.00; // sigma(x,t) value
double dt = T/N;
double sqrt_dt = sqrt(dt);
double** SDE_X = new double*[M]; // SDE Matrix setup
// Random Number generation setup
double RAND_N;
srand ((unsigned int) time(NULL)); // Generator loop reset
std::default_random_engine generator (rand());
std::normal_distribution<double> distribution (0.0,1.0); // Mean = 0.0, Variance = 1.0 ie Normal
for (int i = 0; i < M; i++)
{
SDE_X[i] = new double[N];
for (int j=0; j < N; j++)
{
RAND_N = distribution(generator);
SDE_X[i][0] = x0;
SDE_X[i][j+1] = SDE_X[i][j] + mu * dt + sig * RAND_N * sqrt_dt; // The SDE we wish to plot the path for
std::cout << SDE_X[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << " The simulation is complete!!" << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}
Well why can't you just create the transpose of your SDE_X matrix then? Isn't that what you want to get?
Keep in mind, that presentation has nothing to do with implementation. Whether to access columns or rows is your decision. So you want an implementation of it transposed. Then quick and dirty create your matrix first, and then create your number series. Change i and j, and N and M.
I said quick and dirty, because the program at all is bad:
why don't you just keep it simple and use a better data structure for your matrix? If you know the size: compile-time array or dynamic vectors at runtime? Maybe there are some nicer implementation for 2d array.
There is a bug I think: you create N doubles and access index 0 to N inclusive.
In every iteration you set index 0 to x0 what is also needless.
I would change your code a bit make more clear:
create your matrix at first
initialize the first value of the matrix
provide an algorithm function calculating a target cell taking the matrix and the parameters.
Go through each cell and invoke your function for that cell
Thank you all for your input. I was able to implement my code and have it displayed as needed.
I added a second for loop to rearrange the matrix rows and columns.
Please feel free to let me know if you think there is anyway I can improve it.
#include <iostream>
#include <time.h>
#include <random>
#include <vector>
int main()
{
double T = 1; // End time period for simulation
int N = 3; // Number of time steps
int M = 2; // Number of simulations
int X = 100; // Max number of matrix columns
int Y = 100; // Max number of matrix rows
double x0 = 1.00; // Starting x value
double mu = 0.00; // mu(x,t) value
double sig = 1.00; // sigma(x,t) value
double dt = T/N;
double sqrt_dt = sqrt(dt);
std::vector<std::vector<double>> SDE_X((M*N), std::vector<double>((M*N))); // SDE Matrix setup
// Random Number generation setup
double RAND_N;
srand ((unsigned int) time(NULL)); // Generator loop reset
std::default_random_engine generator (rand());
std::normal_distribution<double> distribution (0.0,1.0); // Mean = 0.0, Variance = 1.0 ie Normal
for (int i = 0; i <= M; i++)
{
SDE_X[i][0] = x0;
for (int j=0; j <= N; j++)
{
RAND_N = distribution(generator);
SDE_X[i][j+1] = SDE_X[i][j] + mu * dt + sig * RAND_N * sqrt_dt; // The SDE we wish to plot the path for
}
}
for (int j = 0; j <= N; j++)
{
for (int i = 0; i <=M; i++)
{
std::cout << SDE_X[i][j] << ", ";
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << " The simulation is complete!!" << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}

Reading 2 CSV files and using vectors to store the values and then calculate the coefficient. Returns -1.#IND

This is my code I have, which when I build it works and creates the .exe file, however throughout the process I print the function (i.e. mean, covarience, coefficient) and they all come back as -1#IND. Think it may not be pulling in the data from the CSV files correctly?
// basic file operations
#include <iterator>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
using namespace std;
typedef vector<double> Prices;
Prices parse_csv_line(string& line)
{
Prices result;
string datum;
stringstream ss(line);
int count=0;
while(getline(ss,datum,','))
{
// convert string to
count++;
if (count%2 == 0)
result.push_back(atof(datum.c_str()));
}
return result;
}
Prices parse_csv_file(const char* filename)
{
ifstream file(filename);
Prices prices;
string line;
// This will discard the header line
getline(file, line);
// This will get each line in the file, and collate its values
while (getline(file, line))
{
Prices v = parse_csv_line(line);
prices.insert(prices.end(), v.begin(), v.end());
}
for(Prices::iterator it=prices.begin(); it != prices.end(); it++)
cout << " " << *it;
return prices;
}
//Calculate Correlation of series A and B, then return
/* Calculatethe mean averages for A and B.
(For each series, add each sample and then divide by the number of samples.) */
double CalculateMean(Prices x)
{
double sum = 0;
for(size_t i = 0; i < x.size(); i++)
sum += x[i];
return (sum / x.size());
}
/* Calculate the variance for A and B.
(First calculate the difference from the mean for each sample number. Square each number then divide by the number of samples (n).
If the numbers you are calculating represent a sample of a larger group, then you would divide by n – 1.) */
double CalculateVariance(Prices x)
{
double mean = CalculateMean(x);
double temp = 0;
for(size_t i = 0; i < x.size(); i++)
{
temp += (x[i] - mean) * (x[i] - mean) ;
}
return temp / x.size();
}
/* calculate the standard deviation for A and B, which is the square root of the variance.
(This number will tell you how closely your samples are located to the mean.) */
double Calculate_StandardDeviation(Prices x)
{
return sqrt(CalculateVariance(x));
}
/* Lastly, calculate the Covariance of the 2 series.
(This value can be used to represent the linear relationship between two variables.) */
double Calculate_Covariance(Prices x, Prices y)
{
double meanX = CalculateMean(x);
double meanY = CalculateMean(y);
cout << "mean x = " << meanX << "\n";
cout << "mean y = " << meanY << "\n";
double total = 0;
for(size_t i = 0; i < x.size(); i++)
{
total += (x[i] - meanX) * (y[i] - meanY);
}
return total / x.size();
}
// Using the calculated values, these can then be inputted into the Correlation Coefficient formula to find the correlation of series A and B.
double Calculate_Correlation(Prices x, Prices y)
{
double covariance = Calculate_Covariance(x, y);
cout << "covariance =" << covariance << "\n";
double correlation = covariance / (Calculate_StandardDeviation(x) * Calculate_StandardDeviation(y));
return correlation;
};
int main()
{
Prices a = parse_csv_file("PC1_A.CSV");
Prices b = parse_csv_file("PC1_B.CSV");
double correlation = Calculate_Correlation(a, b);
cout << "Correlation is: " << correlation;
cin.get();
}