創建更加復雜的自定義交易策略
- 使用交易策略類,創建更復雜的自定義策略
- 開始前的準備工作
- 本節的目標
- 繼承Strategy類,創建一個復雜的多因子選股策略
- 策略和回測參數配置,并開始回測
- 本節回顧
使用交易策略類,創建更復雜的自定義策略
qteasy
是一個完全本地化部署和運行的量化交易分析工具包,Github地址在這里,并且可以通過pip安裝:
$ pip install qteasy -U
qteasy
具備以下功能:
- 金融數據的獲取、清洗、存儲以及處理、可視化、使用
- 量化交易策略的創建,并提供大量內置基本交易策略
- 向量化的高速交易策略回測及交易結果評價
- 交易策略參數的優化以及評價
- 交易策略的部署、實盤運行
通過本系列教程,您將會通過一系列的實際示例,充分了解qteasy
的主要功能以及使用方法。
開始前的準備工作
在開始本節教程前,請先確保您已經掌握了下面的內容:
- 安裝、配置
qteasy
—— QTEASY教程1 - 設置了一個本地數據源,并已經將足夠的歷史數據下載到本地——QTEASY教程2
- 學會創建交易員對象,使用內置交易策略,——QTEASY教程3
- 學會使用混合器,將多個簡單策略混合成較為復雜的交易策略——QTEASY教程4
- 了解自定策略的基礎——QTEASY教程5 ,QTEASY教程6
在QTEASY文檔中,還能找到更多關于使用內置交易策略、創建自定義策略等等相關內容。對qteasy
的基本使用方法還不熟悉的同學,可以移步那里查看更多詳細說明。
qteasy
的內核被設計為一個兼顧高速執行以及足夠的靈活性的框架,理論上您可以實現您所設想的任何類型的交易策略。
同時,qteasy
的回測框架也做了相當多的特殊設計,可以完全避免您無意中在交易策略中導入"未來函數",確保您的交易策略在回測時完全基于過去的數據,同時也使用了很多預處理技術以及JIT技術對內核關鍵函數進行了編譯,以實現不亞于C語言的運行速度。
不過,為了實現理論上無限可能的交易策略,僅僅使用內置交易策略以及策略混合就不一定夠用了,一些特定的交易策略,或者一些特別復雜的交易策略是無法通過內置策略混合而成的,這就需要我們使用qteasy
提供的Strategy
基類,基于一定的規則創建一個自定義交易策略了。
本節的目標
在本節中,我們將介紹qteasy
的交易策略基類,通過一個具體的例子詳細講解如何基于這幾個基類,創建一個只屬于您自己的交易策略。為了說明
繼承Strategy類,創建一個復雜的多因子選股策略
在這個例子中,我們使用
import qteasy as qt
import numpy as npdef market_value_weighted(stock_return, mv, mv_cat, bp_cat, mv_target, bp_target):""" 根據mv_target和bp_target計算市值加權收益率,在策略中調用此函數計算加權收益率"""sel = (mv_cat == mv_target) & (bp_cat == bp_target)mv_total = np.nansum(mv[sel])mv_weight = mv / mv_totalreturn_total = np.nansum(stock_return[sel] * mv_weight[sel])return return_totalclass MultiFactors(qt.FactorSorter):""" 開始定義交易策略"""def __init__(self, pars: tuple = (0.5, 0.3, 0.7)):"""交易策略的初始化參數"""super().__init__(pars=pars, par_count=3, # 策略的可調參數有三個par_types=['float', 'float', 'float'], # 參數1:大小市值分類界限,參數2:小/中bp分界線,參數3,中/大bp分界線par_range=[(0.01, 0.99), (0.01, 0.49), (0.50, 0.99)],name='MultiFactor',description='根據Fama-French三因子回歸模型估算HS300成分股的alpha值選股',strategy_run_timing='close', # 在周期結束(收盤)時運行strategy_run_freq='m', # 每月執行一次選股(每周或每天都可以)strategy_data_types='pb, total_mv, close', # 執行選股需要用到的股票數據data_freq='d', # 數據頻率(包括股票數據和參考數據)window_length=20, # 回測時的視窗長度為20天use_latest_data_cycle=True, # 設置使用最新的數據reference_data_types='close-000300.SH', # 選股需要用到市場收益率,使用滬深300指數的收盤價計算,因此設置HS300指數的收盤價作為參考數據傳入max_sel_count=10, # 最多選出10支股票sort_ascending=True, # 選擇因子最小的股票condition='less', # 僅選擇因子小于某個值的股票lbound=0, # 僅選擇因子小于0的股票ubound=0, # 僅選擇因子小于0的股票 )def realize(self, h, **kwargs):""" 策略的選股邏輯在realize()函數中定義"""size_gate_percentile, bp_small_percentile, bp_large_percentile = self.pars# 讀取投資組合的數據PB和total_MV的最新值pb = h[:, -1, 0] # 當前所有股票的PB值mv = h[:, -1, 1] # 當前所有股票的市值pre_close = h[:, -2, 2] # 當前所有股票的前收盤價close = h[:, -1, 2] # 當前所有股票的最新收盤價# 讀取參考數據(r)market_pre_close = r[-2, 0] # HS300的昨收價market_close = r[-1, 0] # HS300的收盤價# 計算賬面市值比,為pb的倒數bp = pb ** -1# 計算市值的50%的分位點,用于后面的分類size_gate = np.nanquantile(mv, size_gate_percentile)# 計算賬面市值比的30%和70%分位點,用于后面的分類bm_30_gate = np.nanquantile(bp, bp_small_percentile)bm_70_gate = np.nanquantile(bp, bp_large_percentile)# 計算每只股票的當日收益率stock_return = pre_close / close - 1# 根據每只股票的賬面市值比和市值,給它們分配bp分類和mv分類# 市值小于size_gate的cat為1,否則為2mv_cat = np.ones_like(mv)mv_cat += (mv > size_gate).astype('float')# bp小于30%的cat為1,30%~70%之間為2,大于70%為3bp_cat = np.ones_like(bp)bp_cat += (bp > bm_30_gate).astype('float')bp_cat += (bp > bm_70_gate).astype('float')# 獲取小市值組合的市值加權組合收益率smb_s = (market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 1) +market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 2) +market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 3)) / 3# 獲取大市值組合的市值加權組合收益率smb_b = (market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 1) +market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 2) +market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 3)) / 3smb = smb_s - smb_b# 獲取大賬面市值比組合的市值加權組合收益率hml_b = (market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 3) +market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 3)) / 2# 獲取小賬面市值比組合的市值加權組合收益率hml_s = (market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 1) +market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 1)) / 2hml = hml_b - hml_s# 計算市場收益率market_return = market_pre_close / market_close - 1coff_pool = []# 對每只股票進行回歸獲取其alpha值for rtn in stock_return:x = np.array([[market_return, smb, hml, 1.0]])y = np.array([[rtn]])# OLS估計系數coff = np.linalg.lstsq(x, y)[0][3][0]coff_pool.append(coff)# 以alpha值為股票組合的選股因子執行選股factors = np.array(coff_pool)return factors
策略和回測參數配置,并開始回測
定義好上面的策略之后,就可以開始進行回測了,我們需要在qteasy
中創建一個交易員對象,操作前面創建的策略:
shares = qt.filter_stock_codes(index='000300.SH', date='20190501') # 選擇股票池,包括2019年5月以來所有滬深300指數成分股
# 設置回測的運行參數
qt.config(mode=1, # mode=1表示回測模式invest_start='20160405', # 回測開始日期invest_end='20210201', # 回測結束日期asset_type='E', # 投資品種為股票asset_pool=shares, # shares包含同期滬深300指數的成份股trade_batch_size=100, # 買入批量為100股sell_batch_size=1, # 賣出批量為整數股trade_log=True, # 生成交易記錄)# 開始策略的回測alpha = MultiFactors() # 生成一個交易策略的實例,名為alpha
op = qt.Operator(alpha, signal_type='PT') # 生成交易員對象,操作alpha策略,交易信號的類型為‘PT',意思是生成的信號代表持倉比例,例如1代表100%持有股票,0.35表示持有股票占資產的35%
op.op_type = 'stepwise' # 運行模式為步進模式
op.set_blender('1.0*s0', "close") # 交易策略混合方式,只有一個策略,不需要混合
op.run() # 開始運行