大小盘轮动选股策略

  • Python量化投资——使用`qteasy`测试一个大小盘轮动投资策略
    • 问题介绍
    • 策略思想
    • 策略的实现
      • 创建交易策略
      • 配置回测参数
    • 策略的回测结果
    • 策略的进一步改进
      • 可视化报告的使用
      • 交易明细报告
      • 改进后的策略设置
      • 改进后的结果
    • 策略思路的延伸

Python量化投资——使用qteasy测试一个大小盘轮动投资策略

问题介绍

今天我们尝试利用qteasy模块来测试一个大小盘轮动投资策略,看看它能否给我们带来超额收益。

qteasy是本人正在开发的一个快速量化交易工具包,使用这个工具包,可以快速灵活地生成各种量化交易策略,生成历史数据并回测策略的表现,有针对性地优化策略的性能;未来还将提供实时自动化交易功能。该项目正在开发中,Github项目地址在这里:https://github.com/shepherdpp/qteasy

大小盘轮动是一个非常基本而且常见的投资策略。大家在做投资的时候可能会有这样的感觉,有时候大盘股拼命上涨,而很多小盘股按兵不动,出现所谓的“指数涨股票不涨”的情况。然而有时候又恰恰相反,大盘股不涨,而小盘股此起彼伏地往上涨。

我们可以用沪深300指数(000300.SH)代表大盘股,用创业板指(399006.SZ)代表小盘股,通过qteasy查看他们过去十年的走势:

import qteasy as qt
qt.candle('000300.SH', start='20110101', end='20201231', asset_type='IDX', mav=[])

qt.candle('399006.SH', start='20110101', end='20201231', asset_type='IDX', mav=[])

把两张图重叠起来看会更加清楚地发现,这两个指数的涨跌在不少时段是截然相反的,例如:

  • 从2013年一月一直到2014年年中,沪深300基本上处于震荡下行的状态,而同一时段的创业板指开始了一路上涨
  • 而从2017年的年初一直到2018年3月,创业板指一路下跌,而同期的沪深300指数却一路上行从3000点左右上攻到了4400点

如果对比较短期的行情,两个指数之间的差异更多,这时候如果我们可以在大盘股和小盘股之间轮动选股投资,是否会比单独投资大盘股或者小盘股收益更大呢?下面我们就来测试一下。

策略思想

在大小盘之间进行轮动,首先可以考虑最简单的情形:在前面提到的两个指数之间轮动,每天选择未来可能的涨幅较大的指数持有。那么如何判断哪一个指数未来的涨幅较大呢?大家可能有自己的想法,在这里我选择根据趋势来判断:

  • 分别计算两个指数在过去20天的涨幅,也就是今天的价格相对于20天前价格的涨幅
  • 选择涨幅较大的那个指数,在第二天持有,同时卖掉涨幅较小的指数

如果大家有其他的判断方式,欢迎在文末留言。
上面的思路非常简单,也很容易每天实现,只要每天使用当天的收盘价除以20天前的收盘价,计算当日涨跌幅,对比一下两个指数的涨跌幅,第二天根据前一天的结果操作即可:

当日涨幅=Price0Price20−1当日涨幅 = \frac{Price_0}{Price_{20}} - 1当日涨幅=Price20​Price0​​−1

策略的实现

根据上述的策略思路,我们很容易在qteasy中实现这样的轮动选股策略:

创建交易策略

首先,我们需要在queasy中实现一个选股策略,它需要根据“N日价格涨幅”来选股,从两个指数中选择N日价格涨幅最大的一个股票或资产,在qteasy中其实已经有了一个内置策略,能够实现上述目标,这个策略的名称为ndayrate,直接引用这个名称即可使用这个策略。因此,我们首先创建一个Operator对象,并引用这个策略:

op = qt.Operator(strategies = 'ndayrate', signal_type='pt')

现在这个策略已经创建好了,但是我们还需要做一些最基本的设定,确保它能按照我们的想法选股,必要的参数如下:

op.set_parameter(0,   sample_freq='d',  # 策略的选股周期为每日选股 sort_ascending=False,  # 设置选择涨幅最大的指数proportion_or_quantity=1,  # 设置每次选择一只指数后续持有pars=(20, ),  # 策略参数N=20,比较20日涨幅data_types='close')  # 使用收盘价计算涨幅

在上面的代码段中,我们通过几个简单的参数设置选股策略的基本行为:

  • sample_freq='d': 每日选股,如果设置选股周期为'w'表示每周选股,'2d'表示每两天选股一次
  • sort_ascending=False:该策略的操作方式是将所有的N日涨幅排序后取前几位,因为需要取最大涨幅,因此需要降序排列,如果要取最小涨幅,则需要设置sort_ascending=True
  • proportion_or_quantity=1:选择的股票数量,因为从两个指数中固定二选一,因此设置此参数为1
  • pars=(20, ):策略参数N,设置为20表示根据20日涨幅选股
  • data_types='close':默认值,计算收盘价的涨幅

配置回测参数

配置好选股策略以后,需要通过回测检验策略的表现,也就是调用沪深300和创业板两个指数的实际历史数据,进行模拟交易,看看模拟交易的结果是否能够跑赢大盘。在实际操作中,卖卖大盘指数不太容易,不过一般都可以很容易找到跟踪大盘指数的ETF基金来代替大盘,不过为了简单起见,我们这里就直接投资于2011年1月1日一直到2020年12月31日之间的沪深300和创业板指数,假设交易费率为万分之一,双向收费,看看投资的结果如何。

使用qteasy,调用qt.configure()对回测参数进行基本配置:

qt.configure(asset_pool=['000300.SH','399006.SZ'],  # 投资指数包括沪深300和创业板指数invest_amounts=100000,  # 投入金额为十万元asset_type='IDX',  # 为简单起见,直接投资于指数cost_rate_buy=0.0001,  # 买入资产时交易费用万分之一cost_rate_sell=0.0001,  # 卖出资产时的交易费用为万分之一invest_start='20110101',  # 模拟交易开始日期invest_end='20201231',  # 模拟交易结束日期trade_batch_size=0,  # 买入资产时最小交易批量sell_batch_size=0)  # 卖出资产时最小交易批量

上面的配置含义如下

  • asset_pool=['000300.SH', '399006.SZ']:投资目标指数用列表形式给出,如果要投资其他的指数或ETF基金,直接传入证券代码即可,如果要从三个或更多的证券中选股,直接加入列表中即可
  • invest_amounts=100000: 投资金额为十万元,如果需要模拟多次分批投入,还可以传入一个列表,不过需要分别指定每次投入的具体日期
  • asset_type='IDX': 投资标的类型:'E'代表股票, 'IDX'代表指数, 'FD'代表基金,'FT'代表期货,'OPT'代表期权
  • cost_rate_buy=0.0001: 设置买入和卖出交易费用比例,qteasy还支持设置最低费用、固定费用等等,这里只简单设置费率即可
  • cost_rate_sell=0.0001
  • invest_start='20110101': 模拟交易开始日期
  • invest_end='20201231': 模拟交易结束日期
  • trade_batch_size=0: 买入资产时最小交易批量,0代表可以交易任意份额,1代表只能交易整数份,这里可以输入任意大于0的数
  • sell_batch_size=0: 卖出资产时最小交易批量为0

qteasy还有其他的配置参数,参见qteasy的文档。

策略的回测结果

设置好所有的配置后,即可以开始回测了,调用qt.run()开始回测,回测的同时,我们开启可视化图表输出,并且开启交易明细记录:

res=qt.run(op, visual=True, print_backtest_log=True)

片刻后,回测完成,打印报告如下:

     ====================================|                                  ||       BACK TESTING RESULT        ||                                  |====================================qteasy running mode: 1 - History back testing
time consumption for operate signal creation: 142.4ms
time consumption for operation back looping:  3s369.3msinvestment starts on      2011-01-04 00:00:00
ends on                   2020-12-31 00:00:00
Total looped periods:     10.0 years.      - 一共模拟了十年的交易-------------operation summary:------------Sell Cnt Buy Cnt Total Long pct Short pct Empty pct
000300.SH    74       79    153   47.2%      0.0%     52.8%
399006.SZ    85      118    203   48.5%      0.0%     51.5%   Total operation fee:     ¥    3,122.37    - 总交易费用
total investment amount: ¥  100,000.00    - 初始投资金额十万元
final value:              ¥  514,251.88   - 十年后投资总金额来到了五十一万
Total return:                   414.25%   - 十年总收益率
Avg Yearly return:               17.80%   - 年化收益率
Skewness:                         -0.38
Kurtosis:                          2.88
Benchmark return:                63.38%   - 同期沪深300指数的总收益
Benchmark Yearly return:          5.03%   - 沪深300的年化收益------strategy loop_results indicators------
alpha:                            0.185
Beta:                             0.691
Sharp ratio:                      0.726
Info ratio:                       0.049
250 day volatility:               0.256
Max drawdown:                    50.57% peak / valley:        2015-06-03 / 2016-06-13recovered on:         2020-02-18===========END OF REPORT=============

从回测的结果可以很容易看出,这个策略是跑赢了沪深300大盘指数的,在这十年间沪深300的年化收益率只有可怜的5%左右,甚至比某些收益较高的定期产品都不如,而我们这个策略的投资年化收益率达到了17.8%,十年间总资产从十万元达到了五十多万元,翻了五倍多

策略的进一步改进

我们的策略获得了初步的成功,不过,光看总回报率还不能完全说明问题,策略在整个十年间的表现如何呢?这就需要进一步分析,看看能否进一步改进这个策略。这时我们需要进一步查看回测的结果,尤其是可视化结果和交易明细记录,通过这些记录和报告来找到策略的不足和改进点。

可视化报告的使用

由于设置了visual=True,在回测报告的最后,还能看到运行结果的可视化图表报告如下:

可视化图表是qteasy的一个很有用的功能。首先我们可以看到回测的历史回报率曲线图。这个曲线图以百分比为单位,将投资组合的回报率曲线和一个参考曲线(默认情况下参考曲线是沪深300指数,可以通过qt.configure(reference_asset='xxxxxx.xx')来设置为不同的指数)的收益率对比。红色曲线为投资组合的收益率,而蓝色曲线为参考指数收益率。
在这张图的参考指数曲线上,会用红、绿色箭头标注所有的买卖点,同时,图表在持有仓位的时间区间填充上绿色,响应没有持仓(空仓)的时段会保持为白色,这样就很容易看出整个投资历史上组合的回报率,以及买卖、持仓的大致时段和比例。

紧接着第一张图表,后续五张图表都是历史曲线图,显示了投资回报的多种不同的评价指标,这里面我感觉最有用的是“underwater”图,也就是第六张图,显示了投资资产回撤的情况,这个表我们过一会来仔细分析。

最下面还有并列的三张图表,分别统计了历史上历年或历月的收益率,其中可以看到整个十年中有三年(2011年、2016年和2018年)的收益率是负的,其余年份均实现了正收益。

了解了可视化图表,我们来分析历史曲线,大家可以看着历史回报率曲线图,并开始设想,加入我按这个投资策略开始投资,从2015年6月3日开始,我的收益率会如何?结果是:到2016年6月13日亏损50.6%,然后一直到2020年2月才能解套!如下图:

同样,我们从第六张underwater图中也可以看到,在整个十年投资期间,总资产不断地出现回撤,50%回撤是最大最深的一次,但前期还有31%、22%的多次回撤,而且长度都不短,整个投资就是“长期被套牢,偶尔能翻盘”的状况,我相信,没有几个投资者能够熬得住这样的煎熬的,对吧?


如上图,整个十年间除2015年前后或者2020年下半年以外,几乎都处于潜水套牢状态。

因此,我们可以想办法改进一下这个策略,看看如何能够降低回撤,提升策略的性能。为此,我们需要仔细分析模拟交易回测过程中的每一笔交易,寻找降低回撤的办法。要查看回测交易的每一个细节,那就需要查看交易明细报告。

交易明细报告

我们在回测的时候,设置了print_backtest_log=True,因此系统会生成详细的交易明细报告。这份报告被保存在了qteasy/log路径下,可以看到包含两个报告,两个报告都保存为csv文件,便于用Excel打开:

打开第一个文件可以看到交易日志,交易日志中记录了每一个交易日资金的变动,持股的变动、每种股票的交易明细等信息,不管是否有交易或持股变动,每天都有记录:

从上面的文件中可以看到,1月4日买入了31份沪深300指数,到1月5日收盘时卖出了持有的沪深300指数31份,并在1月6日收盘时买入87份创业板指,并在1月7日继续持有。。。
而打开trade_records.csv文件可以看到,这里记录了每一笔成交的交易,包括交易日期、买卖方向、交易份额、价格、总金额、交易费率等等信息,由于只记录有交易的实际发生,因此信息更加紧凑:

仔细分析上面的表格,会发现这个投资策略除了在换股的时候以外,都是满仓持有的,在2015年中的股灾期间也不例外,我们找到这段时间会发现,从2015年的6月18日开始,不管是沪深300指数还是创业板指数,他们的20日收益率都已经由正转负,表明后市已经开始下跌了,然而此时策略仍然坚定地持有创业板指,这是因为创业板指的跌幅要小于沪深300,也就是收益率大于沪深300:

所以其实这时候我们的策略仍然选择了正确的指数,只不过因为两个指数都在跌,我们的策略选择了跌的少的那一个持有,减少了我们的损失。

那么,我们可否从这里出发改进我们的策略呢?思路很简单,我们可以加一条规则:

  • 每天计算两个指数在过去20天的涨幅,也就是今天的价格相对于20天前价格的涨幅
  • 如果选股日两个指数都小于0,那么我们第二天就空仓,一个指数都不持有
  • 否则,选择涨幅较大的那个指数,在第二天持有,同时卖掉涨幅较小的指数

我们在原来的简单选股规则基础上增加了一条“过滤条件”,将两个指数都小于0的情况排除在外,好了,那么在qteasy中如何调整,以反映这个新的修改呢?

改进后的策略设置

qteasy的内置选股策略提供了一个过滤条件condition属性,默认条件下condition='any',代表没有过滤条件,现在我们需要把小于0的收益率过滤掉,因此可以设置condition='greater'同时设置过滤范围ubound=0即可:

op.set_parameter(0, sample_freq='d',sort_ascending=False,proportion_or_quantity=1,pars=(20, ),data_types='close',condition='greater',  # 新增过滤条件:20日涨幅大于等于ubound=0)  # 过滤条件值:0

上面的设置跟前一节基本相同,增加了两个参数:

  • condition='greater':含义是增加过滤条件,N日涨幅必须大于等于某个值才能参加选股,这个值在ubound参数中设置。也就是说排除掉小于这个值的股票,让其无法中选
  • ubound=0: 设置为0,这样只有涨幅大于等于0的指数才能被选中,当然还可以设置为其他浮点数

改进后的结果

同样按照前面的配置,直接执行qt.run()。这里直接放结果:

res=qt.run(op, visual=True, print_backtest_log=True)
     ====================================|                                  ||       BACK TESTING RESULT        ||                                  |====================================qteasy running mode: 1 - History back testing
time consumption for operate signal creation: 108.1ms
time consumption for operation back looping:  914.3msinvestment starts on      2011-01-04 00:00:00
ends on                   2020-12-31 00:00:00
Total looped periods:     10.0 years.-------------operation summary:------------Sell Cnt Buy Cnt Total Long pct Short pct Empty pct
000300.SH    82       85    167   24.4%      0.0%     75.6%
399006.SZ    90      104    194   41.2%      0.0%     58.8%   Total operation fee:     ¥    5,535.42
total investment amount: ¥  100,000.00
final value:              ¥1,006,560.22
Total return:                   906.56%
Avg Yearly return:               25.98%
Skewness:                         -0.23
Kurtosis:                          4.79
Benchmark return:                63.38%
Benchmark Yearly return:          5.03%------strategy loop_results indicators------
alpha:                            0.285
Beta:                             0.624
Sharp ratio:                      1.029
Info ratio:                       0.055
250 day volatility:               0.208
Max drawdown:                    20.26% peak / valley:        2015-06-03 / 2015-08-06recovered on:         2015-10-20
===========END OF REPORT=============

可视化图表如下:

从资产收益率图上可以看到,原来一片绿色(全程持仓)变成了白绿相间(白色区间空仓持币),资产回撤情况得到了大幅度优化:从原来的50%回撤降低到了20%左右。而且总回报率也大大提升:

  • 资产总额从改进前的五十多万提高到一百万
  • 总收益率从400%提升到了900%
  • 年化收益率从17%提升到了26%
  • 最大回撤从50%降低到了20%

看来我们的策略优化是成功的,通过计算两个指数的收益率,我们在两个指数之间轮动,同时避开股灾等两个指数都下跌的行情,我们竟然可以得到一个收益率20倍于沪深300的投资策略。

通过查看交易记录可知,的确策略在2015年6月底的股灾期间保持空仓,躲避了单边下跌的行情。

策略思路的延伸

到这里我们这篇文章就结束了,不过关于策略的优化还可以不断进行,大家可以自己尝试一下调整策略的不同参数,例如不用20日收益率,用10日、30日收益率看看效果会如何变化?另外,过滤参数也可以调整,例如过滤掉涨幅小于0.1%的指数,或者过滤掉涨幅小于-0.1%的指数。另外,是否可以不用沪深300和创业板,用别的指数代替?或者用ETF基金?等等

希望大家可以在评论区分享自己的想法和思路,我们一起开拓思路,找到更好的交易策略!

Python量化投资——年化收益26%,一个大小盘轮轮动量化投资策略的回测效果相关推荐

  1. 量化:年化收益、期初收益、期末收益、年份,任意3个值计算剩下的1个值

    1 网页计算器可以参考:(新浪财经投资收益计算器)http://finance.sina.com.cn/money/283/2005/0708/19.html 计算方法 由图可知: F V = ( 1 ...

  2. cad模型轻量化_CAD环境下一种支持大装配的产品模型轻量化技术

    CAD环境下一种支持大装配的产品模型轻量化技术 针对CAD环境下操作复杂大装配常出现加载和显示困难的问题,提出了一种CAD环境下的轻量化解决方案,将参数化表达和多细节层次(LOD)轻量表达共同定义于产 ...

  3. 量化评估--年化收益、最大回撤、阿尔法、贝塔、夏普比率解释

    年化收益率 年化收益率是把当前收益率(日收益率.周收益率.月收益率)换算成年收益率来计算的.例如日收益率是万分之一,则年化收益率是3.65﹪(平年是365天). 年化收益率=[(投资内收益 / 本金) ...

  4. HTMLTestRunner 汉化版---来源一个大神的源码(加了失败截图,用例失败重新执行 功能)...

    HTMLTestRunner 汉化版 20170925 测试报告完全汉化,包括错误日志的中文处理 针对selenium UI测试增加失败自动截图功能 增加失败自动重试功能 增加饼图统计 同时兼容pyt ...

  5. 时间加权平均价格算法(TWAP)和成交量平均算法(VWAP)在量化回测的应用

    为什么要引入TWAP和 VWAP? 为了评估策略的资金容量,我们对M.trade模块里买入点和卖出点这两个参数进行了更丰富的扩展,支持了策略能够按更丰富的算法交易价格(WAP)进行撮合. 如果资金是1 ...

  6. Python 量化投资实战教程(2) —MACD策略(+26.9%)

    量化投资系列文章: Backtrader 教程 - Python 量化投资实战教程(1) Python 量化投资实战教程(2) -MACD策略(+26.9%) Python 量化投资实战教程(3) - ...

  7. Python量化投资——投资组合的评价和可视化(上):计算收益率、波动率、最大回撤、阿尔法alpha、贝塔beta、夏普率Sharp等指标【源码+详解】

    投资组合的评价和可视化(上)--评价指标的计算 投资结果评价 本文示例数据下载 投资过程回顾 基于收益的投资组合评价 收益率.年化收益.每日收益率 月度历史收益率 基于风险度量的投资组合评价 Vola ...

  8. 【StudyQuant| Python量化投资- 量化研究 - 系列7】多种仓位管理的方法,固定止盈止损 与 移动止盈止损

    前言 StudyQuant -[量化投资教学系列帖子],通过实际案例教初学者使用python进行量化投资,分享最前沿的研究成果.希望能对大家有帮助. 量化投资文章 请点击此处 相关文章 区间震荡策略曾 ...

  9. Python 量化投资实战教程(4) —KDJ 策略

    量化投资系列文章: Backtrader 教程 - Python 量化投资实战教程(1) Python 量化投资实战教程(2) -MACD策略(+26.9%) Python 量化投资实战教程(3) - ...

  10. 上海 python量化 培训_Python量化投资实战班.上海站

    原标题:Python量化投资实战班.上海站 上海 7月27-28日 随着国内量化投资的发展,第三方量化平台费用高,策略保密性差,开发环境局限等弊端不断涌现.VNPY作为一个开源的量化交易系统项目,具备 ...

最新文章

  1. Python、Unicode和中文
  2. C# 世界坐标 页面坐标 PageUnit PageScale
  3. 算法-- 删除排序链表中的重复元素(Java)
  4. cstart做int型转换运算Java,Java实验练习题目-供练习参考
  5. tomcat配置文件server.xml详解
  6. 谷歌发布第二代TPU,并提供了免费试用方案
  7. 人脸Pose检测:ASM、AAM、CLM方法总结
  8. C# 获取文件MD5值的方法
  9. Leetcode每日一题:7.整数反转
  10. Linux Redhat下安装Jenkins
  11. 给网站插入一个百度地图API
  12. 滴滴回应未删道歉微博;阿里 P7 员工租自如病亡;苹果无人车出事故 | 极客头条...
  13. java窗体程序秒表,帮忙解释一个Java小程序(秒表)
  14. ACCESS_REFUSED - operation not permitted on the default exchange
  15. T-SQL笔记8:索引
  16. 计算机硬件 试题,计算机硬件试题150完整版
  17. 什么是计算机病毒?中国黑客教父告诉你
  18. vue3 axios 封装
  19. 桌面上的计算机打不开怎么办,电脑桌面计算机打不开怎么办
  20. 基于java的springboot宠物商城系统毕业设计springboot开题报告

热门文章

  1. 题解 P2919 【[USACO08NOV]守护农场Guarding the Farm】
  2. irr java_java-irr: java版的IRR和XIRR,通过牛顿算法实现内部收益率的计算
  3. word文档插入尾注,并且设置尾注在参考文献这一章
  4. mysql实现oracle的同义词_Oracle 同义词synonym 学习
  5. Failed to open the host Key database file
  6. C++实现IE缓存迭代器
  7. 优锘科技:森数据初体验
  8. Flash Player去广告下载地址
  9. 入门级蛋白质结构查看PyMol的使用——PyMol常用命令
  10. matlab求dfa指数,关于使用MF-DFA方法计算广义Hurst指数的MATLAB操作问题