6. 指数增强选股策略

参考来源:docs/_joinquant_migration_source/Example_06_指数增强选股.ipynb 第一个 Markdown cell。

本策略以0.8为初始权重跟踪指数标的沪深300中权重大于0.35%的成份股. 个股所占的百分比为(0.8*成份股权重)*100%.然后根据个股是否: 1.连续上涨5天 2.连续下跌5天 来判定个股是否为强势股/弱势股,并对其把权重由0.8调至1.0或0.6

策略运行频率:每日运行 策略运行时间:每日收盘前

回测时间为:2021-01-01到2022-12-31

6.1. 1. 策略代码

创建自定义交易策略:

import qteasy as qt
import numpy as np
from qteasy import Parameter, StgData


class IndexEnhancement(qt.GeneralStg):

    def __init__(self):
        super().__init__(
                pars=[
                    Parameter((0.01, 0.99), name='weight_threshold', par_type='float', value=0.35),
                    Parameter((0.51, 0.99), name='init_weight', par_type='float', value=0.8),
                    Parameter((2, 20), name='price_days', par_type='int', value=5),
                ],
                name='IndexEnhancement',
                description='跟踪HS300指数选股,并根据连续上涨/下跌趋势判断强弱势以增强权重',
                data_types=[
                    StgData('wt_idx|000300.SH', freq='m', asset_type='E', window_length=2),
                    StgData('close', freq='d', asset_type='E', window_length=40),
                ],
        )

    def realize(self):
        weight_threshold, init_weight, price_days = self.get_pars('weight_threshold', 'init_weight', 'price_days')
        # 读取投资组合的权重wt和最近price_days天的收盘价
        wt = self.get_data('wt_idx|000300.SH_E_m')[-1]
        close_windows = self.get_data('close_E_d')
        pre_close = close_windows[-price_days - 1:-1]
        close = close_windows[-price_days:]  # 当前所有股票的最新连续收盘价

        # 计算连续price_days天的收益
        stock_returns = close - pre_close

        # 设置初始选股权重为0.8
        weights = init_weight * np.ones_like(wt)

        # 剔除掉权重小于weight_threshold的股票
        weights[wt < weight_threshold] = 0

        # 找出强势股,将其权重设为1, 找出弱势股,将其权重设置为 init_weight - (1 - init_weight)
        up_trends = np.all(stock_returns > 0, axis=1)
        weights[up_trends] = 1.0
        down_trend_weight = init_weight - (1 - init_weight)
        down_trends = np.all(stock_returns < 0, axis=1)
        weights[down_trends] = down_trend_weight

        # 实际选股权重为weights * HS300权重
        weights *= wt

        return weights

6.2. 2. 策略回测

回测参数:

  • 回测时间:2021-01-01到2022-12-31

  • 资产类型:股票

  • 资产池:沪深300成份股

  • 初始资金:100万

  • 买入批量:100股

  • 卖出批量:1股

shares = qt.filter_stock_codes(index='000300.SH', date='20210101')
print(len(shares), shares[:10])
alpha = IndexEnhancement()
op = qt.Operator(alpha, signal_type='PT')
op.op_type = 'stepwise'
op.set_blender('1.0*s0')
res = qt.run(op, mode=1,
       invest_start='20210101',
       invest_end='20221231',
       invest_cash_amounts=[1000000],
       asset_type='E',
       asset_pool=shares,
       trade_batch_size=100,
       sell_batch_size=1,
       trade_log=True,
      )

print()

6.3. 回测结果

419 ['000001.SZ', '000002.SZ', '000063.SZ', '000066.SZ', '000069.SZ', '000100.SZ', '000157.SZ', '000166.SZ', '000333.SZ', '000338.SZ']
No match found! To get better result, you can
- pass "match_full_name=True" to match full names of stocks and funds

     ====================================
     |                                  |
     |       BACK TESTING RESULT        |
     |                                  |
     ====================================

qteasy running mode: 1 - History back testing
time consumption for operate signal creation: 0.0 ms
time consumption for operation back looping:  13 sec 461.8 ms

investment starts on      2021-01-04 00:00:00
ends on                   2022-12-30 00:00:00
Total looped periods:     2.0 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
000001.SZ    0         3      3   100.0%     0.0%      0.0%  
000002.SZ    0         2      2   100.0%     0.0%      0.0%  
000063.SZ    0         0      0   100.0%     0.0%      0.0%  
000100.SZ    1         5      6    66.9%     0.0%     33.1%  
000333.SZ    0         1      1   100.0%     0.0%      0.0%  
000338.SZ    1         1      2    62.3%     0.0%     37.7%  
000651.SZ    0         1      1   100.0%     0.0%      0.0%  
000725.SZ    0        95     95   100.0%     0.0%      0.0%  
000858.SZ    0         0      0   100.0%     0.0%      0.0%  
002027.SZ    1         3      4    62.3%     0.0%     37.7%  
...            ...     ...   ...      ...       ...       ...
601229.SH    1         3      4    50.2%     0.0%     49.8%  
601288.SH    0        76     76   100.0%     0.0%      0.0%  
601318.SH    0         3      3   100.0%     0.0%      0.0%  
601328.SH    0        30     30   100.0%     0.0%      0.0%  
601398.SH    0       106    106   100.0%     0.0%      0.0%  
601601.SH    1         0      1    78.8%     0.0%     21.2%  
601668.SH    0        15     15   100.0%     0.0%      0.0%  
601688.SH    0         1      1   100.0%     0.0%      0.0%  
601899.SH    0         4      4   100.0%     0.0%      0.0%  
603259.SH    0         0      0   100.0%     0.0%      0.0%   

Total operation fee:     ¥    2,388.29
total investment amount: ¥1,000,000.00
final value:              ¥  703,480.41
Total return:                   -29.65% 
Avg Yearly return:              -16.23%
Skewness:                         -0.02
Kurtosis:                          1.63
Benchmark return:               -26.50% 
Benchmark Yearly return:        -14.36%

------strategy loop_results indicators------ 
alpha:                           -0.026
Beta:                             0.941
Sharp ratio:                     -1.237
Info ratio:                      -0.139
250 day volatility:               0.168
Max drawdown:                    43.41% 
    peak / valley:        2021-02-19 / 2022-10-31
    recovered on:         Not recovered!

===========END OF REPORT=============

png