分析仪Analyzers- backtrader中文教程
无论是回测还是交易,能够分析交易系统的性能是了解是否不仅获得了利润,而且还获得了太多的风险,或者与其他交易相比是否真的值得付出努力参考资产(或无风险资产)
这就是Analyzer对象系列的用武之地:提供对发生的事情甚至实际发生的事情的分析。
分析仪的性质
该接口是根据Lines对象的接口建模的,例如一个 next方法,但有一个主要区别:
Analyzers不要保持线。这意味着它们在内存方面并不昂贵,因为即使在分析了数千条价格柱之后,它们仍然可能只是在内存中保存一个结果。
在生态系统中的位置
Analyzer对象(如策略、观察者和数据cerebro)通过实例添加到系统中:
addanalyzer(ancls, *args, **kwargs)
但是当涉及到以下操作时,系统中存在的cerebro.run每个策略都会发生
ancls将被实例*args化**kwargscerebro.run- 实例将
ancls附加到策略
这意味着:
- 如果回测运行包含例如3 个策略,则将创建3 个实例,
ancls并且每个实例都将附加到不同的策略。
底线:分析器分析单个策略的性能,而 不是整个系统的性能
附加位置
有些Analyzer对象实际上可能会使用其他分析器来完成其工作。例如:SharpeRatio使用 的输出TimeReturn进行计算。
这些子分析器或从分析器也将被插入到与创建它们的策略相同的策略中。但它们对用户是完全不可见的。
属性
为了执行预期的工作,Analyzer为对象提供了一些默认属性,这些属性会自动传递并在实例中设置以方便使用:
self.strategy: 引用分析器对象在其中运行的策略子类。分析器也可以访问策略可访问的任何内容self.datas[x]:策略中存在的数据馈送数组。虽然这可以通过策略参考来访问,但快捷方式使工作更加舒适。self.data:获得额外舒适感的捷径self.datas[0]。self.dataX: 不同的捷径self.datas[x]
其他一些别名是可用的:
* `self.dataX_Y` 其中 X 是对 `self.datas[X]` 的引用,`Y`是指行,最后指向:`self.datas[X].lines[Y]` 如果该行有名称,则以下内容也可用:
* `self.dataX_Name` 解析为 `self.datas[X].Name`按名称而不是索引返回行
对于第一个数据,最后两个快捷方式在没有初始 X数字引用的情况下可用。例如:
* `self.data_2` 指的是`self.datas[0].lines[2]`
返回分析
Analyzer基类创建一个self.rets(类型为 collections.OrderedDict)成员属性以返回分析。这是在create_analysis创建自定义分析器时可以被子类覆盖的方法中完成的。
操作模式
尽管Analyzer对象不是Lines对象,因此不会迭代行,但它们被设计为遵循相同的操作模式。
- 在系统启动之前实例化(因此调用
__init__) - 用
start prenext//将在指标工作策略nextstart的计算最小周期之后调用。nextprenextand的默认行为nextstart是调用 next,因为分析器可能从系统处于活动状态的第一刻起就开始分析。len(self)习惯上调用Lines对象来检查柱的实际数量。这也可以Analyzers通过返回值来实现self.strategy- 订单和交易将像通知策略一样通过
notify_order和notify_trade - 现金和价值也将被通知,就像通过
notify_cashvalue方法上的策略完成一样 - 现金、价值和基金价值以及基金份额也将被通知,就像通过
notify_fund方法完成的策略一样 stop将被调用以表示操作结束
完成常规操作周期后,分析仪具有用于提取/输出信息的其他方法
get_analysis: 理想情况下(不强制)返回一个dict包含分析结果的类似对象。print使用标准backtrader.WriterFile(除非被覆盖)从get_analysis.pprint( pretty print ) 使用 Pythonpprint模块来打印get_analysis结果。
最后:
get_analysis创建分析器写入分析结果的成员属性self.ret(类型 )。collections.OrderedDictAnalyzer的子类可以重写此方法以更改此行为
分析器模式
平台中分析器对象的开发backtrader揭示了生成分析的 2 种不同使用模式:
notify_xxx在执行期间通过在和 方法中收集信息next,并生成分析的当前信息next例如
TradeAnalyzer,仅使用notify_trade方法来生成统计信息。- 收集(或不收集)上述信息,但在
stop方法期间一次性生成分析( System Quality Number
SQN)在该方法期间收集交易信息, 但在该方法期间生成统计信息notify_tradestop
一个简单的例子
尽可能简单:
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import datetime
import backtrader as bt
import backtrader.analyzers as btanalyzers
import backtrader.feeds as btfeeds
import backtrader.strategies as btstrats
cerebro = bt.Cerebro()
# data
dataname = '../datas/sample/2005-2006-day-001.txt'
data = btfeeds.BacktraderCSVData(dataname=dataname)
cerebro.adddata(data)
# strategy
cerebro.addstrategy(btstrats.SMA_CrossOver)
# Analyzer
cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='mysharpe')
thestrats = cerebro.run()
thestrat = thestrats[0]
print('Sharpe Ratio:', thestrat.analyzers.mysharpe.get_analysis())
执行它(已将其存储在analyzer-test.py:
$ ./analyzer-test.py
Sharpe Ratio: {'sharperatio': 11.647332609673256}
没有绘图,因为SharpeRatio是计算结束时的单个值。
分析仪的取证分析
再说一遍,Analyzers不是 Lines 对象,而是为了将它们无缝集成到backtrader生态系统中,遵循几个 Lines 对象的内部 API 约定(实际上是它们的混合)
SharpeRatio的代码已经发展到例如考虑到年化,这里的版本应该只是一个参考。from __future__ import (absolute_import, division, print_function,
unicode_literals)
import operator
from backtrader.utils.py3 import map
from backtrader import Analyzer, TimeFrame
from backtrader.mathsupport import average, standarddev
from backtrader.analyzers import AnnualReturn
class SharpeRatio(Analyzer):
params = (('timeframe', TimeFrame.Years), ('riskfreerate', 0.01),)
def __init__(self):
super(SharpeRatio, self).__init__()
self.anret = AnnualReturn()
def start(self):
# Not needed ... but could be used
pass
def next(self):
# Not needed ... but could be used
pass
def stop(self):
retfree = [self.p.riskfreerate] * len(self.anret.rets)
retavg = average(list(map(operator.sub, self.anret.rets, retfree)))
retdev = standarddev(self.anret.rets)
self.ratio = retavg / retdev
def get_analysis(self):
return dict(sharperatio=self.ratio)
代码可以分解为:
params宣言尽管未使用已声明的对象(仅作为示例),但分析器
backtrader与支持参数 中的大多数其他对象一样__init__方法就像Strategies在 中声明指标
__init__一样,带有支持对象的分析器也是如此。在这种情况下:
SharpeRatio使用年回报率计算。计算将是自动的,并可SharpeRatio用于自己的计算。Tips:实际实现
SharpeRatio使用更通用和后来开发的TimeReturn分析器
next方法SharpeRatio不需要,但是每次调用父策略后都会调用这个方法nextstart方法在回测开始之前调用。可用于额外的初始化任务。Sharperatio不需要它
stop方法在回测结束后立即调用。像
SharpeRatio这样,它可以用来完成/进行计算get_analysis方法(返回字典)外部调用者访问生成的分析
返回:带有分析的字典。
参考
class backtrader.Analyzer()
分析器基类。所有分析器都是这个的子类
Analyzer 实例在策略框架中运行,并为该策略提供分析。
自动设置成员属性:
self.strategy(提供对策略的访问权限以及从中可访问的任何内容)self.datas[x]允许访问系统中存在的数据源数组,也可以通过策略参考访问self.data, 允许访问self.datas[0]self.dataX->self.datas[X]self.dataX_Y->self.datas[X].lines[Y]self.dataX_name->self.datas[X].nameself.data_name->self.datas[0].nameself.data_Y->self.datas[0].lines[Y]
这不是Lines对象,但方法和操作遵循相同的设计
__init__在实例化和初始设置期间start/stop表示操作的开始和结束prenext / nextstart / next中next相同方法的方法族notify_trade/notify_order/notify_cashvalue/notify_fund 接收与策略的等效方法相同的通知
操作模式是开放的,没有模式是首选。因此,可以通过next调用生成分析,在操作结束时stop,甚至使用单个方法,如notify_trade
重要的是重写get_analysis以返回包含分析结果的类似dict的 对象(实际格式取决于实现)
start()
调用以指示操作的开始,让分析器有时间设置所需的东西
stop()
调用以指示操作结束,让分析器有时间关闭所需的东西
prenext()
为策略的每个 prenext 调用调用,直到达到策略的最短周期
分析器的默认行为是调用next
nextstart()
为策略的 nextstart 调用仅调用一次,此时已首次达到最短周期
next()
一旦达到策略的最小周期,每次下一次调用策略时调用
notify_cashvalue(cash, value)
在每个下一个周期之前收到现金/价值通知
notify_fund(cash, value, fundvalue, shares)
收到当前现金、价值、基金价值和基金份额
notify_order(order)
在每个下一个周期之前接收订单通知
notify_trade(trade)
在每个下一个周期之前接收交易通知
get_analysis()
返回带有分析结果的类字典对象
字典中分析结果的键和格式取决于实现。
甚至没有强制结果是一个类似字典的对象,只是约定
默认实现返回默认方法rets 创建的默认 OrderedDictcreate_analysis
create_analysis()
意味着被子类覆盖。有机会创建进行分析的结构。
默认行为是创建一个OrderedDict命名的rets
print(*args, **kwargs)
打印get_analysis通过标准 Writerfile对象返回的结果,默认将内容写入标准输出
pprint(*args, **kwargs)
get_analysis使用漂亮的打印 Python 模块 ( pprint )打印返回的结果
len()
支持len通过实际返回分析器操作的策略的当前长度来调用分析器