模組化回測系統

Photo Credits: Unsplash

前言

股票回測是目前相較之下較具科學精神的方法,雖然說過去歷史資料並不能代表未來,但回測結果至少讓我們可以檢驗自己的策略於過往的績效表現如何,藉以提供此策略或許有效的證據。而如果每次要嘗試新的策略就得把相同的架構再重寫一遍,相當費時且修改上會相當麻煩,於是今天我們嘗試把回測固定的流程模組化,這樣未來只需要專注在思考新策略即可!

編輯環境及模組需求

本文章使用 Mac OS 並以 Jupyter Notebook 作為編輯器

import tejapi
import pandas as pd
import numpy as np

Note: tejapi 安裝以命令提示字元 (Windows)/終端機 (Mac),輸入 pip install tejapi

tejapi.ApiConfig.api_key = 'Your Key'
tejapi.ApiConfig.ignoretz = True

本文重點概要

  • 架構的事前規劃
  • 系統模組化

架構系統

Step 1. 思考回測時會用到哪些儲存變數

  • 欲投資之股票池
  • 產生原始資料
  • 訂定交易策略
  • 產生交易訊號表
  • 執行回測
  • 儲存賣出金額
  • 儲存買入成本

構想大致流程所需的欄位

Step 2. 點首先設定一個類別classbacktest

class backtest():

Step 3. 以下的def都是在這class底下創建

def __init__(self, target_list):
# 設定初始值

# 股票池
self.target_list = target_list
        # 訊號表
self.signal_data = pd.DataFrame()

# 交易表
self.action_data = pd.DataFrame()

# 獲利數
self.protfolio_profit = []

# 成本數
self.protfolio_cost = []

當然資料庫也要放在初始值裡面,證券名稱是我們要找的target_list

# 資料庫
self.data = tejapi.get('TWN/APRCD',
coid = target_list,
mdate={'gte':'2020-01-01', 'lte':'2020-12-31'},
opts={'columns':['coid','mdate','close_d',
'volume']},
chinese_column_name=True,
paginate=True).reset_index(drop=True)

Step 4. 策略制定,這裡我們挑選兩個常見策略,以下針對重點介紹,完整程式碼請見此連結

  • 價量策略

突破近20日最高價和最高量進行買進,突破近10日最低價和最低量則賣出

def price_volume(self, specific=None):
# 策略更新
self.signal_data = pd.DataFrame()
self.action_data = pd.DataFrame()

股票池裡每一檔股票都要產生交易訊號

for i in self.target_list:
target_data = self.data[self.data['證券代碼'] == i]

計算近10、20天最高最低價量

rolling_max = target_data[['收盤價(元)', '成交量(千股)']].rolling(20).max()
rolling_min = target_data[['收盤價(元)', '成交量(千股)']].rolling(10).min()

產生交易訊號

  • 買入
#收盤價、成交量同時突破近20天高點買入
stock_data['買入訊號判斷'] = np.where((stock_data['收盤價(元)'] == stock_data['收盤價(max)']) & (stock_data['成交量(千股)'] == stock_data['成交量(max)']), -1, 0)
  • 賣出
#收盤價、成交量同時突破近10天低點賣出
stock_data['賣出訊號判斷'] = np.where((stock_data['收盤價(元)'] == stock_data['收盤價(min)']) & (stock_data['成交量(千股)'] == stock_data['成交量(min)']), 1, 0)
  • 最後一天平倉
remain_stock = self.signal_data.iloc[:-1,8:10].sum().sum()
self.signal_data.iloc[-1,9] = 0
self.signal_data.iloc[-1,8] = 0
if remain_stock < 0:
self.signal_data.iloc[-1,9] = -remain_stock
else:
self.signal_data.iloc[-1,8] = -remain_stock
  • 持有策略

第一天持有至最後一天賣出

def buy_hold(self, specific=None):
# 策略更新
self.signal_data = pd.DataFrame()
self.action_data = pd.DataFrame()

股票池裡每一檔股票都要產生交易訊號

for i in self.target_list:
target_data = self.data[self.data['證券代碼'] == i]

第一天買入,最後一天賣出

target_data['買入訊號判斷'] = 0
target_data['賣出訊號判斷'] = 0

# 第一天買入,最後一天賣出
target_data.iloc[0, 4] = -1
target_data.iloc[-1,5] = 1

Step 5. 執行回測計算

def run(self, specific=None):
# 做出交易紀錄表
trade_data = pd.DataFrame(index= self.data['年月日'],
columns=self.target_list).fillna(0.0)

action_data = self.signal_data[(self.signal_data['買入訊號判
斷'] != 0) | (self.signal_data['賣出訊號判斷'] != 0)]

計算獲利

self.protfolio_profit.append(sum(action_data['交易'].tolist()))

計算成本

self.protfolio_cost.append(-action_data[action_data['買入訊號判斷'] < 0]['交易'].sum())

Step 6. 計算最終報酬率

def ROI(self):
# 報酬率
return_profit = sum(self.protfolio_profit) /
sum(self.protfolio_cost)
       return return_profit

檢視大盤績效

策略的優劣通常和大盤來做比較,如果忙了老半天獲利輸給單純持有大盤,則代表策略或許有進步的空間

Step 1. 設定marketbacktest類別,這裡我們使用調整後指數 Y9997

market = backtest(['Y9997'])

Step 2. 選擇策略

market.buy_hold()

Step 2. 進行回測

market.run()

Step 3. 檢視報酬率

market.ROI()

自訂投資組合

這裡我們想試試 MSCI 做為自己的投資組合,MSCI 指數是指摩根士丹利資本國際公司所編製的股價股數,也稱摩根指數、大摩指數,我們可以查到2020 MSCI 持有的股票名單,這裡使用 TWN/AIDXS交易資料庫來搜尋指數成分股。

data_MSCI = tejapi.get('TWN/AIDXS',
coid = 'MSCI',
mdate= '2019-12-31',
opts={'columns':['coid','mdate','key3']},
chinese_column_name=True)

篩選出成分股,並把獨有的證券代號提出轉為list

MSCI_list = data_MSCI['成份股'].unique().tolist()

最後把中文刪除只留下代碼

MSCI_list = [coid[:4] for coid in MSCI_list]

由於模組化的效果,我們不用再寫一遍回測流程,只需要輕鬆的改變target_list就可以馬上得到我們要的結果

Step 1. 設定mscibacktest類別,並選擇MSCI_list股票池

msci = backtest(MSCI_list)

Step 2. 選擇策略

msci.price_volume()

Step 3. 進行回測

msci.run()

Step 4. 檢視報酬率

msci.ROI()

結論

2020台股屬於大多頭,事後來看是這段期間的持有的策略報酬率較好,但時間只有一年也無法說明持有策略總是優於價量策略。本文章主要介紹如何架構一套簡易回測系統,讀者可在策略上自行調整,例如可以試著將價量的參數1020 天設為可調整的項目,用以比較日期變化對報酬率的影響。

量化分析是未來投資的趨勢,世界知名的避險基金都有採用此方法,將資料萃取成可用的參數作為策略制定,挖掘超額報酬,若讀者有興趣可以前往我們的官方網站,裡面有提供更多財務、交易等財金資料,來幫助您製作更好的交易策略!

完整程式碼

延伸閱讀

相關連結

返回總覽頁
Procesing