股價路徑預測

Photo by Nicholas Cappello on Unsplash

本文重點概要

  • 文章難度:★★★☆☆
  • 以蒙地卡羅法模擬投資組合未來走勢
  • 閱讀建議:本文首先簡述蒙地卡羅的方法原理,接著便會進行資料挑選、模擬過程以及結果呈現,讓讀者了解蒙地卡羅模擬過程的執行,文中不會提及任何數學公式,便於讀者閱讀。

前言

蒙地卡羅模擬法的用途是估計不確定事件的可能結果,其運作方式則是透過假設機率分佈,使不確定性事件的變數建立模型。 並且,每個預測期都會用一組隨機數字來不斷重新計算結果,藉此產生大量的可能結果。

而在財務金融領域中,此方法被廣泛用來衡量資產組合的報酬及風險,較注重預測末尾的極端走勢。因此,本文最後也將透過視覺化結果,說明資產組合的風險報酬表現。

編輯環境及模組需求

本文使用 MacOS 並以 Jupyter Notebook 作為編輯器

#基本套件
import numpy as np
import pandas as pd
#繪圖套件
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set()
#TEJAPI
import tejapi
tejapi.ApiConfig.api_key = 'Your Key'
tejapi.ApiConfig.ignoretz = True

資料庫使用

  • 證券交易資料表: 資料庫代碼為 ‘TWN/EWPRCD’,提供證券日交易行情資訊,以及還原股價資訊。
  • 報酬率資訊表: 資料庫代碼為 ‘TWN/EWPRCD2’,包含證券與指數之報日、週、月、年酬率資料。

資料處理

Step 1. 報酬率資料撈取

ticker = ['1476', '2330', '2603', '2882']
# 儒鴻, 台積電, 國泰金, 長榮
ret = tejapi.get('TWN/EWPRCD2', # 公司交易資料-已調整股價(收盤價)
                  coid = ticker,
                  mdate = {'gte':'20200101'},
                  opts = {'columns': ['coid', 'mdate', 'roia']},
                  chinese_column_name = True,
                  paginate = True)
ret = ret.set_index('年月日')
資料轉置
資料轉置
# 資料轉置
RetData = {}
for i in ticker:
    r = ret[ret['證券代碼'] == i]
    r = r['日報酬率 %']
    RetData.setdefault(i, r)
RetData = pd.concat(RetData, axis = 1)
RetData = RetData * 0.01
此處轉換資料表格式,便於後續計算各標的平均報酬與標的間共變異數。
此處轉換資料表格式,便於後續計算各標的平均報酬與標的間共變異數。

Step 2. 平均報酬、共變異數、本金計算

# 平均報酬
Mean = pd.DataFrame(
list(np.mean(RetData[i]) for i in RetData.columns), index=RetData.columns, columns = ['平均值'])
# 共變異數矩陣
covMatrix = RetData.cov()
左:平均報酬 ; 右:共變異數矩陣
左:平均報酬 ; 右:共變異數矩陣
price = tejapi.get('TWN/EWPRCD', # 公司交易資料-未調整股價
                  coid = ticker,
                  mdate = {'gte':'20220525', 'lte':'20220525'},
                  opts = {'columns': ['coid', 'mdate', 'close_d']},
                  chinese_column_name = True,
                  paginate = True)
price = price.set_index('年月日')
principal = (price.loc['2020-05-25']['收盤價(元)'].sum()) * 1000

透過加總四支標的於2020年5月25日的收盤價,並假設至少持有一張股票(1000股),則初始本金為1,193,900元。

模擬條件設定

權重設定、模擬期間與模擬次數

# 權重設定
weights = list()
for i in range(4):
    weights.append(list(price['收盤價(元)'])[i]/price['收盤價(元)'].sum())
# 模擬次數
number_of_trial = 100
# 模擬期間
sim_period = 30

在權重設定的部分,讀者可以根據自身標的持有情形而做改變,此處直接使用股價權重比例僅為示範而已。

儒鴻:40%、台積電:44%、長榮:12%、國泰金:4%。

模擬計算流程

sim_mean = np.full(shape = (sim_period, 4), fill_value = Mean.T.loc['平均報酬'])
sim_mean = sim_mean.T

首先,定義儲存表格sim_mean並填入各標的之平均報酬,再將其轉置,將個別標的獨立出來。

sim_portfolio = np.full(shape = (sim_period, number_of_trial), fill_value = 0)

接著,定義儲存表格sim_portfolio為投資組合的預測欄位,並先行將每個欄位填入0,後續再通過計算填入該預測路徑該期間之預測值。

for i in range(0, number_of_trial):
    multi_normal = np.random.normal(size = (sim_period, 4))
    cholesky = np.linalg.cholesky(covMatrix)
    
    sim_return = sim_mean + np.inner(cholesky, multi_normal)
    
    sim_portfolio[:,i] = 
    np.cumprod(np.inner(weights, sim_return.T)+1) * principal

multi_normal:

標的報酬分佈圖
標的報酬分佈圖

從上圖中可以發現,除了長榮(2603)有較嚴重的厚尾問題,各項標的報酬分配大致上接近常態分配,因此本文此處也套用常態分配在各標的上。

cholesky:

在處理多資產投資組合時,透過cholesky分解出共變異數矩陣的下三角矩陣,處理標的間相關性問題。

接著,將上述兩矩陣內積,得到模擬之各項標的報酬走勢;最後乘上個標的權重比例(同樣是內積)以及初始本金,即完成投資組合路徑模擬計算。

視覺化模擬結果

plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # 輸入中文plt.figure(figsize=(15,8)) #框定圖表尺寸plt.plot(sim_portfolio)
plt.ylabel('投資組合累積價值變動', fontsize = 15)
plt.xlabel('模擬期間', fontsize = 15)
plt.title('模擬路徑', fontsize = 20)
plt.show()
模擬路徑
模擬路徑

透過這一次的模擬結果,可以藉由圖表中最下面的路徑推論,接下來一個月該投資組合走勢下檔風險最多不會超過 -16%;而上漲報酬最大可能為25%。因此該投資組合有較低下檔風險以及較高的漲勢機率。

結論

透過上述的過程,相信讀者可以明白蒙地卡羅方法的執行流程,並且可以知道其背後具有統計理論的支撐;然而,也因為蒙地卡羅方法是透過隨機機率為基礎進行大量計算,以模擬將來的可能走勢,所以不能代表市場會全然地與預測結果相同,若市場中有大幅度的波動導致極端值產生,則蒙地卡羅方法的參考性就有所降低。因此,想要在市場中保有領先地位,不僅僅要有邏輯清晰且數據支持的分析結果,也必須時刻掌握資訊的流通,而TEJ也歡迎讀者選購 TEJ E Shop中的方案,相信讀者具有完整的資料庫後,就能輕易地完成自身資產配置的走勢模擬,並掌握市場整體的脈動。

完整程式碼

延伸閱讀

相關連結

 
返回總覽頁
Procesing