1. 双均线择时策略

参考来源:docs/_joinquant_migration_source/Example_01_双均线择时策略.ipynb 第一个 Markdown cell。

本策略根据交易目标的其日K线数据建立简单移动平均线的双均线交易模型, 交易策略如下:

策略包含两个参数:短周期天数S、长周期天数L 分别以两个不同的周期计算交易标的日K线收盘价的移动平均线,得到两根移动均线,以S为周期计算的均线为快均线,以L为周期计算的均线为慢均线,根据快慢均线的交叉情况产生交易信号:

  1. 当快均线由下向上穿越慢均线时全仓买入交易标的

  2. 当快均线由上向下穿越短均线时平仓

模拟回测交易:

  • 回测数据为:沪深300指数(000300.SH)

  • 回测周期为2011年1月1日到2020年12月31日

  • 生成交易结果图表

策略参数优化:

  • 同样使用HS300指数,在2011年至2020年共十年的历史区间上搜索最佳策略参数

  • 并在2020年至2022年的数据上进行验证

  • 输出30组最佳参数的测试结果

1.1. 首先导入qteasy模块

import qteasy as qt

1.2. 创建一个新的策略

使用qt.RuleIterator策略基类,可以创建规则迭代策略, 这种策略可以把相同的规则迭代应用到投资组合中的所有股票上,适合在一个投资组合 中的所有股票上应用同一种择时规则。

from qteasy import Parameter, StgData
from qteasy import RuleIterator
# 创建双均线交易策略类
class Cross_SMA_PS(RuleIterator):
    """自定义双均线择时策略策略,产生的信号类型为交易信号
        这个均线择时策略有两个参数:
            - FMA 快均线周期
            - SMA 慢均线周期
        策略跟踪上述两个周期产生的简单移动平均线,当两根均线发生交叉时
        直接产生交易信号。
    """
    def __init__(self, **kwargs):
        """
        初始化交易策略的参数信息和基本信息
        """
        super().__init__(
            pars=[Parameter((10, 100), name='fast', par_type='int', value=10),
                  Parameter((30, 180), name='slow', par_type='int', value=160)],
            # 策略只有长短周期两个参数, 均为整型变量
            name='CROSSLINE',  # 策略的名称
            description='快慢双均线择时策略',  # 策略的描述
            data_types=StgData('close', freq='d', asset_type='ANY', window_length=200),  # 策略基于收盘价计算均线,因此数据类型为'close', 历史数据窗口长度为200
            **kwargs,
        )

    def realize(self):
        """策略的具体实现代码:
         - f: fast, 短均线计算日期;
         - s: slow: 长均线计算日期;
        """
        from qteasy.tafuncs import sma
        # 获取传入的策略参数
        f, s = self.get_pars('fast', 'slow')
        # 获取历史数据日频收盘价,计算长短均线的当前值和昨天的值
        close = self.get_data('close_ANY_d')
        # 使用qt.sma计算简单移动平均价
        s_ma = sma(close, s)
        f_ma = sma(close, f)
        
        # 为了考察两条均线的交叉, 计算两根均线昨日和今日的值,以便判断
        s_today, s_last = s_ma[-1], s_ma[-2]
        f_today, f_last = f_ma[-1], f_ma[-2]
        
        # 根据观望模式在不同的点位产生交易信号
        # 在PS信号类型下,1表示全仓买入,-1表示卖出全部持有股份
        # 当快均线自下而上穿过上边界,发出全仓买入信号
        if (f_last <= s_last) and (f_today >= s_today):  
            return 1
        # 当快均线自上而下穿过上边界,发出全部卖出信号
        elif (f_last >= s_last) and (f_today <= s_today):  
            return -1
        else:  # 其余情况不产生任何信号
            return 0

1.3. 回测交易策略,查看结果

定义好策略后,定一个Operator交易员对象,引用刚刚创建的策略,根据策略的规则设定交易员的信号模式为PS PS表示比例交易信号,此模式下信号在-1到1之间,1表示全仓买入,-1表示全部卖出,0表示不操作。 使用历史数据回测交易策略,使用历史数据生成交易信号后进行模拟交易,记录并分析交易结果

stg = Cross_SMA_PS()
op = qt.Operator([stg], signal_type='PS')

# 设置op的策略参数
op.set_parameter(0, par_values= (10, 160))  # 设置快慢均线周期分别为10天、166天
op.set_group_parameters('Group_1', blender_str='s0')
# 设置基本回测参数,开始运行模拟交易回测
res = qt.run(op, 
             mode=1,  # 运行模式为回测模式
             asset_pool='000300.SH',  # 投资标的为000300.SH即沪深300指数
             invest_start='20110101',  # 回测开始日期
             visual=True,  # 生成交易回测结果分析图
             trade_batch_size=0.01,
             sell_batch_size=0.01,
            )

交易结果如下;

====================================
|                                  |
|         BACKTEST REPORT          |
|                                  |
====================================
qteasy running mode: 1 - History back testing
time consumption for operate signal creation: 172.5 ms
time consumption for operation back testing:  3.6 ms
investment starts on      2011-01-04 15:00:00
ends on                   2026-02-27 15:00:00
Total looped periods:     15.2 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
000300.SH    68       68    136   55.2%     -0.0%     44.8%  

Total operation fee:     ¥    3,333.02
total investment amount: ¥  100,000.00
final value:              ¥  142,737.62
Total return:                    42.74% 
Avg Yearly return:                2.38%
Skewness:                         -0.91
Kurtosis:                         13.80
Benchmark return:                47.68% 
Benchmark Yearly return:          2.61%

------strategy loop_results indicators------ 
alpha:                           -0.012
Beta:                             1.000
Sharp ratio:                      0.061
Info ratio:                      -0.006
250 day volatility:               0.139
Max drawdown:                    40.45% 
    peak / valley:        2015-06-08 / 2020-04-24
    recovered on:         Not recovered!


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

从上面的交易结果可以看到,十年间买入68次卖出68次,持仓时间为55%,最终收益率只有42.7%。

下面是交易结果的可视化图表展示

png

交叉线交易策略的长短周期选择很重要,可以使用qteasy来搜索最优的策略参数:

1.4. 策略参数的优化

我们可以在历史数据上搜索最优的策略参数,找到在历史数据上表现最好的参数组合,并检验它们在独立测试区间上的表现,以检验是否过拟合。


op.set_parameter(0, 
                 opt_tag=1  # 将op中的策略设置为可优化,如果不这样设置,将无法优化策略参数
                )
res = qt.run(op, 
             mode=2, 
             opti_start='20110101',  # 优化区间开始日期
             opti_end='20200101',  # 优化区间结束日期
             test_start='20200101',  # 独立测试开始日期
             test_end='20220101',  # 独立测试结束日期
             opti_sample_count=1000,  # 一共进行1000次搜索
             opti_method='SA',  # 优化方法为模拟退火算法
             parallel=False,  # 不启用并行搜索
            )

策略优化可能会花很长时间,qt会显示一个进度条:

Epoch:1/5->175917.941: 100%|█████████████████████████████████████████████████| 128/128 [00:08<00:00, 15.94it/s]
Epoch:2/5->183493.313: 100%|█████████████████████████████████████████████████| 128/128 [00:07<00:00, 16.43it/s]
Epoch:3/5->203089.648: 100%|█████████████████████████████████████████████████| 128/128 [00:07<00:00, 16.59it/s]
Epoch:4/5->187650.270: 100%|█████████████████████████████████████████████████| 128/128 [00:07<00:00, 16.46it/s]
Epoch:5/5->205538.237: 100%|█████████████████████████████████████████████████| 128/128 [00:07<00:00, 16.57it/s]
Epoch:1/1->411083.340: 100%|███████████████████████████████████████████████████| 30/30 [00:04<00:00,  7.04it/s]

优化完成,显示最好的30组参数及其相关信息:

====================================
|                                  |
|       OPTIMIZATION REPORT        |
|                                  |
====================================
qteasy running mode: 2 - Strategy Parameter Optimization
time consumption for optimization: 39 sec 103.0 ms
time consumption for evaluation:   4 sec 261.2 ms
investment starts on 2011-01-04 15:00:00
ends on 2019-12-31 15:00:00
Total looped periods: 9.0 years.
total investment amount: ¥   100,000.00
Benchmark type is 000300.SH
Total Benchmark rtn: 28.43% 
Average Yearly Benchmark rtn rate: 2.82%
Statistical analysis of optimal strategy messages indicators: 
Total return:        270.25% ± 13.73%
Annual return:       15.66% ± 0.46%
Alpha:               -0.277 ± 0.466
Beta:                -0.459 ± 2.175
Sharp ratio:         0.434 ± 0.069
Info ratio:          0.011 ± 0.002
250 day volatility:  0.145 ± 0.008
Other messages indicators are listed in below table
   Strategy items Sell-outs Buy-ins ttl-fee      FV      ROI    MDD 
0     (43, 144)       5.0      6.0    509.43 358,315.55 258.3% 31.6%
1     (29, 171)       5.0      6.0    498.98 358,659.37 258.7% 31.6%
2      (72, 84)      17.0     18.0  1,786.90 359,602.66 259.6% 43.8%
3      (72, 84)      17.0     18.0  1,786.90 359,602.66 259.6% 43.8%
4     (35, 151)       5.0      6.0    510.77 360,689.42 260.7% 31.6%
5      (77, 81)      29.0     30.0  3,111.64 362,208.28 262.2% 44.0%
6      (77, 81)      29.0     30.0  3,111.64 362,208.28 262.2% 44.0%
7      (80, 91)      15.0     16.0  1,519.87 362,252.85 262.3% 45.8%
8     (24, 176)       5.0      6.0    505.68 362,696.68 262.7% 31.6%
9     (24, 176)       5.0      6.0    505.68 362,696.68 262.7% 31.6%
10    (36, 150)       5.0      6.0    510.71 362,666.50 262.7% 31.6%
11    (11, 156)      11.0     12.0  1,005.55 362,714.28 262.7% 31.9%
12     (58, 83)      12.0     13.0  1,218.41 363,195.61 263.2% 43.2%
13    (31, 169)       6.0      7.0    566.80 363,756.82 263.8% 31.6%
14    (36, 151)       5.0      6.0    514.33 364,408.58 264.4% 31.6%
15    (28, 173)       5.0      6.0    505.27 365,648.99 265.6% 31.6%
16     (73, 83)      16.0     17.0  1,678.20 366,055.42 266.1% 43.6%
17    (32, 171)       4.0      5.0    452.30 366,955.25 267.0% 31.6%
18    (13, 156)      10.0     11.0    903.07 367,001.52 267.0% 31.8%
19     (73, 84)      17.0     18.0  1,767.40 368,221.99 268.2% 43.8%
20     (77, 82)      25.0     26.0  2,725.38 368,871.74 268.9% 44.7%
21     (77, 82)      25.0     26.0  2,725.38 368,871.74 268.9% 44.7%
22     (81, 91)      15.0     16.0  1,560.50 374,068.95 274.1% 44.4%
23     (76, 81)      25.0     26.0  2,730.01 375,311.56 275.3% 43.9%
24     (73, 85)      16.0     17.0  1,708.08 379,569.28 279.6% 44.0%
25    (12, 155)      11.0     12.0    992.25 381,190.46 281.2% 31.6%
26     (76, 84)      21.0     22.0  2,181.56 382,247.74 282.2% 44.6%
27     (77, 86)      16.0     17.0  1,719.80 400,385.81 300.4% 43.2%
28     (78, 85)      22.0     23.0  2,393.91 406,202.21 306.2% 43.2%
29     (80, 86)      21.0     22.0  2,386.87 411,083.34 311.1% 41.6%

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

这三十组参数会被用于独立测试,以检验它们是否过拟合:

Epoch:1/1->259292.734: 100%|███████████████████████████████████████████████████████████| 30/30 [00:01<00:00, 23.02it/s]

====================================
|                                  |
|        VALIDATION REPORT         |
|                                  |
====================================
qteasy running mode: 2 - Strategy Parameter Optimization
time consumption for optimization: 39 sec 103.0 ms
time consumption for evaluation:   4 sec 261.2 ms
investment starts on 2020-01-02 15:00:00
ends on 2021-12-31 15:00:00
Total looped periods: 2.0 years.
total investment amount: ¥   100,000.00
Benchmark type is 000300.SH
Total Benchmark rtn: 18.98% 
Average Yearly Benchmark rtn rate: 9.09%
Statistical analysis of optimal strategy messages indicators: 
Total return:        115.83% ± 31.89%
Annual return:       46.59% ± 10.98%
Alpha:               -0.081 ± 0.066
Beta:                0.999 ± 0.000
Sharp ratio:         0.545 ± 0.322
Info ratio:          -0.038 ± 0.047
250 day volatility:  0.178 ± 0.004
Other messages indicators are listed in below table
   Strategy items Sell-outs Buy-ins ttl-fee     FV      ROI    MDD 
0     (43, 144)       1.0      1.0    84.86 248,458.67 148.5% 15.2%
1     (29, 171)       1.0      1.0    85.88 258,545.09 158.5% 15.2%
2      (72, 84)       2.0      3.0   224.59 195,264.51  95.3% 20.8%
3      (72, 84)       2.0      3.0   224.59 195,264.51  95.3% 20.8%
4     (35, 151)       3.0      3.0   282.50 241,963.33 142.0% 17.0%
5      (77, 81)      10.0     11.0   792.08 168,647.51  68.6% 24.3%
6      (77, 81)      10.0     11.0   792.08 168,647.51  68.6% 24.3%
7      (80, 91)       4.0      5.0   412.29 218,152.13 118.2% 16.7%
8     (24, 176)       1.0      1.0    85.21 251,880.99 151.9% 15.2%
9     (24, 176)       1.0      1.0    85.21 251,880.99 151.9% 15.2%
10    (36, 150)       3.0      3.0   279.96 238,065.57 138.1% 17.3%
11    (11, 156)       5.0      5.0   448.16 231,744.72 131.7% 19.1%
12     (58, 83)       3.0      4.0   346.95 230,754.45 130.8% 19.8%
13    (31, 169)       1.0      1.0    85.55 255,239.86 155.2% 15.2%
14    (36, 151)       3.0      3.0   279.98 238,344.64 138.3% 17.2%
15    (28, 173)       1.0      1.0    85.59 255,731.20 155.7% 15.2%
16     (73, 83)       6.0      7.0   503.93 183,585.71  83.6% 18.5%
17    (32, 171)       1.0      1.0    85.96 259,292.73 159.3% 15.2%
18    (13, 156)       4.0      4.0   362.38 243,928.41 143.9% 17.5%
19     (73, 84)       5.0      6.0   427.50 176,000.45  76.0% 20.8%
20     (77, 82)       8.0      9.0   642.96 173,471.06  73.5% 22.4%
21     (77, 82)       8.0      9.0   642.96 173,471.06  73.5% 22.4%
22     (81, 91)       5.0      6.0   491.77 217,222.67 117.2% 16.7%
23     (76, 81)       8.0      9.0   643.36 171,211.45  71.2% 24.4%
24     (73, 85)       2.0      3.0   220.90 194,837.49  94.8% 19.9%
25    (12, 155)       4.0      4.0   358.07 234,517.54 134.5% 18.5%
26     (76, 84)       7.0      8.0   572.56 181,243.30  81.2% 20.5%
27     (77, 86)       6.0      7.0   564.34 217,678.26 117.7% 18.9%
28     (78, 85)       7.0      8.0   598.97 201,469.22 101.5% 19.2%
29     (80, 86)       8.0      9.0   672.51 198,322.07  98.3% 19.4%

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

参数优化结果以及各个指标的可视化图表展示:

png

优化之后我们可以检验一下找到的最佳参数:

# 从优化结果中取出一组参数试验一下:
op.set_parameter(0, 
                 pars= (43, 144)  # 修改策略参数,改为短周期25天,长周期166天
                )

# 重复一次测试,除策略参数意外,其他设置不变
res = qt.run(op, 
             mode=1,  
             asset_pool='000300.SH',  
             invest_start='20110101',  
             visual=True  
            )

得到结果:

====================================
|                                  |
|         BACKTEST REPORT          |
|                                  |
====================================
qteasy running mode: 1 - History back testing
time consumption for operate signal creation: 176.1 ms
time consumption for operation back testing:  3.5 ms
investment starts on      2011-01-04 15:00:00
ends on                   2026-02-27 15:00:00
Total looped periods:     15.2 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
000300.SH    11       12     23   69.7%     -0.0%     30.3%  

Total operation fee:     ¥      690.06
total investment amount: ¥  100,000.00
final value:              ¥  198,850.27
Total return:                    98.85% 
Avg Yearly return:                4.64%
Skewness:                         -0.97
Kurtosis:                         15.94
Benchmark return:                47.68% 
Benchmark Yearly return:          2.61%

------strategy loop_results indicators------ 
alpha:                            0.596
Beta:                             4.558
Sharp ratio:                      0.197
Info ratio:                       0.003
250 day volatility:               0.130
Max drawdown:                    31.58% 
    peak / valley:        2015-06-08 / 2015-07-08
    recovered on:         2017-11-21


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

优化后总回报率达到了98.85%,比优化前的参数好很多。

优化后的结果可视化图表如下:

png