11. Construye una estrategia más complicada
qteasy es una implementación y operación completamente localizada de un conjunto de herramientas de análisis comercial cuantitativo, la dirección de Github está aquí, y se puede instalar a través de pip:
$ pip install qteasy -U
qteasy tiene las siguientes funciones:
Adquisición, limpieza, almacenamiento, procesamiento, visualización y uso de datos financieros.
Cree estrategias comerciales cuantitativas y proporcione una gran cantidad de estrategias comerciales básicas integradas.
Backtesting de estrategias comerciales vectorizadas de alta velocidad y evaluación de resultados comerciales
Optimización y evaluación de parámetros de estrategia comercial.
Implementación y operación en vivo de estrategias comerciales.
En estos tutoriales, aprenderá las funciones principales y el uso de qteasy a través de una serie de ejemplos prácticos.
11.1. Antes de empezar
Asegúrese de dominar el siguiente contenido antes de comenzar este tutorial:
Instalar y configurar
qteasy—— QTEASY教程1Configure una fuente de datos local y haya descargado suficientes datos históricos al local ——QTEASY教程2
Aprenda a crear un objeto comercial, use estrategias comerciales integradas ——QTEASY教程3
Aprenda a usar el mezclador para combinar múltiples estrategias simples en estrategias comerciales más complejas ——QTEASY教程4
Comprenda cómo personalizar las estrategias comerciales ——QTEASY教程5QTEASY教程6
En la QTEASY documentación, también puede encontrar más contenido sobre el uso de estrategias comerciales integradas, la creación de estrategias personalizadas, etc. Si aún no estás familiarizado con el uso básico de qteasy, puedes ir allí para ver explicaciones más detalladas.
El núcleo de qteasy está diseñado como un marco que equilibra la ejecución de alta velocidad y la flexibilidad suficiente. En teoría, puedes implementar cualquier tipo de estrategia comercial que puedas imaginar.
Mientras tanto, el marco de backtesting de qteasy también ha sido especialmente diseñado para evitar por completo que usted importe «funciones futuras» sin darse cuenta en su estrategia comercial, asegurando que su estrategia comercial se base completamente en datos pasados durante el backtesting. Al mismo tiempo, se han utilizado muchas técnicas de preprocesamiento y tecnologías JIT para compilar las funciones clave del kernel para lograr una velocidad de ejecución no menor que la de C.
Sin embargo, para lograr estrategias comerciales teóricamente infinitas posibles, puede que no sea suficiente utilizar únicamente estrategias comerciales integradas y una combinación de estrategias. Algunas estrategias comerciales específicas, o algunas estrategias comerciales particularmente complejas, no se pueden crear combinando estrategias integradas. Esto requiere que utilicemos la clase base Strategy proporcionada por qteasy para crear una estrategia comercial personalizada basada en ciertas reglas.
11.2. Objetivo de este tutorial
En este tutorial, presentaremos la clase base de estrategia comercial de qteasy y explicaremos en detalle cómo crear su propia estrategia comercial basada en estas clases base a través de un ejemplo específico. para ilustrar
11.3. Cree una estrategia compleja de selección de acciones multifactorial heredando la clase Estrategia
En este ejemplo, utilizamos
>>> import qteasy as qt
>>> import numpy as np
>>> from qteasy import Parameter, StgData
>>> def 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_total
... return_total = np.nansum(stock_return[sel] * mv_weight[sel])
... return return_total
>>> class MultiFactors(qt.FactorSorter):
... """ 开始定义交易策略 """
...
... def __init__(self, par_values: tuple = (0.5, 0.3, 0.7)):
... """交易策略的初始化参数"""
... super().__init__(
... pars=[Parameter((0.01, 0.99), par_type='float', name='size_gate', value=0.5), # 参数1:大小市值分类界限
... Parameter((0.01, 0.49), par_type='float', name='bp_s_gate', value=0.3), # 参数2:小/中bp分界线
... Parameter((0.50, 0.99), par_type='float', name='bp_l_gate', value=0.7)], # 参数3,中/大bp分界线
... name='MultiFactor',
... description='根据Fama-French三因子回归模型估算HS300成分股的alpha值选股',
... data_types=[StgData('pb', freq='d', asset_type='E', window_length=20, use_latest_data_cycle=True), # 执行选股需要用到的股票数据
... StgData('total_mv', freq='d', asset_type='E', window_length=20, use_latest_data_cycle=True),
... StgData('close', freq='d', asset_type='E', window_length=20, use_latest_data_cycle=True),
... StgData('close-000300.SH', freq='d', asset_type='IDX', window_length=20, use_latest_data_cycle=True)], # 选股需要用到市场收益率,使用沪深300指数的收盘价计算
... max_sel_count=10, # 最多选出10支股票
... sort_ascending=True, # 选择因子最小的股票
... condition='less', # 仅选择因子小于某个值的股票
... lbound=0, # 仅选择因子小于0的股票
... ubound=0, # 仅选择因子小于0的股票
... )
...
... def realize(self):
... """ 策略的选股逻辑在realize()函数中定义
... """
...
... size_gate_percentile, bp_small_percentile, bp_large_percentile = self.get_pars('size_gate', 'bp_s_gate', 'bp_l_gate')
... # 读取投资组合的数据PB和total_MV的最新值
... pb = self.get_data('pb_E_d')[-1] # 当前所有股票的PB值
... mv = self.get_data('total_mv_E_d')[-1] # 当前所有股票的市值
... pre_close = self.get_data('close_E_d')[-1] # 当前所有股票的前收盘价
... close = self.get_data('close_E_d')[-2] # 当前所有股票的最新收盘价
...
... market_pre_close = self.get_data('close-000300.SH_IDX_d')[-2] # HS300的昨收价
... market_close = self.get_data('close-000300.SH_IDX_d')[-1] # 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,否则为2
... mv_cat = np.ones_like(mv)
... mv_cat += (mv > size_gate).astype('float')
... # bp小于30%的cat为1,30%~70%之间为2,大于70%为3
... bp_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)) / 3
... smb = 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)) / 2
... hml = hml_b - hml_s
...
... # 计算市场收益率
... market_return = market_pre_close / market_close - 1
...
... coff_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
Configuración de parámetros y backtesting.
Cuando se define la estrategia anterior, podemos comenzar a realizar pruebas retrospectivas. Necesitamos crear un objeto comercial en qteasy y operar la estrategia creada anteriormente:
shares = qt.filter_stock_codes(index='000300.SH', date='20190501') # 选择股票池,包括2019年5月以来所有沪深300指数成分股
# 开始策略的回测
alpha = MultiFactors() # 生成一个交易策略的实例,名为alpha
op = qt.Operator(alpha, signal_type='PT',
run_timing='close', # 在周期结束(收盘)时运行
run_freq='M', # 每月执行一次选股(每周或每天都可以)
) # 生成交易员对象,操作alpha策略,交易信号的类型为‘PT',意思是生成的信号代表持仓比例,例如1代表100%持有股票,0.35表示持有股票占资产的35%
# 设置回测参数,并开始回测
>>> qt.run(op=op,
... 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, # 生成交易记录
... ) # 开始运行
Los resultados son los siguientes:
====================================
| |
| BACKTEST REPORT |
| |
====================================
qteasy running mode: 1 - History back testing
time consumption for operate signal creation: 197.5 ms
time consumption for operation back testing: 315.2 ms
investment starts on 2016-04-05 15:00:00
ends on 2021-01-29 15:00:00
Total looped periods: 4.8 years.
-------------operation summary:------------
Only non-empty shares are displayed, call
"loop_result["oper_count"]" for complete operation summary
Sell Cnt Buy Cnt Total Long pct Short pct Empty pct
000413.SZ 3 3 6 5.4% -0.0% 94.6%
000415.SZ 1 1 2 2.0% -0.0% 98.0%
000625.SZ 1 1 2 2.0% -0.0% 98.0%
000629.SZ 1 1 2 1.5% -0.0% 98.5%
000656.SZ 1 1 2 1.8% -0.0% 98.2%
000723.SZ 5 5 10 8.2% -0.0% 91.8%
000725.SZ 1 1 2 1.9% -0.0% 98.1%
000728.SZ 1 1 2 1.9% -0.0% 98.1%
000783.SZ 1 1 2 1.8% -0.0% 98.2%
000898.SZ 4 4 8 7.1% -0.0% 92.9%
... ... ... ... ... ... ...
001965.SZ 1 1 2 1.9% -0.0% 98.1%
300418.SZ 2 2 4 3.8% -0.0% 96.2%
300442.SZ 1 1 2 1.8% -0.0% 98.2%
600026.SH 1 1 2 1.8% -0.0% 98.2%
000975.SZ 1 1 2 1.8% -0.0% 98.2%
300394.SZ 1 1 2 1.5% -0.0% 98.5%
600160.SH 3 3 6 5.0% -0.0% 95.0%
601127.SH 1 2 3 1.7% -0.0% 98.3%
601058.SH 2 2 4 3.6% -0.0% 96.4%
302132.SZ 1 1 2 2.0% -0.0% 98.0%
Total operation fee: ¥ 3,227.95
total investment amount: ¥ 100,000.00
final value: ¥ 153,592.75
Total return: 53.59%
Avg Yearly return: 9.31%
Skewness: 0.09
Kurtosis: 6.81
Benchmark return: 63.94%
Benchmark Yearly return: 10.80%
------strategy loop_results indicators------
alpha: 0.026
Beta: 0.702
Sharp ratio: 0.295
Info ratio: -0.008
250 day volatility: 0.161
Max drawdown: 30.41%
peak / valley: 2016-11-22 / 2018-10-16
recovered on: 2019-03-07
trade log is stored in: /Users/jackie/Projects/qteasy_logs/trade_log_none_20260309_152544.csv
trade summary is stored in: /Users/jackie/Projects/qteasy_logs/trade_summary_none_20260309_152544.csv
value curve (complete values) is stored in: /Users/jackie/Projects/qteasy_logs/value_curve_none_20260309_152544.csv
==================END OF REPORT===================

11.4. Resumen
En este tutorial, explicamos en detalle cómo crear su propia estrategia comercial basada en la clase base de estrategia comercial de qteasy a través de un ejemplo específico. A través de este ejemplo, puede ver que la clase base de estrategia comercial de qteasy proporciona suficiente flexibilidad para implementar cualquier tipo de estrategia comercial que pueda imaginar.
A partir del siguiente tutorial, presentaremos el método de optimización de la estrategia comercial de qteasy, encontraremos los parámetros óptimos de la estrategia comercial a través de varios algoritmos de optimización y evaluaremos el rendimiento de la estrategia comercial.