模组化回测系统

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 天设为可调整的项目,用以比较日期变化对报酬率的影响。

量化分析是未来投资的趋势,世界知名的避险基金都有采用此方法,将资料萃取成可用的参数作为策略制定,挖掘超额报酬,若读者有兴趣可以前往我们的官方网站,里面有提供更多财务、交易等财金资料,来帮助您制作更好的交易策略!

完整程式码

延伸阅读

相关连结

返回总览页