使用BackTrader等量化软件做交易会生成大量的测试数据, 策略的好坏及稳定性等都要通过回测结果的分析来进行判定。
常用的量化分析指标一般分为三类:
下面进行具体分析。
Return收益指标。
就量化策略而言, 最重要的就是投资回报率这个指标, 其主要用于评估策略模型的稳定性。 而好的量化策略的关键就是具有稳定性, 能够获取稳定的投资回报率。 判断策略稳定的标准是: 在多种产品组合和多个时间周期的情况下都能够稳定盈利。
对于初学者而言, 重点关注投资回报率指标就可以了。 其他指标通常在投资回报率差不多的情况下, 对策略做一些辅助优化即可。
Risk风险指标。包含:
Factor多因子指标。
专业因子指标如下。
就目前国内量化交易的实际情况而言, 初学者只需重点掌握 BackTrader软件的常用功能, 能够灵活使用即可, 不需要对多因子进行深入分析。
内置Analyzer分析类的主要指标如下:
● AnnualReturn, 年化回报率。
● Calmar, 卡曼指数。
● DrawDown, 最大回撤数据。
● TimeDrawDown, 不同周期的最大回撤数据。
● PositionsValue, 仓位变化数据。
● PyFolio, 专业Folio量化图表分析。
● LogReturnsRolling, 对数化回报率分析。
● PeriodStats, 周期分析。
● Returns, 回报率。
● SharpeRatio, 夏普指数。
● SharpeRatio_A, 修正版夏普指数。
● SQN, 策略评估指数。
● TimeReturn, 周期回报率。
● TradeAnalyzer, 交易分析。
● Transactions, 逐笔订单分析。
● VWR, 动态加权回报率。
比较专业的Analyzer分析类指标, 只在进行一些特殊分析的时候才需要使用, 本节讲解比较简单的量化回测分析案例, 介绍量化分析的基本操作, 仅使用到一些常用的量化分析指标, 如Sharp、 MaxDown等。
在Analyzer分析模块中, 最重要的子模块是analyzer.Analyzer子模块。
在analyzer.Analyzer子模块内部分布图中, 以“_”开头的函数是类内部函数, 其他主要函数如下。
● 常规量化操作函数: next、 prenext、 nextstart、 start、 stop。
● 数据获取函数: get_analysis。
● 数据传递函数: notify_cashvalue、 notify_trade、 notify_order、notify_fund。
● 其他类函数: Create_analysis、 print、 pprint。
此外还有两个重要的函数: csv、 rets。
下图所示是 Analyzer 分析模块的核心部分,改图中最左边的圆形中的内容,是整个模块的入口:
从上图可以看到 ,Analyzer 分析模块的核心是 Analyzer 分析类及其类函数。Analyzer 分析类及其类函数又分为两个子类:
注意, MetaTimeFrameAnalyzer(元数据分析的时间周期分析) 子类源自TimeFrameAnalyzer子类, 而不是由MetaAnalyzer子类派生出的。
在BackTrader量化软件中, 把Analyzer分析模块中的TimeFrameAnalyzer子类作为核心子类, 而在其他量化软件中, 通常把时间周期分析也作为一个量化分析指标。
MetaAnalyzer子类的设计非常巧妙, 其中的Meta元数据可以导入各种专业量化指标, 从而衍生出各种专业的量化分析指标, 如SQN指数、Sharp指数、 MaxDown等常用量化分析指标。
这种巧妙的设计架构, 非常方便用户扩展各种量化分析指标和各种自定义分析指标, 大大简化了用户的编程工作。
下面再看一看 analyzer.Analyzer 子模块架构图, 如下图所示。由图可以看出, analyzer.Analyzer子模块是所有分析模块的基础, 定义了量化分析主要的类函数。 其中以“_”开头的函数是类内部函数, 其他主要函数有以下几类。
● 常规量化操作函数: next、 prenext、 nextstart、 stop、 start。
● 数据获取函数: get_analysis。
● 数据传递函数: notify_trade、 notify_order、 notify_fund。
● 其他类函数: create_analysis、 print、 pprint。
SQN 指数全称为 System Quality Number
,即系统质量指数,用来评估量化策略的优劣。SQN 的计算公式为:
SQN=root(n)×expectancy/stdev(R)
(SQN=交易次数n的平方根×交易系统的期望值/期望值的标准差)
其中,
root(n) : 一年交易次数n的平方根。
expectancy: 交易系统的期望值, 以倍数(风险回报比) 表示。
stdev(R) : 期望值的标准差。
评测的交易总次数最多不能超过100, 当然, 交易次数也有下限,即不能少于30。 当交易数量≥30时, SQN指数通常被认为是可靠的。
SQN指数具有如下意义:
● 交易次数越多, 获利机会越大。
● 风险回报比越大越好。
● 风险回报比的标准差越小, 交易结果越具有规律性, 回撤越小。
SQN指数公式很简单, 要优化SQN指数也很简单:
● 使交易次数和平均风险回报比的乘积尽可能大。
● 使公式中的期望值标准差尽可能小。
本实例代码 Analyzer1.py 。
本节案例增加了一些回测分析函数指标,重点是 addanalyzer
分析指标添加函数:
print("\n\t#2-5,设置每手交易数目为:10,不再使用默认值:1手")
cerebro.addsizer(bt.sizers.FixedSize, stake=10)
print("\n\t#2-6,设置addanalyzer分析参数")
cerebro.addanalyzer(SQN)
#
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="SharpeRatio", legacyannual=True)
cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name="AnnualReturn")
#
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="TradeAnalyzer")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="DW")
以上代码为量化程序添加 SQN 指数、Sharp 指数、MaxDown 常用量化分析指标。
addanalyzer
策略添加函数中改的 name 参数变量,主要用于分析结果和图标绘制。这些指标名称可以通过name 参数设置,一般使用默认模式,即指标函数名称。下图是该函数关系属性示意图:
量化分析编程主要有两个环节:
addanalyzer
添加各种指标。在量化回测结果数据中提取各种分析数据,需要从量化回测的返回值中获取分析数据:
print("\n#3,调用BT回测入口程序,开始执行run量化回测运算")
results = cerebro.run()
通过如下代码,把相关的回测结果数据提取出来,保存到 anzs 变量中:
# ---------
print("\n#5,analyzer分析BT量化回测数据")
strat = results[0]
anzs = strat.analyzers
#
dsharp = anzs.SharpeRatio.get_analysis()["sharperatio"]
trade_info = anzs.TradeAnalyzer.get_analysis()
#
dw = anzs.DW.get_analysis()
max_drowdown_len = dw["max"]["len"]
max_drowdown = dw["max"]["drawdown"]
max_drowdown_money = dw["max"]["moneydown"]
#
print("\t夏普指数SharpeRatio : ", dsharp)
print("\t最大回撤周期 max_drowdown_len : ", max_drowdown_len)
print("\t最大回撤 max_drowdown : ", max_drowdown)
print("\t最大回撤(资金)max_drowdown_money : ", max_drowdown_money)
anzs
变量用于保存回测分析数据,该变量本身是复合字典格式,提取的各组分析数据都是标准的 dict 字典格式,各组分析数据的返回值也都是 dict 字典格式,可方便大家提取使用。各组回测结果都保存在 Analyzer 分析类的 rets
属性中,可以通过 get_analysis
函数读取。
下图是 get_analysis
函数关系属性图:
由图可以看出,相关的分析结果不仅可以通过 rets 变量导出,也可以通过内置的 print、pprint 两个输出函数直接输出,而且输出的数据格式均进行过分组处理。
本案例生成图片如下:
本案例各分析指标输出内容为:
#5,analyzer分析BT量化回测数据
夏普指数SharpeRatio : -66.94067728496657
最大回撤周期 max_drowdown_len : 269
最大回撤 max_drowdown : 0.03984537510517593
最大回撤(资金)max_drowdown_money : 39.85270000001765
本实例代码: Analyzer2.py 。
上个案例已经添加了一些分析指标,本案例继续添加如下分析指标:
添加分析指标的代码如下:
# 周期回报率,不同时间周期
cerebro.addanalyzer(
bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years, _name="timReturns"
)
# cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Months,_name='timReturns')
#
# 动态加权回报率 Variability-Weighted Return: Better SharpeRatio with Log Returns
cerebro.addanalyzer(bt.analyzers.VWR, _name="VWR")
添加输出代码如下:
#
print("\t#5-2,常用量化分析数据")
print("\tSQN指数、AnnualReturn年化收益率,Trade交易分析报告")
print("\t可以通过修改参数,改为其他时间周期:周、月、季度等")
for alyzer in strat.analyzers:
alyzer.print()
本案例生成图片如下:
输入内容如下:
#5,analyzer分析BT量化回测数据
5-1夏普指数SharpeRatio : -66.94067728496657
最大回撤周期 max_drowdown_len : 269
最大回撤 max_drowdown : 0.03984537510517593
最大回撤(资金)max_drowdown_money : 39.85270000001765
#5-2,常用量化分析数据
SQN指数、AnnualReturn年化收益率,Trade交易分析报告
可以通过修改参数,改为其他时间周期:周、月、季度等
===============================================================================
SQN:
- sqn: 1.0152350590677315
- trades: 32
===============================================================================
SharpeRatio:
- sharperatio: -66.94067728496657
===============================================================================
AnnualReturn:
- 2020: 8.860000000066037e-05
- 2021: 0.00038036629954540935
===============================================================================
TradeAnalyzer:
-----------------------------------------------------------------------------
- total:
- total: 32
- open: 0
- closed: 32
-----------------------------------------------------------------------------
- streak:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- won:
- current: 1
- longest: 9
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- lost:
- current: 0
- longest: 2
-----------------------------------------------------------------------------
- pnl:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- gross:
- total: 53.19999999999992
- average: 1.6624999999999974
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- net:
- total: 46.89999999999994
- average: 1.4656249999999982
-----------------------------------------------------------------------------
- won:
- total: 22
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- pnl:
- total: 122.12029999999996
- average: 5.5509227272727255
- max: 23.0399
-----------------------------------------------------------------------------
- lost:
- total: 10
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- pnl:
- total: -75.22030000000002
- average: -7.522030000000003
- max: -15.918399999999988
-----------------------------------------------------------------------------
- long:
- total: 32
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- pnl:
- total: 46.89999999999994
- average: 1.4656249999999982
*************************************************************************
- won:
- total: 122.12029999999996
- average: 5.5509227272727255
- max: 23.0399
*************************************************************************
- lost:
- total: -75.22030000000002
- average: -7.522030000000003
- max: -15.918399999999988
- won: 22
- lost: 10
-----------------------------------------------------------------------------
- short:
- total: 0
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- pnl:
- total: 0.0
- average: 0.0
*************************************************************************
- won:
- total: 0.0
- average: 0.0
- max: 0.0
*************************************************************************
- lost:
- total: 0.0
- average: 0.0
- max: 0.0
- won: 0
- lost: 0
-----------------------------------------------------------------------------
- len:
- total: 242
- average: 7.5625
- max: 26
- min: 1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- won:
- total: 98
- average: 4.454545454545454
- max: 15
- min: 1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- lost:
- total: 144
- average: 14.4
- max: 26
- min: 1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- long:
- total: 242
- average: 7.5625
- max: 26
- min: 1
*************************************************************************
- won:
- total: 98
- average: 4.454545454545454
- max: 15
- min: 1
*************************************************************************
- lost:
- total: 144
- average: 14.4
- max: 26
- min: 1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- short:
- total: 0
- average: 0.0
- max: 0
- min: 9223372036854775807
*************************************************************************
- won:
- total: 0
- average: 0.0
- max: 0
- min: 9223372036854775807
*************************************************************************
- lost:
- total: 0
- average: 0.0
- max: 0
- min: 9223372036854775807
===============================================================================
DrawDown:
- len: 31
- drawdown: 0.016181390901583496
- moneydown: 16.191600000005565
-----------------------------------------------------------------------------
- max:
- len: 269
- drawdown: 0.03984537510517593
- moneydown: 39.85270000001765
===============================================================================
TimeReturn:
- 2020-12-31: 8.860000000066037e-05
- 2021-12-31: 0.00038036629954540935
===============================================================================
VWR:
- vwr: 0.02078841499279231
输出信息中的TimeReturn时间周期回报率, 使用的周期也是year(年度) , 所以最终数据和使用annual_return年化回报率完全相同。