finMath.net

Monte-Carlo Simulation of a Black Scholes Model

Getting Started

Checkout finmath-experiments from git and run maven (mvn or mvnw) from its directory. This will start a JShell. See Getting Started for details.

Experiment 0-4: Monte-Carlo Simulation and Valuation

Run the following experiment from your JShell (which was launched from finmath-experiments).

Experiment 0

The following will create an object of type TimeDiscretizationFromArray (from the package net.finmath.time) and then print the object (using the toString()-method). The time discretization starts in 0.0 and has 100 time steps of size 0.1.
JShell:

				var td = new net.finmath.time.TimeDiscretizationFromArray(0.0, 100, 0.1);
				td.toString();
			
We may shorten the name of object by importing a classes from the package or all classes from the packages (like name-spaces), e.g. here from net.finmath.time via import net.finmath.time.*;.

Experiment 1

In the following experiment we create a class of type BrownianMotionFromMersenneRandomNumbers (from the package net.finmath.montecarlo) which represent samples of a set of (independent) normal distributed random variables \( \Delta W(t_{i}) \) (the so called Brownian increments). The arguments of BrownianMotionFromMersenneRandomNumbers are (timeDiscretization, numberOfFactors, numberOfPaths, seed), where numberOfFactors refers to the vector dimension of \( \Delta W(t_{i}) \). In the following we create a one factor (i.e., one dimensional) Brownian motion:

JShell:

				import net.finmath.montecarlo.*;
				import net.finmath.plots.*;
				import net.finmath.time.*;
				
				var td = new TimeDiscretizationFromArray(0.0, 100, 0.1);
				var bm = new BrownianMotionFromMersenneRandomNumbers(td, 1, 10000, 3213);   // change number of paths
				var x = bm.getBrownianIncrement(0,0);
			
To plot a histogram of the random variable x enter
JShell:

				var plot = Plots.createHistogram(x, 100, 5.0);
				plot.setTitle("Histogram").setXAxisLabel("value").setYAxisLabel("frequency");
				plot.show();
				
			
For fun, you may also create an animation:
JShell:

				for(int i=2; i<100; i+=1) {
					int numberOfPaths = i*i*Math.max(i/10,1);
					Plots.updateHistogram(plot, (new BrownianMotionFromMersenneRandomNumbers(td, 1, numberOfPaths, 3213)).getBrownianIncrement(0,0), 100, 5.0);
					Thread.sleep(100);
				}
			

Experiment 2

Given a Brownian motion providing the Brownian increments \( \Delta W(t_{i}) \), we create a model (here a BlackScholesModel) and from that a simulation of this model using an Euler scheme (via EulerSchemeFromProcessModel). The model is \( \mathrm{d}S(t) = r S(t) \mathrm{d} + \sigma(t) S(t) \mathrm{d}W(t) ; \quad S(t_{0}) = S_{0} \), where \( S(t_{0}) \) is the modelInitialValue, \( r \) is the modelRiskFreeRate, \( \sigma \) is the modelVolatility.
JShell:

				import net.finmath.montecarlo.*;
				import net.finmath.montecarlo.process.*;
				import net.finmath.montecarlo.assetderivativevaluation.*;
				import net.finmath.montecarlo.assetderivativevaluation.models.*;
				import net.finmath.stochastic.*;
				import net.finmath.time.*;
				import net.finmath.plots.*;
				
				double modelInitialValue = 100.0;
				double modelRiskFreeRate = 0.05;
				double modelVolatility = 0.20;
				
				// Create a model
				var model = new BlackScholesModel(modelInitialValue, modelRiskFreeRate, modelVolatility);
				
				// Create a corresponding MC process from the model
				var td = new TimeDiscretizationFromArray(0.0, 300, 0.01);
				var brownianMotion = new BrownianMotionFromMersenneRandomNumbers(td, 1, 10000, 3231);
				var process = new EulerSchemeFromProcessModel(model, brownianMotion);
				
				// Create a function, plotting paths t -> S(t)
				DoubleToRandomVariableFunction paths = time -> process.getProcessValue(td.getTimeIndex(time), 0 /* assetIndex */);
				
				// Plot 100 of paths against the given time discretization.
				var plot = new PlotProcess2D(td, paths, 100);
				plot.setTitle("Black Scholes model paths").setXAxisLabel("time").setYAxisLabel("value");
				plot.show();
			

Experiment 3

We value a financial product on our simulation, that is we calculate the expectation \( E(f(S(T)) \) for, e.g. \( f(x) = \max(x - K) \). The function \( f \) represents the financial product, in the example below we use an EuropeanOption. The product provides a method getValue which implements \( E(f(S(T)) \) given a simulation providing S(T), in our example the object simulation. Note: the following requires that Experiment 2 has initialized the object simulation. We first create the product
JShell: (continued from experiment 2)

				import net.finmath.montecarlo.assetderivativevaluation.products.*;
				
				double maturity = 3.0;
				double strike = 106.0;
				
				var europeanOption = new EuropeanOption(maturity, strike);
			
Given that the objects process and europeanOption have been initialized, we can value the product against the simulation:
JShell: (continued)

				// Using the process (Euler scheme) and provide methods like getAssetValue and getNumeraire
				var simulation = new MonteCarloAssetModel(process);

				// Use the simulation to value the product				
				var valueOfEuropeanOption = europeanOption.getValue(0.0, simulation);
				var value = valueOfEuropeanOption.average().doubleValue();
			
The value reported it 18.115.... Request the standard error via
JShell: (continued)

				valueOfEuropeanOption.getStandardError();
			

The reported standard error is 0.27....

You can plot the products payoff function and the histogram of the simulated values of \( S(T) \) where \( T \) corresponds to the optionMaturity:

JShell: (continued)

				var underlying = simulation.getAssetValue(maturity, 0 /* assetIndex */);
				
				var plot = Plots.createHistogramBehindValues(underlying, valueOfEuropeanOption, 100 /* bins */, 5.0 /* stddev */);
				plot.setTitle("European option value and distribution of underlying").setXAxisLabel("underlying").setYAxisLabel("value");
				plot.show();
			

Analytic Benchmark

We may compare the value obtained from the Monte-Carlo simulation with the analytic solution using Black-Scholes formula:

JShell: (continued)

				import net.finmath.functions.AnalyticFormulas;
				
				AnalyticFormulas.blackScholesOptionValue(modelInitialValue, modelRiskFreeRate, modelVolatility, maturity, strike);
			
The value reported is 17.984... .

Summary (Experiments 1-3)

We have created a simulation, calculated the value of a European option.

Where to continue

You may continue with