Monte Carlo Pricing in Python
Time Value of Money
Money is valued differently over time. What does that mean specifically? If someone were to offer you the option of receiving $100 today, or $100 a year from today — which would you prefer? Naturally, most would prefer to receive the $100 as soon as possible (today). Intuitively, this can be translated to understanding the time value of money. As a cash flow gets further away in the future, the less value it has. The same concept can be extended to comparing the values of the cash flows at different points in time. Intuitively, we would prefer to receive $100 a year from today rather than two years from today. Mathematically, the culprit for the temporal difference in the value of money is a risk-free rate of interest. The sooner money is received the sooner interest can be earned. This is how different sums of money can be compared at different times — that is by finding the present value of the cash flows and comparing them. Consider the following mutually exclusive choices:
Assume the annual risk-free rate of interest is 1%.
- Receive $100 Today
- Receive $102 One Year from Today
Which should you choose?
To determine which cash flow to receive we can discount the $102 at the risk-free rate to find the value of the $102 in today’s dollars.
Present Value of Receiving $100 Today
- 100/(1.01)⁰ = $100
Present Value of Receiving $102 One Year from Today
- 102/(1.01)¹ = $101
In today’s dollars, Choice A is worth $100 where Choice B is worth $101. Since Choice B has a higher present value it means Choice B is worth more than Choice A today. This may seem a simple concept, but especially when valuing more complicated securities it becomes essential to remember this temporal value difference.
In general, the market price of any security should represent the present value of all future cash flows generated by that security. Consider the following investment vehicle:
- Pays $100 at the end of year 1
- Pays $100 at the end of year 2
- Pays $100 at the end of year 3
How much should you be willing to pay for Security A? Well, now that we know money is valued differently at different points in time we can use an appropriate risk-free rate to discount the value of each cash flow to the current point in time to determine the price of the security. Assuming the annual risk-free rate of return is 1% we can discount each of the payments to the present.
First Year’s Payment in Today’s Dollars
- 100/(1.01) = 99.01
Second Year’s Payment in Today’s Dollars
- 100/(1.01)² = 98.03
Third Year’s Payment in Today’s Dollars
- 100/(1.01)³ = 97.06
Sum of the Present Value of Future Cash Flows
- $97.06 + $98.03 + $99.01 = $294.10
Therefore, the appropriate value of Security A today is $294.10. We can generalize this concept to find the fair value for any security, regardless of how unique or exotic their payoff structure. Later on in this article, we are going to be analyzing derivatives with unique payoff structures. However, using this notion of the present value of future cash flows we can find the appropriate price of said securities today (more specifically, the expected present value of future cash flows today). In order to do so, we are going to need a method of modeling stochastic movements in the underlying asset.
Geometric Brownian Motion
Before we can model the price of derivative securities whose value depends on an underlying equity — we need to model the underlying equity. Geometric Brownian motion is a stochastic process that can be used to generate sample paths that the underlying equity may follow. In other words, we can use geometric Brownian motion to simulate stock prices.
- Yt — Stock price at time t
- dYt — Change in stock price from time t
- μ — Drift term
- σ — Volatility term
- dt — Change in time
- dWt — Brownian motion
There appear to be many components to geometric Brownian motion, but there are essentially three components: the return (dYt/Yt), the expected return (μdt), and the shocks to the return (σdWt). We can model geometric Brownian motion in Python very easily using the following code.
When using geometric Brownian motion to model an equity we only need to provide a few parameters: initial stock price, drift (expected return) of the equity for time period T, volatility of the equity for time period T, the length of the time steps dt, and the total time we are generating to T. In the code above we use the following parameter set…
- Initial Price — 100
- Drift — 8% (expected return)
- Volatility — 10% (expected shock to return)
- Time Steps (dt) — 1/365 (daily)
- Total Time (T) — 1 (one year)
If using geometric Brownian motion to generate sample paths for a real equity, there are a few ways you can go about finding drift and volatility. Generally, I use the average historical return for the time period T I am generating for, and volatility I use the implied volatility (see What is Implied Volatility?) for an at the money option. After running the code above we end up generating 100 sample paths that can be plotted using matplotlib.
Now that we have a means of generating sample paths of the underlying asset, we can talk about derivatives pricing.
The infamous Black-Scholes model is used to price European style options. However, the overall theme of pricing remains the same. The way in which Black-Scholes came up with this pricing model follows a risk-neutral expectation. Essentially, they find the risk-neutral expected value (see Deriving the Black-Scholes Model) of the option which determines the fair value today. This is no different to how we priced Security A in the Securities Pricing section above. There are some drawbacks to this model in the form of strong assumptions made about a market environment…
- No Transaction Costs
- Continuous Trading
- Lognormally Distributed Stock Returns
In practice, these assumptions are immediately violated as transaction costs exist, trading can only be preformed discretely, and stock returns empirically show they are not lognormally distributed. My stream of research focuses on taking into account generic market conditions like transaction costs and discrete trading in the Black-Scholes equation by making mathematical modifications (if interested see Option Pricing and Replication under Generic Market Conditions). Nevertheless, the Black-Scholes price offers a baseline we can check against our Monte Carlo price. The Black-Scholes equation is as follows…
- St — Stock price at time t
- X — Strike price of the option
- σ — Volatility term
- Φ — Cumulative normal distribution function
- B(t,T) — Continuous discount factor
- T — Time until maturity
- t — Current point in time
If the equation above isn’t immediately clear don’t worry — the implementation in Python is much easier to understand (if you wish to see more of a mathematical explanation without the full derivation see Risk-Neutral Portfolio Management).
12.368267463784072 # Price of the European call option by BS Model
Monte Carlo Pricing
We now have everything we need to start Monte Carlo pricing. Recall how the value of a security today should represent all future cash flows generated by that security. Well, in the case of financial derivatives, we don’t know the future value of their cash flows. However, we do know the possible outcomes. With knowing the possible outcomes we can find the expected present value of all future cash flows. Allow me to elaborate with an example…
In the case of a European call option, it will either expire in the money (exercise) or out of the money (do nothing). Let’s build a model of this payoff structure in Python.
Now we can use this payoff model in our code for generating underlying equity paths to find the value of the option at the end of each sample path. Then we can discount the value to the present (remember the time value of money!), and average all the values to find the expected present value of future cash flows generated by the option.
16.31698913180365 # Monte Carlo Price of the European Call Option
Considering the sample size of our generated paths (and arbitrary parameter set) we are very close to the Black-Scholes price! Its worthwhile to note that neither price is more correct, they just tell us different things. Understanding how each price is generated will aid in interpretation.
This same process can be used to price any security where there is uncertainty in the payoff. Let’s look at a more exotic option…
Up and Out Barrier Option
- Strike price and payoff similar to a European Call
- Barrier level in which the option can no longer be exercised
With an up and out barrier option, if the barrier level is triggered it doesn’t matter whether or not the option expires in the money — it becomes unexercisable. We can once again model this payoff structure very easily in Python.
The only difference between this barrier option and a European option (in implementation) is that th barrier option requires the observance of each price tick to determine if the barrier has been breached.
9.08694137422691 # Monte Carlo Price of Up and Out Barrier Option
This is the Monte Carlo price of the Up and Out Barrier Option. Logically, this makes sense as the extra constraint on the European option (a barrier level) doesn’t add to the payoff, or increase payoff potential (it actually hinders it). Therefore we should pay less for this option, as shown by the Monte Carlo price. The beauty in this pricing methodology is the ability to develop exotic products for clients that precisely suit their needs. Though it may be a crude example, if a client wants to hedge their exposure in an equity position by purchasing call options, but they do not believe the underlying asset will rise past a certain point we can price an Up and Out Barrier Option for their situation and decrease their hedging cost.