Fredrik Olsson
Data Scientist
In this blogpost we will dive into the world of finance, and specifically option pricing. We are going to illustrate how we can use Monte Carlo simulations to price financial options, by looking at two examples. In both of these examples no explicit solution formula exists, making the Monte Carlo approach useful in pricing these options.
If you are not familiar with Monte Carlo simulations or financial options, or could use a reminder, I suggest that you take a look at the post Introduction to Monte Carlo simulations and option pricing where we introduced all these concepts. In that post we:
Introduced derivative assets and financial options, especially the European call option
Looked at our first model for stocks, namely the standard Black & Scholes model
Introduced the concept of Monte Carlo simulations
Looked at our first pricing example
The examples in this post are definitely more challenging mathematically, so make sure that you have a grasp on the basics from the introductory post.
Let's get started.
For our first example, we will use the standard Black & Scholes model, i.e. the same one used in the introduction post about Monte Carlo simulations and option pricing. Here the stock dynamics follow a Geometric Brownian Motion:
with the solution:
where , so has a log-normal distribution. The contract we will look at now, is very similar to a European call option, but instead of having just one underlying stock, we take the arithmetic average of several stocks ( of them). This contract is called an arithmetic basket call option, and has the following payoff at time :
Even if we know the distribution of every stock , we do not know the distribution of the arithmetic average of of them (the log-normality is not preserved under summation). We can therefore not find an explicit formula like the Black & Scholes formula for European call options in this case for the option price:
Our solution will be to use Monte Carlo simulations. For simulation purposes, we will use that the log stock prices follow a multivariate normal distribution. For simplicity, we assume that all stocks have the same initial value , same volatility and that the correlation between all the stocks are the same. The log stock prices will then follow a multivariate normal distribution with the following expected value vector and covariance matrix :
Note that is an -vector and is an -matrix. This is useful because we can now simulate from this multivariate normal distribution and then transform the values using the exponential function to get simulations of the stocks. We thus have the following Monte Carlo sampler for estimating the price of the arithmetic basket call option:
So, assuming that we have underlying stocks, that , the strike price , the risk free interest rate , the stock volatility , the correlation and that the time to maturity year, we can implement the following Monte Carlo sampler in Python:
import numpy as np
from scipy.stats import norm
n = 10 # number of underlying stocks in the arithmetic basket call
s = 100 # initial stock prices
K = 90 # strike price
sigma = 0.2 # volatility of the stocks
rho = 0.4 # correlations between the stocks
r = 0.01 # risk free interest rate (continuously compounded)
T = 1 # time to maturity (years)
mu = (np.log(s) + (r - 0.5*sigma**2)*T)*np.ones(n) # expected value vector of the log stock prices
# covariance matrix for the log stock prices
cov_mat = (rho*sigma**2)*np.ones((n,n))
cov_mat = cov_mat - np.diag(np.diag(cov_mat)) + np.diag((sigma**2)*np.ones(n))
cov_mat = cov_mat*T
N = 100000 # size of the Monte Carlo sample
# generate Monte Carlo sample
mc = np.random.multivariate_normal(mu, cov_mat, N) # log stock prices
mc = np.exp(mc) # stock prices
mc = np.mean(mc, 1) # arithmeric mean of the stock prices
mc = np.exp(-r*T)*np.maximum(mc - K, 0) # option prices
price = np.mean(mc) # estimated price
# confidence interval
price_std = np.std(mc) / np.sqrt(N) # standard deviation of the price estimator
lo = price - norm.ppf(0.975)*price_std # lower bound of confidence interval for the price
hi = price + norm.ppf(0.975)*price_std # upper bound of confidence interval for the price
Running a simulation (with ) gives us the following price estimate and 95% confidence interval for the Monte Carlo estimated price:
As mentioned in the first post, we will get different values if we were to repeat the simulations. So if you try and implement this by yourself you would not get exactly the same values, but they should however be very similar.
When comparing actual options prices on various financial markets with the prices given by the standard Black & Scholes model, it becomes clear that they generally do not match very well. The standard Black & Scholes model is just not complex enough to explain the stock's price process. There are several adjustments one could make to get a better model. One major drawback of the standard Black & Scholes model is that the stock volatility is constant and deterministic, while the actual stock volatility is a stochastic process just like the stock's price process. We will therefore now look at a model with stochastic stock volatility, namely the Heston model.
In the Heston model, we have dynamics given as stochastic differential equations, for both the stock and the volatility. These dynamics looks as follows:
where is the stock's price process as before, and is the stock's volatility process. and are here two independent standard Brownian Motions. Also, is the risk free interest rate, and , , and are model parameters.
We return to the European call option that we saw in the introductory post. As you might remember, this means that we want to find the option price:
In the standard Black & Scholes model we could find an explicit formula for this price. In the Heston model however, this is not the case. The reason is that we cannot find a closed form solution to the system of stochastic differential equations for and above. We will therefore need numerical methods and Monte Carlo simulations to generate a sample of stock prices that we can use to estimate the option price.
So we cannot solve these stochastic differential equations analytically, and will instead rely on numerical methods. As always when dealing with continuous functions in numerical analysis, we are going to use some kind of discretization scheme to solve these equations. This means that instead of dealing with this as a continuous problem over the interval , we are reducing this continuous interval to discrete time points where we have that and . We will then, using some discretization scheme, calculating the values of and at these time points only.
We start with the differential equation for . We will here use something called the Euler Scheme. For a stochastic differential equation on the form:
where and are functions, the Euler scheme is:
for , where is the size of each time step and is the increment of the standard Brownian Motion. Comparing with the equation for , the Euler scheme in this case becomes:
for . Note that the stochastic part here are the s, so the Monte Carlo aspect will be to simulate these normal random variables. Doing this scheme times, we will have a Monte Carlo sample of size of the stock prices . We must of course simulate the process for as well. To ensure that the s take on only positive values, we add another term to the discretization scheme. We will not go into details here but this is called the Milstein scheme (this extra term can be seen in the code in the end). If you are interested you can check out the Wikipedia page.
So, we have the following Monte Carlo sampler for estimating the price of the European call option:
We assume that the initial stock price is , the initial volatility is , the strike price , the risk free interest rate and the time to maturity is year. Also, we assume that our model parameters have the values , , and . Then, using time steps in the discretization (typically 252 trading days on a year, so daily time steps as year), we can implement the following Monte Carlo sampler in Python:
import numpy as np
from scipy.stats import norm
n = 10 # number of underlying stocks in the arithmetic basket call
s = 100 # initial stock prices
K = 90 # strike price
sigma = 0.2 # volatility of the stocks
rho = 0.4 # correlations between the stocks
r = 0.01 # risk free interest rate (continuously compounded)
T = 1 # time to maturity (years)
mu = (np.log(s) + (r - 0.5*sigma**2)*T)*np.ones(n) # expected value vector of the log stock prices
# covariance matrix for the log stock prices
cov_mat = (rho*sigma**2)*np.ones((n,n))
cov_mat = cov_mat - np.diag(np.diag(cov_mat)) + np.diag((sigma**2)*np.ones(n))
cov_mat = cov_mat*T
N = 100000 # size of the Monte Carlo sample
# generate Monte Carlo sample
mc = np.random.multivariate_normal(mu, cov_mat, N) # log stock prices
mc = np.exp(mc) # stock prices
mc = np.mean(mc, 1) # arithmeric mean of the stock prices
mc = np.exp(-r*T)*np.maximum(mc - K, 0) # option prices
price = np.mean(mc) # estimated price
# confidence interval
price_std = np.std(mc) / np.sqrt(N) # standard deviation of the price estimator
lo = price - norm.ppf(0.975)*price_std # lower bound of confidence interval for the price
hi = price + norm.ppf(0.975)*price_std # upper bound of confidence interval for the price
Running a simulation (with ) gives us the following price estimate and 95% confidence interval for the Monte Carlo estimated price:
In this blogpost, we made use of the concepts introduced in Introduction to Monte Carlo simulations and option pricing to price two quite tricky financial options using Monte Carlo simulations: the arithmeric basket call option in the standard Black & Scholes model, and the European call option in the Heston model. To summarize the highlights, we have:
Introduced the arithmetic basket call option
Looked at an example of how we can simulate using multivariate distributions
Introduced the Heston model for stocks
Introduced discretization and the Euler scheme for solving stochastic differential equations
Seen two examples of Monte Carlo samplers for estimating expected values
Published on February 11th 2020
Last updated on March 1st 2023, 10:53
Fredrik Olsson
Data Scientist