Python中的幾何布朗運動模擬:奇怪的結果
我正在嘗試在 Python 中模擬幾何布朗運動,但是我得到的結果看起來很奇怪,在我看來它們不可能是正確的。我的目標是模擬 1 年的每一天。基本上,我使用了兩種略有不同的方法。根據我的研究,應該可以使用每日漂移和波動率,
dt = 1
或者年化漂移和波動率並使用dt = 1/365
. 對於第一種方法,我根據每日曆史數據計算了每日漂移和波動率,並在第二種方法中對其進行了年度化。因此也隨之T
改變。以下是我從這個答案(Python 中的幾何布朗運動模擬)中部分獲得的 Python 程式碼:import numpy as np import matplotlib.pyplot as plt np.random.seed(1000) quandl.ApiConfig.api_key = "XXXXXX" def gen_paths(S0, r, sigma, T, M, I): dt = float(T) / M paths = np.zeros((M + 1, I), np.float64) paths[0] = S0 for t in range(1, M + 1): rand = np.random.standard_normal(I) paths[t] = paths[t - 1] * np.exp((r - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * rand) return paths # Get data df = quandl.get(...) value = df['Value'] # Compute returns returns = value.pct_change(1) # Daily drift and volatility S0 = value[-1] # initial stock price r = np.mean(returns) # drift sigma = np.std(returns) # volatility T = 365 # time M = 365 # number of steps I = 100000 # number of simulations paths_1 = gen_paths(S0, r, sigma, T, M, I) print("Average: " + str(np.average(paths_1[-1]))) # Yearly drift and volatility r = np.mean(returns) * 365 sigma = np.std(returns) * np.sqrt(365) T = 1.0 paths_2 = gen_paths(S0, r, sigma, T, M, I) print("Average: " + str(np.average(paths_2[-1]))) # Visualize 5 simulated paths for each fig, axs = plt.subplots(2) axs[0].plot(paths_1[:, :5]) axs[1].plot(paths_2[:, :5]) plt.show()
這是我得到的結果:
對於我得到
117183
的具有每日漂移和波動率76145
的方法以及具有年度漂移和波動率的方法的平均值。以下是我的問題:
- 這些結果是否正確或我的程式碼有什麼問題?
- 兩種方法的平均值不應該非常相似嗎?
- 哪種方法有利於使用?
好問題!
摘要:您的程式碼和數學是正確的,但是您使用了太高的音量和漂移,以至於無法真實世界。由於高音量和對數正態性,您的模擬衰減為零。
基本上,我使用了兩種略有不同的方法。根據我的研究,應該可以使用 dt = 1 的每日漂移和波動率,或者將漂移和波動率年化並使用 dt = 1/365
使用年數量的解決方案 $ {t, \sigma, r} $ 是 $$ \begin{align} S(t+\Delta t) = S(t) \exp \left((r-\tfrac{1}{2}\sigma^2)\Delta t + \sigma\sqrt{\Delta t}\cdot Z \right). \end{align} $$
創建新的每日數量 $ {d, s, \nu} $ 通過替換 $ \Delta t := d/365 $ , $ ; \sigma := s \sqrt{365} $ , $ ; r:= \nu \cdot 365 $ ,我們得到 $$ \begin{align} S(d+\Delta d) = S(d) \exp \left((\nu-\tfrac{1}{2}s^2)\Delta d + s\sqrt{\Delta d}\cdot Z \right). \end{align} $$
因此,無論您使用年度參數還是每日參數,“公式”看起來都是一樣的。
- 這些結果是否正確或我的程式碼有什麼問題?
您的程式碼和結果是正確的。問題是你的參數是巨大的。您假設的每日值應該是年度值。因此,您假設每年的內容是巨大的。每日費率應該是 $ \nu=\tfrac{0.04}{365} $ ; 卷應該是 $ s=\tfrac{0.4}{\sqrt{365}}. $ 然後是年度版本 $ \sigma=0.4 $ 和 $ r=0.04 $ .
儘管可以預料,但令人困惑的是,您的所有模擬都向零衰減。這是因為您的 GBM 是對數正態分佈,並且當您的變異數接近無窮大(您的 vol 很大)時,幾乎所有的終端密度都為零。終值很大的機率很小,但是這個機率很小,所以我們看不到這個。您可以通過繪製具有較大變異數的 PDF 和 CDF 來看到這一點。
- 兩種方法的平均值不應該非常相似嗎?
您對兩個模擬使用不同的隨機數。*通過刪除頂部的np.random.seed(1000)*來強制隨機數相同,並在每次呼叫函式之前添加一次,如下所示
... np.random.seed(1000) paths_1 = gen_paths(S0, r, sigma, T, M, I) ... np.random.seed(1000) paths_2 = gen_paths(S0, r, sigma, T, M, I)
這將確保它們使用相同的隨機性,並且您將看到您的兩個圖是相同的。
哪種方法有利於使用?
每年(幾乎)總是,除非您從事日內建模和真正的高解析度工作,並避免出現下溢的數值問題。我從未真正見過有人使用除年度以外的任何東西來進行標準 GBM 建模和定價。