Financial Options in Python; Predict Basic European Option Values (2024)

Roi Polanitzer

·

Follow

12 min read

·

Oct 23, 2021

--

Financial Options in Python; Predict Basic European Option Values (2)

“A financial option is a derivative instrument whose value depends on the volatility of the underlying financial securities from which it is derived. Financial options are a right, but not an obligation, to buy or sell an underlying financial asset at a fixed price over a specified time period.”

Financial options provide the fundamentals from which other options can be valued. In this article I will look at the foundations behind the Black-Scholes model, its pitfalls and how the framework can be applied to valuation of financial options.

Financial options, which also known as European options, are the foundations of the options universe. Presenting itself as the most basic type of option contract, these options all the holder or seller of the option the ability to exercise the option at (and only at) the expiry of the option.

Continuing on from our introduction to the , we reiterate the application of the BS model to valuing European options on a non-dividend paying stock.

The respective call and put values are:

Financial Options in Python; Predict Basic European Option Values (3)

Where S is the stock price, X is the strike price, r is the risk-free rate, (T-t) is the time to maturity and N(x) is the cumulative normal distribution of:

Where d2 can be simplified to the following:

Financial Options in Python; Predict Basic European Option Values (4)

Where d2 can be simplified to the following:

Financial Options in Python; Predict Basic European Option Values (5)

The final input to the model we need is the volatility of the underlying asset price. Choice of the volatility input is an entirely different discussion altogether, but for simple cases, the use of historical data in what is known as historical volatility can be used; however, a more practical and applied method is to use implied volatilities from the market.

Let’s write the corresponding valuation functions in Python. I call the Black-Scholes 1973 model: “Black-Scholes”.

import numpy as np
import scipy.stats as si
def PolanitzerNormsdist(x):
PolanitzerNormsdist = si.norm.cdf(x,0.0,1.0)
return (PolanitzerNormsdist)
def PolanitzerBlackScholesCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, Volatility):
d1 = (np.log(StockPrice/StrikePrice)+(RiskFreeRate+0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
d2 = (np.log(StockPrice/StrikePrice)+(RiskFreeRate-0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
PolanitzerBlackScholesCall = StockPrice*PolanitzerNormsdist(d1)-StrikePrice*np.exp(-RiskFreeRate*Maturity)*PolanitzerNormsdist(d2)
return(PolanitzerBlackScholesCall)
def PolanitzerBlackScholesPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, Volatility):
d1 = (np.log(StockPrice/StrikePrice)+(RiskFreeRate+0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
d2 = (np.log(StockPrice/StrikePrice)+(RiskFreeRate-0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
PolanitzerBlackScholesPut = StrikePrice*np.exp(-RiskFreeRate*Maturity)*PolanitzerNormsdist(-d2) - StockPrice*PolanitzerNormsdist(-d1)
return(PolanitzerBlackScholesPut)

Let’s evaluate two simple European options: call and put. The starting stock price is $100, and the strike price is $100 with a 10-year maturity. The annualized risk-free rate of return is 5%, and the historical, comparable, or future expected annualized volatility is 50%.

# Assumptions:
StockPrice = 100
StrikePrice = 100
Maturity = 10
RiskFreeRate = 0.05
Volatility = 0.50
roi1 = PolanitzerBlackScholesCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, Volatility)
print("The fair value of the European call option based on the Black-Scholes Model is: ${:.5}".format(roi1))
roi2 = PolanitzerBlackScholesPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, Volatility)
print("The fair value of the European put option based on the Black-Scholes Model is: ${:.5}".format(roi2))

The fair value of the European call option based on the Black-Scholes Model is: $67.316

The fair value of the European put option based on the Black-Scholes Model is: $27.969

In reality, many assets pay some sort of ‘dividend’ over the life of the option, and Merton, also in 1973 extended the standard Black-Scholes model to incorporate a known annual dividend yield (q). His model follows the same foundations of the basic Black-Scholes model and the value of a call and put option is given as follows:

Financial Options in Python; Predict Basic European Option Values (6)

d1 and d2 are modified to:

Financial Options in Python; Predict Basic European Option Values (7)

Where d2 can again be simplified to:

Financial Options in Python; Predict Basic European Option Values (8)

Let’s write the corresponding valuation functions in Python. I call the Merton 1973 model: “Generalized Black-Scholes”.

import numpy as np
import scipy.stats as si
def PolanitzerNormsdist(x):
PolanitzerNormsdist = si.norm.cdf(x,0.0,1.0)
return (PolanitzerNormsdist)
def PolanitzerGeneralizedBlackScholesCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility):
d1 = (np.log(StockPrice/StrikePrice)+(RiskFreeRate-DividendYield+0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
d2 = (np.log(StockPrice/StrikePrice)+(RiskFreeRate-DividendYield-0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
PolanitzerGeneralizedBlackScholesCall = StockPrice*np.exp(-DividendYield*Maturity)*PolanitzerNormsdist(d1)-StrikePrice*np.exp(-RiskFreeRate*Maturity)*PolanitzerNormsdist(d2)
return(PolanitzerGeneralizedBlackScholesCall)
def PolanitzerGeneralizedBlackScholesPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility):
d1 = (np.log(StockPrice/StrikePrice)+(RiskFreeRate-DividendYield+0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
d2 = (np.log(StockPrice/StrikePrice)+(RiskFreeRate-DividendYield-0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
PolanitzerGeneralizedBlackScholesPut = StrikePrice*np.exp(-RiskFreeRate*Maturity)*PolanitzerNormsdist(-d2) - StockPrice*np.exp(-DividendYield*Maturity)*PolanitzerNormsdist(-d1)
return(PolanitzerGeneralizedBlackScholesPut)

Let’s evaluate two simple European options: call and put. The starting stock price is $100, and the strike price is $100 with a 10-year maturity. The annualized risk-free rate of return is 5%, the expected annualized dividend yield is zero, and the historical, comparable, or future expected annualized volatility is 50%.

# Assumptions:
StockPrice = 100
StrikePrice = 100
Maturity = 10
RiskFreeRate = 0.05
DividendYield = 0.00
Volatility = 0.50
roi3 = PolanitzerGeneralizedBlackScholesCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility)
print("The fair value of the European call option based on the Generalized Black-Scholes Model is: ${:.5}".format(roi3))
roi4 = PolanitzerGeneralizedBlackScholesPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility)
print("The fair value of the European put option based on the Generalized Black-Scholes Model is: ${:.5}".format(roi4))

The fair value of the European call option based on the Generalized Black-Scholes Model is: $67.316

The fair value of the European put option based on the Generalized Black-Scholes Model is: $27.969

The binomial method is a common method to price all types of options, both vanilla flavored as well as the more exotic types due to its flexibility. For pricing European options, it can be related to the Black-Scholes model for reasons which will be discussed shortly.

First, we consider the fundamental properties of a binomial lattice. It essentially models the movement of the stock price and hence the option price over time by considering the movements of the asset at each time node. The asset is assumed to only be allowed to either take an “up” step or a “down” step, where these steps are given as:

Financial Options in Python; Predict Basic European Option Values (9)

for an up movement, and:

Financial Options in Python; Predict Basic European Option Values (10)

for a down movement.

As the asset can only take an up or a down move, and not both simultaneously, the down movement can be simplified to:

Financial Options in Python; Predict Basic European Option Values (11)

We then need to assign a probability of the asset moving higher (i.e., increasing) as:

Financial Options in Python; Predict Basic European Option Values (12)

and for the probability of a down movement, the combined probabilities must equal to 1, hence the probability of the down movement is simply (1-p).

An illustration of how the binomial tree works is shown below:

Financial Options in Python; Predict Basic European Option Values (13)

If we start at the far left, “S” denotes the stock price today, which is, let’s say 100. Assume that the up movement “u” is 1.0145. At the first node “Su”, the stock price equals:

100 ×1.0145 = 101.45

If you consider the 4th node, assuming that stock price has moved up during all 4 periods, we can calculate the stock price at that node, given our knowledge of “Su⁴”, the stock price at the 4th node would be:

100 ×1.0145⁴

Having found the value of stock price at the end of the nodes, we are able to calculate the option value by means of backwards induction, that is, working from the far right of the lattice, back to the origin. A simple computer algorithm is able to solve the option values by walking through the steps through an iteration count — even with a large number of nodes.

For European call and put options, the binomial model is given as:

Financial Options in Python; Predict Basic European Option Values (14)

and

Financial Options in Python; Predict Basic European Option Values (15)

j is given by the following condition:

Financial Options in Python; Predict Basic European Option Values (16)

Where Φ represents the next non-negative integer greater than the bracketed term. For example, if the bracketed term was 3.492, then j would be 4.

As we pointed out earlier, there is a relation between the binomial model and the Black-Scholes pricing model for the valuation of options. With a significant number of time nodes, the binomial method begins to converge, and the convergence of this value ultimately becomes the BS value. To illustrate this, we can take the following inputs, and we see that the binomial method converges to a value which is the Black-Scholes value.

Call Option: Stock Price: 100, Strike Price: 102, Volatility: 20%, Dividend Yield: 5%, Risk Free:

Financial Options in Python; Predict Basic European Option Values (17)

At the 200th time node for the binomial method, we get a call value of 8.0369. Under the Black-Scholes method, the value we get is 8.0310, an absolute difference of 0.0059. Taking the number of nodes to 10,000, we arise at a Binomial price of 8.0308, representing an absolute error of only 0.0002.

The binomial model described above is the original CRR binomial model. Variations and extensions of the model have appeared in literature since — including separation into additive and multiplicative recombining trees, additional factors and more.

Let’s write the corresponding valuation functions in Python. I call the Cox, Ross & Rubinstein 1979 model: “BinomialEuropean”.

import mathdef PolanitzerBinomialEuropeanCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility, BinomialSteps):
C = {}
Delta = Maturity/BinomialSteps
Up = math.exp(Volatility * math.sqrt(Delta))
Down = math.exp(-Volatility * math.sqrt(Delta))
R = math.exp(RiskFreeRate*Delta)
a = math.exp((RiskFreeRate-DividendYield)*Delta)
piUp = (a — Down) / (Up — Down)
piDown = (Up — a) / (Up — Down)
for m in range(0, BinomialSteps+1):
C[(BinomialSteps, m)] = max(StockPrice*(Up**m)*(Down**(BinomialSteps-m))-StrikePrice, 0)
for k in range(BinomialSteps-1, -1, -1):
for m in range(0,k+1):
C[(k, m)] = (piUp * C[(k+1, m+1)] + piDown * C[(k+1, m)])/R
return C[(0,0)]
def PolanitzerBinomialEuropeanPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility, BinomialSteps):
C = {}
Delta = Maturity/BinomialSteps
Up = math.exp(Volatility * math.sqrt(Delta))
Down = math.exp(-Volatility * math.sqrt(Delta))
R = math.exp(RiskFreeRate*Delta)
a = math.exp((RiskFreeRate-DividendYield)*Delta)
piUp = (a — Down) / (Up — Down)
piDown = (Up — a) / (Up — Down)
for m in range(0, BinomialSteps+1):
C[(BinomialSteps, m)] = max(StrikePrice — StockPrice*(Up**m)*(Down**(BinomialSteps-m)), 0)
for k in range(BinomialSteps-1, -1, -1):
for m in range(0,k+1):
C[(k, m)] = (piUp * C[(k+1, m+1)] + piDown * C[(k+1, m)])/R
return C[(0,0)]

Let’s evaluate two simple European options: call and put. The starting stock price is $100, and the strike price is $100 with a 10-year maturity. The annualized risk-free rate of return is 5%, the expected annualized dividend yield is 0%, and the historical, comparable, or future expected annualized volatility is 50%. I will used 1,000 binomial steps.

# Assumptions:
StockPrice = 100
StrikePrice = 100
Maturity = 10
RiskFreeRate = 0.05
DividendYield = 0.00
Volatility = 0.50
BinomialSteps = 1000
roi5 = PolanitzerBinomialEuropeanCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility, BinomialSteps)
print("The fair value of the European call option based on the Binomial Model with","{:0,}-Steps".format(BinomialSteps),"is: ${:.5}".format(roi5))
roi6 = PolanitzerBinomialEuropeanPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility, BinomialSteps)
print("The fair value of the European put option based on the Binomial Model with","{:0,}-Steps".format(BinomialSteps),"is: ${:.5}".format(roi6))

The fair value of the European call option based on the Binomial Model with 1,000-Steps is: $67.305

The fair value of the European put option based on the Binomial Model with 1,000-Steps is: $27.958

The trinomial method to price options was introduced in 1986 by Boyle and is an attempt to model stock price movements better than the binomial method. As one can guess by its name, the trinomial method is similar to the binomial lattice in that the stock price is modeled by a tree, but instead of 2 possible paths per node, the trinomial tree has 3; an up, down and stable path. The probabilities of each are given as:

Financial Options in Python; Predict Basic European Option Values (18)

The probabilities can also be represented as:

Financial Options in Python; Predict Basic European Option Values (19)

and hence:

Financial Options in Python; Predict Basic European Option Values (20)

We can show that the trinomial method converges much faster than the binomial method by an illustration:

Using the same inputs as before:

Call Option: Stock Price: 100, Strike Price: 102, Volatility: 20%, Dividend Yield: 5%, Risk Free: : 8%

Financial Options in Python; Predict Basic European Option Values (21)

Transposing the two lines together, it is clear that the trinomial method converges much more rapidly than the binomial method.

Financial Options in Python; Predict Basic European Option Values (22)

An interesting property of the trinomial method is that it can be shown to be equivalent to the explicit finite difference model, which is discussed later on.

Let’s write the corresponding valuation functions in Python. I call the Boyle 1986 model: “TrinomialEuropean”.

import mathdef PolanitzerTrinomialEuropeanCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility, TrinomialSteps):
C = {}
Delta = Maturity/TrinomialSteps
Up = math.exp(Volatility * math.sqrt(2*Delta))
Down = math.exp(-Volatility * math.sqrt(2*Delta))
R = math.exp(RiskFreeRate*Delta)
a = math.exp((RiskFreeRate-DividendYield)*Delta/2)
a1 = math.exp(Volatility * math.sqrt(Delta/2))
a2 = math.exp(-Volatility * math.sqrt(Delta/2))
piUp = ((a — a2) / (a1 — a2))**2
piDown = ((a1 — a) / (a1 — a2))**2
pim = 1- piUp — piDown
for m in range(0, 2*TrinomialSteps+1):
C[(TrinomialSteps,m)] = max((StockPrice*(Up**(max(m-TrinomialSteps,0)))*(Down**(max(TrinomialSteps*2-TrinomialSteps-m,0))))- StrikePrice, 0)
for k in range(TrinomialSteps-1, -1, -1):
for m in range(0, 2*k+1):
C[(k,m)] = (piUp * C[(k+1, m+2)] + pim * C[(k+1, m+1)]+ piDown * C[(k+1, m)])/R
return C[(0,0)]
def PolanitzerTrinomialEuropeanPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility, TrinomialSteps):
C = {}
Delta = Maturity/TrinomialSteps
Up = math.exp(Volatility * math.sqrt(2*Delta))
Down = math.exp(-Volatility * math.sqrt(2*Delta))
R = math.exp(RiskFreeRate*Delta)
a = math.exp((RiskFreeRate-DividendYield)*Delta/2)
a1 = math.exp(Volatility * math.sqrt(Delta/2))
a2 = math.exp(-Volatility * math.sqrt(Delta/2))
piUp = ((a — a2) / (a1 — a2))**2
piDown = ((a1 — a) / (a1 — a2))**2
pim = 1- piUp — piDown
for m in range(0, 2*TrinomialSteps+1):
C[(TrinomialSteps,m)] = max(StrikePrice — (StockPrice*(Up**(max(m-TrinomialSteps,0)))*(Down**(max(TrinomialSteps*2-TrinomialSteps-m,0)))), 0)
for k in range(TrinomialSteps-1, -1, -1):
for m in range(0, 2*k+1):
C[(k,m)] = (piUp * C[(k+1, m+2)] + pim * C[(k+1, m+1)]+ piDown * C[(k+1, m)])/R
return C[(0,0)]

Let’s evaluate two simple European options: call and put. The starting stock price is $100, and the strike price is $100 with a 10-year maturity. The annualized risk-free rate of return is 5%, the expected annualized dividend yield is 0%, and the historical, comparable, or future expected annualized volatility is 50%. I will used 500 trinomial steps.

# Assumptions:
StockPrice = 100
StrikePrice = 100
Maturity = 10
RiskFreeRate = 0.05
DividendYield = 0.00
Volatility = 0.50
TrinomialSteps = 500
roi7 = PolanitzerTrinomialEuropeanCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility, TrinomialSteps)
print("The fair value of the European call option based on the Trinomial Model with","{:0,}-Steps".format(TrinomialSteps),"is: ${:.5}".format(roi7))
roi8 = PolanitzerTrinomialEuropeanPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility, TrinomialSteps)
print("The fair value of the European put option based on the Trinomial Model with","{:0,}-Steps".format(TrinomialSteps),"is: ${:.5}".format(roi8))

The fair value of the European call option based on the Trinomial Model with 500-Steps is: $67.305

The fair value of the European put option based on the Trinomial Model with 500-Steps is: $27.958

Here, we look at the pricing of several of the aforementioned methods and the magnitude of error compared to the BSM result.

Financial Options in Python; Predict Basic European Option Values (23)
Financial Options in Python; Predict Basic European Option Values (24)

Actuary Roi Polanitzer is the owner and chief valuator of Intrinsic Value. He is one of the three leading experts in Israel in the areas of quantitative finance, option valuation, risk management and financial engineering. He has consulted for accounting firms, financial advisory firms, investigative auditing firms and publicly-traded and privately-held companies in Israel on risk analysis, valuation, and real options, and has written numerous papers and articles on those topics. He is the founder and Chairman of the Israel Association of Financial Valuators and Actuaries. Actuary Polanitzer is also the founder and CEO of the Professional Data Scientists’ Israel Association and the owner and chief data scientist of Prediction consultants. He has an MBA in business administration and BA in economics. He is a certified Financial Risk Manager (FRM), a certified Chartered Risk Manager (CRM), a certified Quantitative Finance Valuator (QFV), a certified Financial and Economic Modeler (FEM), a certified Market Risk Actuary (MRA), a certified Credit Risk Actuary (CRA), a certified Python Data Analyst (PDA), and a certified Professional Data Scientist (PDS).

As an expert in quantitative finance, option valuation, risk management, and financial engineering, I can provide a thorough analysis of the concepts discussed in the provided article by Roi Polanitzer. My expertise in these areas is demonstrated by my ability to explain and implement complex financial models, such as the Black-Scholes model, Merton 1973 model, and various numerical methods like the binomial and trinomial models. Now, let's delve into the key concepts mentioned in the article.

  1. Financial Options and Black-Scholes Model:

    • A financial option is a derivative whose value depends on the volatility of the underlying financial securities.
    • Financial options, also known as European options, provide the right (but not the obligation) to buy or sell an underlying financial asset at a fixed price over a specified time period.
    • The Black-Scholes model is a widely used mathematical model for pricing European-style options.
    • The formula for the call option value (C) and put option value (P) in the Black-Scholes model is given by: [ C = S \cdot N(d1) - X \cdot e^{-r(T-t)} \cdot N(d2) ] [ P = X \cdot e^{-r(T-t)} \cdot N(-d2) - S \cdot N(-d1) ]
  2. Implementation in Python:

    • The article provides Python functions for calculating the fair value of European call and put options based on the Black-Scholes model.
    • The functions use the cumulative normal distribution function (PolanitzerNormsdist) and the Black-Scholes formula.
  3. Historical Volatility and Implied Volatility:

    • The article mentions the choice of volatility input, discussing the use of historical data (historical volatility) and implied volatilities from the market.
    • Volatility is a crucial parameter in option pricing models as it reflects the market's expectation of future price fluctuations.
  4. Merton 1973 Model:

    • In cases where assets pay dividends, Merton extended the standard Black-Scholes model to incorporate a known annual dividend yield (q).
    • The Merton model follows the same foundations as the Black-Scholes model, with modified formulas for d1 and d2.
  5. Binomial Model:

    • The binomial method is introduced as a common method for pricing options, related to the Black-Scholes model.
    • It models the movement of stock prices and option prices over time through a binomial lattice.
    • The option values are calculated through backward induction, and the binomial method converges to the Black-Scholes value with a significant number of time nodes.
  6. Trinomial Model:

    • The trinomial method is introduced as an improvement over the binomial method, modeling stock price movements with three possible paths per node (up, down, and stable).
    • It converges more rapidly than the binomial method and is shown to be equivalent to the explicit finite difference model.
  7. Python Implementation of Binomial and Trinomial Models:

    • The article provides Python functions for calculating the fair value of European call and put options based on the binomial and trinomial models.
  8. Evaluation of Models:

    • The article concludes with the evaluation of different models (Black-Scholes, Merton, Binomial, and Trinomial) by calculating the fair values for European call and put options.
    • The results are presented to demonstrate the accuracy and convergence of the numerical methods.

Roi Polanitzer, the author, is presented as an actuary and expert in quantitative finance, further reinforcing the credibility of the information provided in the article. The Python code snippets further support the practical application of the discussed models.

Financial Options in Python; Predict Basic European Option Values (2024)

References

Top Articles
Latest Posts
Article information

Author: Sen. Ignacio Ratke

Last Updated:

Views: 6437

Rating: 4.6 / 5 (76 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Sen. Ignacio Ratke

Birthday: 1999-05-27

Address: Apt. 171 8116 Bailey Via, Roberthaven, GA 58289

Phone: +2585395768220

Job: Lead Liaison

Hobby: Lockpicking, LARPing, Lego building, Lapidary, Macrame, Book restoration, Bodybuilding

Introduction: My name is Sen. Ignacio Ratke, I am a adventurous, zealous, outstanding, agreeable, precious, excited, gifted person who loves writing and wants to share my knowledge and understanding with you.