分析仪Analyzers- backtrader中文教程
无论是回测还是交易,能够分析交易系统的性能是了解是否不仅获得了利润,而且还获得了太多的风险,或者与其他交易相比是否真的值得付出努力参考资产(或无风险资产)
这就是Analyzer
对象系列的用武之地:提供对发生的事情甚至实际发生的事情的分析。
分析仪的性质
该接口是根据Lines对象的接口建模的,例如一个 next
方法,但有一个主要区别:
Analyzers
不要保持线。这意味着它们在内存方面并不昂贵,因为即使在分析了数千条价格柱之后,它们仍然可能只是在内存中保存一个结果。
在生态系统中的位置
Analyzer
对象(如策略、观察者和数据cerebro
)通过实例添加到系统中:
addanalyzer(ancls, *args, **kwargs)
但是当涉及到以下操作时,系统中存在的cerebro.run
每个策略都会发生
ancls
将被实例*args
化**kwargs
cerebro.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
的计算最小周期之后调用。next
prenext
and的默认行为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.OrderedDict
Analyzer的子类可以重写此方法以更改此行为
分析器模式
平台中分析器对象的开发backtrader
揭示了生成分析的 2 种不同使用模式:
notify_xxx
在执行期间通过在和 方法中收集信息next
,并生成分析的当前信息next
例如
TradeAnalyzer
,仅使用notify_trade
方法来生成统计信息。- 收集(或不收集)上述信息,但在
stop
方法期间一次性生成分析( System Quality Number
SQN
)在该方法期间收集交易信息, 但在该方法期间生成统计信息notify_trade
stop
一个简单的例子
尽可能简单:
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
不需要,但是每次调用父策略后都会调用这个方法next
start
方法在回测开始之前调用。可用于额外的初始化任务。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].name
self.data_name
->self.datas[0].name
self.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
通过实际返回分析器操作的策略的当前长度来调用分析器