Roi Polanitzer
·
Follow
12 min read
·
Oct 23, 2021

“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 BlackScholes 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 nondividend paying stock.
The respective call and put values are:
Where S is the stock price, X is the strike price, r is the riskfree rate, (Tt) is the time to maturity and N(x) is the cumulative normal distribution of:
Where d2 can be simplified to the following:
Where d2 can be simplified to the following:
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 BlackScholes 1973 model: “BlackScholes”.
import numpy as np
import scipy.stats as sidef 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)+(RiskFreeRate0.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)+(RiskFreeRate0.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 10year maturity. The annualized riskfree 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.50roi1 = PolanitzerBlackScholesCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, Volatility)
print("The fair value of the European call option based on the BlackScholes Model is: ${:.5}".format(roi1))
roi2 = PolanitzerBlackScholesPut(StockPrice, StrikePrice, Maturity, RiskFreeRate, Volatility)
print("The fair value of the European put option based on the BlackScholes Model is: ${:.5}".format(roi2))
The fair value of the European call option based on the BlackScholes Model is: $67.316
The fair value of the European put option based on the BlackScholes 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 BlackScholes model to incorporate a known annual dividend yield (q). His model follows the same foundations of the basic BlackScholes model and the value of a call and put option is given as follows:
d1 and d2 are modified to:
Where d2 can again be simplified to:
Let’s write the corresponding valuation functions in Python. I call the Merton 1973 model: “Generalized BlackScholes”.
import numpy as np
import scipy.stats as sidef 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)+(RiskFreeRateDividendYield+0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
d2 = (np.log(StockPrice/StrikePrice)+(RiskFreeRateDividendYield0.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)+(RiskFreeRateDividendYield+0.5*Volatility**2)*Maturity)/(Volatility*np.sqrt(Maturity))
d2 = (np.log(StockPrice/StrikePrice)+(RiskFreeRateDividendYield0.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 10year maturity. The annualized riskfree 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.50roi3 = PolanitzerGeneralizedBlackScholesCall(StockPrice, StrikePrice, Maturity, RiskFreeRate, DividendYield, Volatility)
print("The fair value of the European call option based on the Generalized BlackScholes 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 BlackScholes Model is: ${:.5}".format(roi4))
The fair value of the European call option based on the Generalized BlackScholes Model is: $67.316
The fair value of the European put option based on the Generalized BlackScholes 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 BlackScholes 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:
for an up movement, and:
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:
We then need to assign a probability of the asset moving higher (i.e., increasing) as:
and for the probability of a down movement, the combined probabilities must equal to 1, hence the probability of the down movement is simply (1p).
An illustration of how the binomial tree works is shown below:
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:
and
j is given by the following condition:
Where Φ represents the next nonnegative 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 BlackScholes 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 BlackScholes value.
Call Option: Stock Price: 100, Strike Price: 102, Volatility: 20%, Dividend Yield: 5%, Risk Free:
At the 200th time node for the binomial method, we get a call value of 8.0369. Under the BlackScholes 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((RiskFreeRateDividendYield)*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**(BinomialStepsm))StrikePrice, 0)
for k in range(BinomialSteps1, 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((RiskFreeRateDividendYield)*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**(BinomialStepsm)), 0)
for k in range(BinomialSteps1, 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 10year maturity. The annualized riskfree 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 = 1000roi5 = 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,000Steps is: $67.305
The fair value of the European put option based on the Binomial Model with 1,000Steps 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:
The probabilities can also be represented as:
and hence:
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%
Transposing the two lines together, it is clear that the trinomial method converges much more rapidly than the binomial method.
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((RiskFreeRateDividendYield)*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(mTrinomialSteps,0)))*(Down**(max(TrinomialSteps*2TrinomialStepsm,0)))) StrikePrice, 0)
for k in range(TrinomialSteps1, 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((RiskFreeRateDividendYield)*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(mTrinomialSteps,0)))*(Down**(max(TrinomialSteps*2TrinomialStepsm,0)))), 0)
for k in range(TrinomialSteps1, 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 10year maturity. The annualized riskfree 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 = 500roi7 = 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 500Steps is: $67.305
The fair value of the European put option based on the Trinomial Model with 500Steps 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.
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 publiclytraded and privatelyheld 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 BlackScholes 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.

Financial Options and BlackScholes 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 BlackScholes model is a widely used mathematical model for pricing Europeanstyle options.
 The formula for the call option value (C) and put option value (P) in the BlackScholes model is given by: [ C = S \cdot N(d1)  X \cdot e^{r(Tt)} \cdot N(d2) ] [ P = X \cdot e^{r(Tt)} \cdot N(d2)  S \cdot N(d1) ]

Implementation in Python:
 The article provides Python functions for calculating the fair value of European call and put options based on the BlackScholes model.
 The functions use the cumulative normal distribution function (
PolanitzerNormsdist
) and the BlackScholes formula.

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.

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

Binomial Model:
 The binomial method is introduced as a common method for pricing options, related to the BlackScholes 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 BlackScholes value with a significant number of time nodes.

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.

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.

Evaluation of Models:
 The article concludes with the evaluation of different models (BlackScholes, 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.