期權定價

菜鳥問題 - 蒙地卡羅與 BAPM 歐洲期權定價差異

  • January 5, 2022

現在是寒假(新年快樂!),我正在嘗試實施一些期權定價模型(bapm、tapm、monte carlo、Fast Fourier 等)以供練習。

**問題:**我的 BAPM CRR 模型對於“ec”收斂到8.45544504853379,這與線上結果一致。我的 Monte Carlo 實現收斂到4.748831589623564 :(。我在程式碼中找不到錯誤…我希望有人能告訴我在使用 ~100k GBM 模擬時是否可能出現如此大的錯誤。

類型 =

$$ “ec”, “ep”, “ac”, “ap” $$(歐元看漲期權、歐元看跌期權等) 二項式資產定價模型

# Initial parameters
S0 = 100      # initial stock price
K = 100       # strike price
T = 1         # time to maturity in years
r = 0.06      # annual risk-free rate
N = 100         # number of time steps
sig = .13      # sigma - std of stock annualized 

import numpy as np
import matplotlib.pyplot as plt

class BAPM():
   def __init__(self, S0, K, T, N, r, c, sig) -> None:
       self.S0 = S0
       self.K = K
       self.T = T
       self.N = N
       self.r = r
       self.c = c
       self.sig = sig
       self.dt = self.T/self.N

   def JarrowRudd(self, type):
       u = np.exp((self.r - self.sig**2 / 2)*self.dt + self.sig*np.sqrt(self.dt))
       d = np.exp((self.r - self.sig**2 / 2)*self.dt - self.sig*np.sqrt(self.dt))
       p = (np.exp(self.r*self.dt) - d)/(u - d)
       q = 1-p
       disc = np.exp(-self.r*self.dt)
       return self.optionPrice(type, p, q, u, d, disc)

   def CRR(self, type, drift = 0):
       u = np.exp(drift*self.dt + self.sig * np.sqrt(self.dt))
       d = np.exp(drift*self.dt - self.sig * np.sqrt(self.dt))
       p = (np.exp(self.r*self.dt) - d)/(u - d)
       q = 1-p
       disc = np.exp(-self.r*self.dt)
       return self.optionPrice(type, p, q, u, d, disc)

   def Tian(self, type):
       v = np.exp(self.sig **2 * self.dt)
       u = .5 * np.exp(self.r * self.dt) * v * (v + 1 + np.sqrt(v**2 + 2*v -3))
       d = .5 * np.exp(self.r * self.dt) * v * (v + 1 - np.sqrt(v**2 + 2*v -3))
       p = (np.exp(self.r * self.dt) - d)/(u - d)
       q = 1-p
       disc = np.exp(-self.r * self.dt)
       return self.optionPrice(type, p, q, u, d, disc)

   def optionPrice(self, type, p, q, u, d, disc):
       # European Option
       if type == "ec" or type == "ep":
           # terminal value of stock
           S = self.S0 * (d ** (np.arange(self.N,-1,-1))) * (u ** (np.arange(0,self.N+1,1)))
           V = 0
           # value of option at terminal time
           if type == "ec":
               V = np.maximum(S - self.K, np.zeros(self.N+1))
           elif type == "ep":
               V = np.maximum(self.K - S, np.zeros(self.N+1))
           # take 2 at a time and get weighted-discounted value
           for i in np.arange(self.N,0,-1):
               V = disc * ( p * V[1:i+1] + q * V[0:i])
           # final result is option price
           return V[0]

       elif type == "ac" or type == "ap":
           print("test successful")
           # terminal value of stock
           S = self.S0 * (d**(np.arange(self.N,-1,-1))) * (u ** (np.arange(0,self.N+1,1)))

           V = 0
           # value of payoff at terminal time
           if type == "ac":
               V = np.maximum(0, S - self.K)
           elif type == "ap":
               V = np.maximum(0, self.K - S)

           # backtrack through options tree
           for i in np.arange(self.N-1, -1, -1):
               # recalculate prices at current level
               S = self.S0 * d**(np.arange(i,-1,-1)) * u**(np.arange(0,i+1,1))

               V[:i+1] = disc * ( p*V[1:i+2] + q*V[0:i+1] )                
               V = V[:-1]

               if type == 'ap':
                   V = np.maximum(V, self.K - S)
               else:
                   V = np.maximum(V, S - self.K)
 
           return V[0]

bapm = BAPM(S0, K, T, N, r, c, sig)
print(bapm.CRR(type = "ec"))

8.45544504853379

蒙地卡羅定價(僅限香草……美國尚未實施)

import numpy as np
import matplotlib.pyplot as plt

class MCPricing():
   def __init__(self, S0, drift, sig, T, tIncrement, r) -> None:
       self.S0 = S0
       self.mu = drift
       self.sig = sig
       self.T = T
       self.dt = tIncrement
       self.r = r

       self.N = round(self.T / self.dt)
       self.t = np.linspace(0, self.T, self.N)

   def simulateGBM(self):
       W = np.random.standard_normal(size = self.N)
       W = np.cumsum(W)*np.sqrt(self.dt)
       X = (self.mu - .5*self.sig**2)*self.t + self.sig*W
       S = self.S0*np.exp(X)
       return S.tolist()

   def calculateOptionPrice(self, K, nsim, type):
       if type == "ec" or type == "ep":
           sims = [self.simulateGBM() for i in range(nsim)]
           payoffs = []
           for path in sims:
               if type == "ec":
                   payoffs.append(np.maximum(path[-1] - K, 0))
               elif type == "ep":
                   payoffs.append(np.maximum(K - path[-1], 0))
           payoffs = np.array(payoffs)
           return np.average(np.exp(-1*self.r * self.T) * payoffs)

mcpm = MCPricing(S0 = 100, drift=0, sig =.13, T=1, tIncrement=.01, r=.06)
path1 = mcpm.simulateGBM()
plt.plot(mcpm.t, path1)

mcpm.calculateOptionPrice(100, 100000, "ec")

4.748831589623564

我會很感激任何幫助!謝謝

真希望我知道為什麼我以前的版本不起作用……但我發現對 GBM 的一些修改讓我得到了答案。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

class MCPricing():
   def __init__(self, S0, drift, sig, T, tIncrement, r) -> None:
       self.S0 = S0
       self.mu = drift
       self.sig = sig
       self.T = T
       self.dt = tIncrement
       self.r = r

       self.N = round(self.T / self.dt)
       self.t = np.linspace(0, self.T, self.N)

   def simulateGBM(self, nsims):
       Xt = np.log(self.S0) +\
            np.cumsum(((self.mu - self.sig**2/2)*self.dt + \
            self.sig*np.sqrt(self.dt) * \
            np.random.normal(size=(self.N,nsims))),axis=0)
            
       return np.exp(Xt)

   def calculateOptionPrice(self, K, nsims, type):
       if type == "ec" or type == "ep":
           paths = self.simulateGBM(nsims)
           if type == "ec":
               payoffs = np.maximum(paths[-1]-K, 0)
           elif type == "ep":
               payoffs = np.maximum(K - paths[-1], 0)
               
           option_price = np.mean(payoffs)*np.exp(-self.r * self.T) #discounting back to present value
           
           return option_price

mcpm = MCPricing(S0 = 100, drift=0.06, sig =.13, T=1, tIncrement=.001, r=.06)
paths = mcpm.simulateGBM(1000)
plt.plot(paths)
mcpm.calculateOptionPrice(100, 10000, "ec")

8.373535799654391

引用自:https://quant.stackexchange.com/questions/69306