使用基於“正常”或連續複利的 mu 和 signa 的幾何布朗運動模擬股票價格?
我編寫了一個簡單的腳本,用於使用幾何布朗運動對股票價格進行建模。我下載的時間序列是每日調整後的收盤價。我的目標是能夠改變預測期和所有其他變數。
但是,我試圖了解使用線性或標準方法與使用對數方法計算 mu(平均回報)和 sigma(變異數)之間的價格預測差異。對數方法始終會產生更高的預測股票價格。我的程式碼如下。
我搜尋了網際網路並閱讀了我能找到的任何內容。這個論壇上也有幾篇有用的文章,例如這里和這裡。但沒有什麼能真正涵蓋我的問題。
我的問題是,哪種方法最合適?
(我正在使用 Python 3。)
from math import log, e import matplotlib.pyplot as plt from pandas_datareader import data from datetime import date, timedelta import datetime stock = 'AAPL' # Enter the name of the stock start = '2015/1/1' apple = data.DataReader(stock, 'yahoo', start) # This is the 'normal' way of calculating mu and sigma close = apple[:]['Adj Close'] mu = (close[-1]/close[1])** (252.0/len(close)) - 1 sigma = (close/close.shift(1)-1)[1:].std()*np.sqrt(252) # This is the 'log' way of calculating mu and sigma apple['log_price'] = np.log(apple['Adj Close']) apple['log_return'] = apple['log_price'].diff() mu = apple.log_return.sum() -1 sigma = np.std(apple.log_price) s0 = close[-1] T = 18/12 delta_t = 0.001 num_reps = 1000 steps = T/delta_t plt.figure(figsize=(15,10)) closing_prices = [] for j in range(num_reps): price_path = [s0] st = s0 for i in range(int(steps)): drift = (mu - 0.5 * sigma**2) * delta_t diffusion = sigma * np.sqrt(delta_t) * np.random.normal(0, 1) st = st*e**(drift + diffusion) price_path.append(st) closing_prices.append(price_path[-1]) plt.plot(price_path) plt.ylabel('stock price',fontsize=15) plt.xlabel('steps',fontsize=15) plt.axhline(y = s0, color = 'r', linestyle = '-') # print latest price TW plt.show() mean_end_price = round(np.mean(closing_prices),2) print("Expected price in 12 months: $", str(mean_end_price))
您的程式碼中的漂移是:
drift = (mu - 0.5 * sigma**2) * delta_t
所以我假設你正在使用幾何布朗運動來模擬你的股票價格,而不僅僅是簡單的布朗運動。因此,您的模型是對數正態,而不是正態。另外,我假設您下載的時間序列是每日收盤價。
GBM模型的解法如下(下 $ \delta t:=(t_i)-(t_{i-1}) $ & $ Z\sim~N(0,1) $ ):
$$ ln(S_{t_i}) - ln(S_{t_{i-1}}) = (\mu - 0.5\sigma^2)\delta t+\sigma\sqrt{\delta t}Z $$
請注意,上面的日誌返回是正常分佈的:
$$ ln(S_{t_i}) - ln(S_{t_{i-1}}) \sim N\left(\tilde{\mu} := (\mu - 0.5\sigma^2)\delta t;\tilde{\sigma}:=\sqrt{\delta t}\sigma\right) $$
如果我們使用每日時間序列,那麼 $ \delta t = \frac{1}{260} $ .
如果您想根據歷史每日數據校准上述模型,您的任務是校準 $ \tilde{\mu} $ 和 $ \tilde{\sigma} $ :
$$ (i): \tilde{\mu}=\frac{1}{n}\sum_{i=1}^{n} ln\left( \frac{S_{t_i}}{S_{t_{i-1}}}\right) $$
$$ (ii): \tilde{\sigma}^2 = \frac{1}{n-1} \sum_{i=1}^{n} \left( \left[ ln\left( \frac{S_{t_i}}{S_{t_{i-1}}}\right) - \tilde{\mu} \right]^2\right) $$
請注意,在上面的 (i) 中,您計算了 $ \tilde{\mu} $ 並不是 $ \mu $ . 在您的模擬中,您需要 $ \mu $ ,所以首先執行以下操作:
$$ \sigma = \tilde{\sigma}\frac{1}{\sqrt{\delta t}}=\tilde{\sigma}\sqrt{260} $$
$$ \mu = \frac{1}{\delta t}\tilde{\mu}+0.5{\sigma}^2=260\tilde{\mu}+0.5{\sigma}^2 $$
那就是 $ \mu $ 你應該在你的模擬中使用。
下一點是:為什麼您的程式碼中有以下行?
mu = apple.log_return.sum() -1
為什麼要減去 1?如果你的日誌返回是每天的,得到 $ \mu $ ,您的程式碼應為:
mu = apple.log_return.sum()/apple.log_return.count() mu = mu*260 + 0.5*apple.log_return.var()*sqrt(260)
要獲得 $ \mu $ 符合我上面描述的公式。
如果您使用 GBM 來模擬您的股票價格,那麼您不應該使用正常收益來校準您的模型:所以您所謂的“正常”方式是校準模型的錯誤方式。
ps:如果你有每天的時間序列,如果你想以每天的粒度進行模擬,你可以選擇一天作為你的時間單位。這將使您的任務變得更加容易,因為您可以使用 $ \tilde{\sigma} $ 和 $ \tilde{\mu} $ 直接,而不是必須年化它們:即將它們轉換成 $ \sigma $ 和 $ \mu $ .