期權定價
菜鳥問題 - 蒙地卡羅與 BAPM 歐洲期權定價差異
現在是寒假(新年快樂!),我正在嘗試實施一些期權定價模型(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