《BackTrader量化交易图解》第9章:回测结果分析

9. 回测结果分析

9.1 常用量化分析指标

使用BackTrader等量化软件做交易会生成大量的测试数据, 策略的好坏及稳定性等都要通过回测结果的分析来进行判定。
常用的量化分析指标一般分为三类:

  1. Return, 收益指标。
  2. Risk, 风险指标。
  3. Factor, 多因子分析指标。

下面进行具体分析。

  1. Return收益指标。

    • Returns收益率, 通常为百分比形式的、 非累积的年/月/日等周期收益率, 即每个周期相对于上一个交易周期的收益比率。
    • annual_return, 年化回报率, 使用策略投资一年的收益率。
    • ROI, 投资回报率。
    • cum_returns, 累计收益。
    • VWR, 动态加权回报率。
    • omega_ratio, 欧米伽比率, 用来分析收益分布, 指标数值越高越好, 它是对偏度和峰值的一个调整。
    • benchmark_returns, 参考/基准(年化) 收益率, 标准指数(如SPY标普指数、 上证指数) 投资一年的收益率。

    就量化策略而言, 最重要的就是投资回报率这个指标, 其主要用于评估策略模型的稳定性。 而好的量化策略的关键就是具有稳定性, 能够获取稳定的投资回报率。 判断策略稳定的标准是: 在多种产品组合和多个时间周期的情况下都能够稳定盈利。

    对于初学者而言, 重点关注投资回报率指标就可以了。 其他指标通常在投资回报率差不多的情况下, 对策略做一些辅助优化即可。

  2. Risk风险指标。包含:

    • Alpha, 阿尔法指数, 非系统性风险投资指数。
    • Beta, 贝塔指数, 系统性风险投资指数, 反映了策略对大盘变化的敏感性。
    • Volatility, 波动率, 用来衡量策略的风险性, 波动率越大代表策略风险越高。
    • annual_volatility, 年化波动率。
    • information_ratio, 信息比率, 数值越高, 业绩表现持续优于大盘的程度越高。 该指标主要用来衡量投资组合所带来的超额收益。
    • calmar_ratio, 卡尔马比率, 是年化收益率与历史最大回撤之间的比率。 数值越大, 表示业绩越好; 数值越小, 表示业绩越差。
    • sharpe_ratio, 夏普指数/夏普比率, 是投资回报与风险的比例, 数值越大, 投资组合越佳。
    • sortino_ratio, 索提诺比率, 是夏普指数的修正版, 是用于评价投资资产、 组合或者策略收益的指标。
    • downside_risk, 下行风险, 指未来价格走势有低于投资者预期目标价位的风险。
    • tail_ratio, 尾比, 其含义是赚取的回报率比亏钱的比率大多少倍。
    • MaxDown, 最大回撤数据, 用于衡量策略可能出现的最糟糕情况。
    • SQN指数: 策略评级指数, 用于评估策略优劣。
  3. Factor多因子指标。

    • Factor Autocorrelation, 因子的自回归程度。
    • Profitable Count, 盈利的交易次数。
    • Unprofitable Count, 亏损的交易次数。
    • mean_return_by_quantile, 因子平均收益率数据。
    • mean_return_difference, 收益率差值, 即最好因子收益率减去最差因子收益率。
    • Return Ratio, 收益回撤比。
    • N-day Variance Ratio, n日方差比率。
    • Hurst, 赫斯特指数, 可衡量一个时间序列统计的相关性。
    • cumulative_returns_by_quantile, 多因子累计收益率。
    • Cash-netural Investment, 投资收益现金净值。

    专业因子指标如下。

    • 规模类因子: 总市值、 流通市值、 自由流通市值。
    • 估值类因子: 市盈率( TTM) 、 市净率、 市销率、 市现率、 企业价值倍数。
    • 成长类因子: 营业收入同比增长率、 营业利润同比增长率、 母公司利润同比增长率、 现金流金额同比增长率。
    • 盈利类因子: 净资产收益率( ROE) 、 总资产报酬率( ROA) 、销售毛利率、 销售净利率。
    • 动量反转因子: 前1~6个月涨跌幅。
    • 交投因子: 前一个月的日均换手率。
    • 波动因子: 前一个月的波动率、 前一个月的振幅。
    • 股东因子: 户均/机构持股比例、 户均/机构持股比例变化。
    • 分析师因子: 预测当年净利润增长率、 主营业务收入增长率, 以及最近一个月的净利润上调幅度、 主营业务收入上调幅度、 上调评级占比。

就目前国内量化交易的实际情况而言, 初学者只需重点掌握 BackTrader软件的常用功能, 能够灵活使用即可, 不需要对多因子进行深入分析。

9.2 Analyzer 分析类

内置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。

9.3 Analyzer 分析模块架构图

下图所示是 Analyzer 分析模块的核心部分,改图中最左边的圆形中的内容,是整个模块的入口:

btr_anz001

从上图可以看到 ,Analyzer 分析模块的核心是 Analyzer 分析类及其类函数。Analyzer 分析类及其类函数又分为两个子类:

  • TimeFrameAnalyzer,时间周期分析子类;
  • MetaAnalyzer,元数据分析子类。

注意, 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。

btr_anz002

9.4 SQN 指数

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指数也很简单:
● 使交易次数和平均风险回报比的乘积尽可能大。
● 使公式中的期望值标准差尽可能小。

9.5 案例:回测数据基本分析

本实例代码 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 参数设置,一般使用默认模式,即指标函数名称。下图是该函数关系属性示意图:

btr_add_anz

量化分析编程主要有两个环节:

  1. 在主程序源码中的数据设置部分,设置各种常用的分析指标,并使用 addanalyzer 添加各种指标。
  2. 当量化程序运行完成时,在量化回测结果数据中提取各种分析数据。

在量化回测结果数据中提取各种分析数据,需要从量化回测的返回值中获取分析数据:

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 函数关系属性图:

btr_add_sta

由图可以看出,相关的分析结果不仅可以通过 rets 变量导出,也可以通过内置的 print、pprint 两个输出函数直接输出,而且输出的数据格式均进行过分组处理。

本案例生成图片如下:

Analyzer1

本案例各分析指标输出内容为:

#5,analyzer分析BT量化回测数据
        夏普指数SharpeRatio :  -66.94067728496657
        最大回撤周期 max_drowdown_len :  269
        最大回撤 max_drowdown :  0.03984537510517593
        最大回撤(资金)max_drowdown_money :  39.85270000001765

9.6 案例:回测数据扩展指标分析

本实例代码: Analyzer2.py

上个案例已经添加了一些分析指标,本案例继续添加如下分析指标:

  • TimeReturn, 周期回报率
  • VWR, 动态加权回报率。

添加分析指标的代码如下:

# 周期回报率,不同时间周期
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()

本案例生成图片如下:

Analyzer2

输入内容如下:

#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年化回报率完全相同。

代码仓库链接:CPythoner/BackTraderDemo at develop (github.com)

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
由于backtrader是一个Python开源框架,可以用于量化交易,因此可以通过编程来实现量化交易策略。下面是一个简单的backtrader量化交易案例图解。 假设我们有一些历史股票价格数据,我们想要用backtrader来实现一个简单的均线策略。具体来说,当股票价格上穿均线时,我们会买入股票;当股票价格下穿均线时,我们会卖出股票。 首先,我们需要导入backtrader库: ``` import backtrader as bt ``` 接下来,我们需要定义一个backtrader策略类。在该类中,我们需要定义以下方法: 1. __init__(): 初始化策略。 2. next(): 定义策略的逻辑。 具体代码如下: ``` class MyStrategy(bt.Strategy): def __init__(self): self.sma = bt.indicators.SimpleMovingAverage(self.data.close, period=10) self.order = None def next(self): if self.order: return if not self.position: if self.data.close[0] > self.sma[0]: self.order = self.buy() else: if self.data.close[0] < self.sma[0]: self.order = self.sell() ``` 在__init__()方法中,我们定义了一个简单移动平均指标(SMA),并将其计算在每个数据点上。我们还定义了一个空的订单变量,该变量将在接下来的逻辑中用于检查我们是否已经下了订单。 在next()方法中,我们首先检查我们是否有未完成的订单。如果我们有未完成的订单,我们就返,等待订单完成后再继续。如果我们没有未完成的订单并且我们没有持仓,我们就检查当前价格是否高于SMA。如果是,我们就下单买入。如果我们已经持有了仓位,我们就检查当前价格是否低于SMA。如果是,我们就下单卖出。 接下来,我们需要加载我们的数据。假设我们有一个名为“data.csv”的文件,其中包含了我们的股票价格数据。我们可以使用以下代码来加载数据: ``` data = bt.feeds.GenericCSVData( dataname='data.csv', fromdate=datetime(2019, 1, 1), todate=datetime(2020, 1, 1), dtformat=('%Y-%m-%d'), open=1, high=2, low=3, close=4, volume=5, openinterest=-1 ) ``` 在这里,我们使用了backtrader的GenericCSVData源,该源允许我们从CSV文件中加载数据。我们还指定了数据的时间范围,以及每个数据点的格式和位置。 接下来,我们需要实例化我们的策略并运行回测。我们可以使用以下代码来完成这个过程: ``` cerebro = bt.Cerebro() cerebro.addstrategy(MyStrategy) cerebro.adddata(data) cerebro.run() ``` 在这里,我们使用backtrader的Cerebro类来实例化我们的交易引擎。我们还向引擎中添加了我们的策略和数据。最后,我们运行回测并输出结果。 总的来说,backtrader是一个非常强大的Python框架,可以用于快速实现量化交易策略。在上面的例子中,我们演示了如何使用backtrader来实现一个简单的均线策略。当然,您可以根据自己的需求和想法来设计和实现不同的量化交易策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C与Python实战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值