#!/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