#!/usr/bin/env python
# coding: utf-8
#
#
# # Binomial Pricing Model
# ### [(Go to Quant Lab)](https://israeldi.github.io/quantlab/)
#
# #### Source: Numerical Methods in Finance with C++
#
# © Maciej J. Capinski, Tomasz Zastawniak
#
#
# ## Table of Contents
#
# 1. [Random Numbers](#1.-Random-Numbers)
# 2. [Plotting Random Samples](#2.-Plotting-Random-Samples)
# 3. [Simulation](#3.-Simulation)
# - 3.1 [Random Variables](#3.1-Random-Variables)
# - 3.2 [Stochastic Processes](#3.2-Stochastic-Processes)
# - 3.2.1 [Geometric Brownian Motion](#3.2.1-Geometric-Brownian-Motion)
# - 3.2.2 [Square-Root Diffusion](#3.2.2-Square-Root-Diffusion)
# - 3.2.3 [Stochastic Processes](#3.2-Stochastic-Processes)
# - 3.2.4 [Stochastic Processes](#3.2-Stochastic-Processes)
# - 3.3 [Variance Reduction](#3.3-Variance-Reduction)
# 4. [Valuation](#4.-Valuation)
# - 4.1 [European Options](#4.1-European-Options)
# - 4.2 [American Options](#4.2-American-Options)
# 5. [Risk Measures](#5.-Risk-Measures)
# - 5.1 [Value-at-Risk](#5.1-Value-at-Risk)
# - 5.2 [Credit Value Adjustments](#5.2-Credit-Value-Adjustments)
#
# Initially import all the modules we will be using for our notebook
# In[2]:
import math
import numpy as np
import numpy.random as npr
# from pylab import plt, mpl
import sys
import os
# ## 1.1 Creating Main Program
# In[2]:
if __name__== "__main__":
print("Hi there")
input("Provide a character: ")
# In[3]:
# Directory where we will save our plots
directory = "./images"
if not os.path.exists(directory):
os.makedirs(directory)
# ## 1.2 Entering Data
# #### ([Back to Top](#Table-of-Contents))
# In[4]:
if __name__== "__main__":
S0 = float(input("Enter S_0: "))
U = float(input("Enter U: "))
D = float(input("Enter D: "))
R = float(input("Enter R: "))
# making sure that 0= U or R <= D):
print("Arbitrage exists")
print("Terminating program")
sys.exit()
print("Input data checked")
print("There is no arbitrage\n")
# compute risk-neutral probability
print("q = ", (R - D) / (U - D))
# compute stock price at node n=3,i=2
n = 3; i = 2
print("n = ", n)
print("i = ", i)
print("S(n,i) = ", S0* math.pow(1 + U,i) * math.pow(1 + D, n - i))
# ## 1.3 Functions
# #### ([Back to Top](#Table-of-Contents))
# In[5]:
# computing risk-neutral probability
def RiskNeutProb(U, D, R):
return (R - D) / (U - D)
# computing the stock price at node n,i
def S(S0, U, D, n, i):
return S0 * math.pow(1 + U,i) * math.pow(1 + D, n - i)
def isValidInput(S0, U, D, R):
# making sure that 0= U or R <= D):
print("Arbitrage exists")
print("Terminating program")
return 0
return 1
# inputting, displaying and checking model data
def GetInputData():
#entering data
params = ("S0", "U", "D", "R")
S0, U, D, R = [float(input("Enter %s: " % (var))) for var in params]
if not isValidInput(S0, U, D, R):
return 0
print("Input data checked")
print("There is no arbitrage\n")
d = locals().copy()
return d
if __name__== "__main__":
# compute risk-neutral probability
print("q = ", RiskNeutProb(U, D, R))
output = GetInputData()
if output == 0:
sys.exit()
# Update our parameters
locals().update(output)
# compute stock price at node n=3,i=2
n = 3; i = 2
print("n = ", n)
print("i = ", i)
print("S(n,i) = ", S(S0,U,D,n,i))
# ## 2.0 Object Oriented European and American
# #### ([Back to Top](#Table-of-Contents))
# In[4]:
# Binomial Model (Parent class) ---------------------------------------------------
class BinModel:
def __init__(self, S0=100, U=0.1, D=-0.1, R=0):
self.S0 = S0
self.U = U
self.D = D
self.R = R
def RiskNeutProb(self):
return (self.R - self.D) / (self.U - self.D)
def S(self, n, i):
return self.S0 * math.pow(1 + self.U, i) * math.pow(1 + self.D, n - i)
# European Option class ------------------------------------------------------------------
class EurOption():
def PriceByCRR(self, Model, N=3):
q = Model.RiskNeutProb();
Price = np.zeros(N + 1)
for i in range(0, N + 1):
Price[i] = self.Payoff(Model.S(N, i))
for n in range(N - 1, -1, -1):
for i in range(0, n + 1):
Price[i] = (q * Price[i+1] + (1 - q) * Price[i]) / (1 + Model.R);
return Price[0]
# American Option class
class AmOption():
def PriceBySnell(self, Model, N=3):
q=Model.RiskNeutProb()
Price = np.zeros(N + 1)
for i in range(0, N + 1):
Price[i] = self.Payoff(Model.S(N, i))
for n in range(N - 1, -1, -1):
for i in range(0, n + 1):
ContVal = (q * Price[i+1] + (1 - q) * Price[i]) / (1 + Model.R)
Price[i] = self.Payoff(Model.S(n,i))
if (ContVal > Price[i]):
Price[i] = ContVal
return Price[0]
class AsianOption()
def PriceAsian(self, Model, N=3):
q = Model.RiskNeutProb();
Price = np.zeros(N + 1)
for i in range(0, 2 * N + 1):
Price[i] = self.Payoff(Model.S(N, i))
for n in range(N - 1, -1, -1):
for i in range(0, n + 1):
Price[i] = (q * Price[i+1] + (1 - q) * Price[i]) / (1 + Model.R);
return Price[0]
# Payoff Classes ----------------------------------------------------------------------------
class Call(EurOption, AmOption):
def __init__(self, K=1):
self.K = K
def Payoff(self, z):
if (z > self.K):
return z - self.K
return 0
class Put(EurOption, AmOption):
def __init__(self, K=1):
self.K = K
def Payoff(self, z):
if (z < self.K):
return self.K - z
return 0
class Digital_Call(EurOption, AmOption):
def __init__(self, K=1):
self.K = K
def Payoff(self, z):
if self.K < z:
return 1
return 0
class BullSpread(EurOption, AmOption):
def __init__(self, K1=1, K2 = 2):
self.K1 = K1
self.K2 = K2
def Payoff
model = BinModel(S0=10, U=0.2, D=-0.1, R=0.1)
Option1 = Digital_Call(K=22)
Option1.PriceByCRR(model, N=6)
# ## Exercises:
#
# 1. Modify the `PriceByCRR()` function in `EurOption` Class to compute the time $0$ price of a European option using the **Cox–Ross–Rubinstein (CRR)** formula:
# $$H(0)=\frac{1}{(1+R)^{N}}\sum_{i=0}^{N}\frac{N!}{i!(N-i)!}q^{i}(1-q)^{N-i}h(S(N,I))$$
#
#
# 2. The payoff of a **digital call** with strike price $K$ is:
# $$h^{digit\thinspace call}(z)=\begin{cases}
# 1 & \textrm{{if} }K