Backtrader教程:分析仪

  |  

无论是回溯测试还是交易,能够分析交易系统的性能是了解是否不仅获得了利润,而且是否在风险太大的情况下实现了利润,或者与参考资产(或无风险资产)相比,是否真的值得付出努力的关键。

这就是对象家族的用武之Analyzer 地:提供对所发生事件甚至实际发生的事情的分析。

analyzers的性质

该接口是根据 Lines 对象(例如next 方法)的接口建模的,但有一个主要区别:

  • Analyzers 不要握住 lines

    这意味着它们在内存方面并不昂贵,因为即使在分析了数千个价格柱之后,它们仍然可能只是在内存中保存单个结果。

在生态系统中的位置

Analyzer 对象(如策略、 observers 和数据)通过 cerebro 实例添加到系统中:

  • addanalyzer(ancls, *args, **kwargs)

但是,当涉及到操作期间cerebro.run ,系统中存在的每个策略将发生以下情况

  • ancls将在*args **kwargscerebro.run

  • 实例ancls 将附加到策略

这意味着:

  • 例如,如果回溯测试运行包含 3 个策略,则将创建 3 个实例,每个实例 ancls 将附加到不同的策略。

结论:分析器分析单个策略的性能,而不是整个系统的性能

其他位置

某些Analyzer 对象实际上可能使用其他 analyzers 来完成其工作。例如: SharpeRatio 使用的 TimeReturn 输出进行计算。

这些子analyzers 或从analyzers 也将插入到与创建它们的策略相同的策略中。但它们对用户来说是完全不可见的。

属性

为了运行预期的工作,Analyzer 对象提供了一些缺省属性,这些属性会自动传递并在实例中设置,以便于使用:

  • self.strategy:引用分析器对象在其中操作的策略子类。策略可访问的任何内容也可以由分析器访问

  • self.datas[x]:策略中存在的 data feeds 数组。尽管可以通过策略参考访问这一点,但快捷方式使工作更加舒适。

  • self.data:为增加舒适度而快捷键 self.datas[0]

  • self.dataX:不同 self.datas[x]

其他一些别名可用,尽管它们可能有些过分:

* `self.dataX_Y` where X is a reference to `self.datas[X]` and `Y`
  refers to the line, finally pointing to: `self.datas[X].lines[Y]`

如果 line 具有名称,则以下选项也可用:

* `self.dataX_Name` which resolves to `self.datas[X].Name` returning
  the line by name rather than by index

对于第一个数据, last 两个快捷方式在没有初始X 数字参考的情况下可用。例如:

* `self.data_2` refers to `self.datas[0].lines[2]`

* `self.data_close` refers to `self.datas[0].close`

返回分析

Analyzer 基类创建一个self.rets(类型collections.OrderedDict为 )成员属性以返回分析。这是在方法中完成的,如果创建自定义analyzers,则该方法create_analysis可由子类覆盖。

做法

虽然Analyzer 对象不是 Lines 对象,因此不会反复运算 lines,但它们被设计为遵循相同的操作模式。

  1. 在系统启动之前实例化(因此调用__init__

  2. 发出开始操作的信号start

  3. prenext / nextstart / next 将在指针工作的策略的计算最短周期之后被调用。

    的缺省nextstart行为prenext是调用 next,因为分析器可能从系统处于活动状态的第一刻起就开始分析。

    习惯上调用len(self)Lines对象来检查实际的柱数。这也通过返回值来工作Analyzersself.strategy

  4. 订单和交易将像notify_order 通过和 notify_trade

  5. 现金和价值也将被通知,就像策略完成的方法一notify_cashvalue

  6. 现金,价值和基金价值以及基金份额也将被通知,就像使用方法的策略notify_fund 一样

  7. stop 将被调用以指示操作结束

一旦常规操作周期完成, analyzers 具有提取/输出信息的其他方法

  • get_analysis:理想情况下(不强制)返回包含 dict 分析结果的类似对象。

  • print 使用标准 backtrader.WriterFile (除非被覆盖)从 get_analysis写入分析结果。

  • pprint (漂亮的打印)使用Python pprint 模块来打印 get_analysis resutls。

最后:

  • get_analysis 创建一个成员属性 self.ret (类型 collections.OrderedDict), analyzers 向该属性写入分析结果。

    Analyzer 的子类可以重写此方法以更改此行为

分析器模式

平台中 Analyzer 对象的backtrader 开发揭示了生成分析的 2 种不同使用模式:

  1. 在运行过程中,通过在 和 next 方法中notify_xxx收集信息,并在next

    TradeAnalyzer例如,仅使用该notify_trade方法来生成统计信息。

  2. 收集(或不收集)上述信息,但在方法过程中stop 一次性生成分析

    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 代码已经发展到例如考虑年化,这里的版本应该只是一个参考。

请查看 Analyzers 参考

另外还有一个SharpeRatio_A ,它以年化形式直接提供价值,而不管所寻求的时间范围如何

代码作为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 声明

    尽管未使用声明的对象(作为示例),但 Analyzers 与支持参数中的大多数backtrader 其他对象一样

  • __init__ 方法

    就像策略声明指针一__init__样,支持对象 analyzers 也是如此。

    在这种情况下:使用SharpeRatio年度申报表计算。计算将是自动的,并SharpeRatio可用于自己的计算。

    注意

    实际实现SharpeRatio 使用更通用和后来开发的 TimeReturn 分析仪

  • next 方法

    SharpeRatio 不需要它,但此方法将在每次调用父策略后调用 next

  • start 方法

    在回溯测试开始之前调用。可用于额外的初始化任务。夏普不需要它

  • stop 方法

    在回溯测试结束后立即调用。像SharpeRatio 这样,它可以用来完成/进行计算

  • get_analysis 方法(返回字典)

    外部调用者可以访问生成的分析

    返回:带有分析的字典。

参考

backtrader类 .分析仪()

分析器基类。所有 analyzers 都是这个的子类

Analyzer 实例在策略的框架中运行,并为该策略提供分析。

自动设置成员属性:

  • self.strategy (允许访问策略以及从中访问的任何内容)

  • self.datas[x] 允许访问系统中存在的 data feeds 数字,也可以通过策略参考访问

  • 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 遵循策略中对相同方法的调用的方法系列

  • notify_trade / notify_order / notify_cashvalue notify_fund 接收与策略的等效方法相同的通知

操作模式 open ,不首选任何模式。因此,分析可以通过next 调用生成,在操作期间 stop 甚至使用单个方法,例如 notify_trade

重要的是重写get_analysis 以返回包含分析结果的类似字典的对象(实际格式取决于实现)

开始()

调用以指示操作的开始,使分析器有时间设置所需的内容

停止()

调用以指示操作结束,使分析器有时间关闭所需的内容

prenext()

针对策略的每次前置点调用调用,直到达到策略的最小周期

分析器的缺省行为是调用next

nextstart()

在策略的下一个启动调用时仅调用一次,此时首次达到最小周期

下一步()

在策略的每次下一次调用时调用,一旦达到策略的最小值

notify_cashvalue(现金,价值)

在每个下一个周期之前收到现金/价值通知

notify_fund(现金、价值、基金价值、股份)

接收当前现金、价值、基金价值和基金份额

notify_order(订货)

在每个下一个周期之前接收订单通知

notify_trade(贸易)

在每个下一个周期之前接收交易通知

get_analysis()

返回类似 dict 的对象以及分析结果

字典中分析结果的键和格式取决于实现。

甚至没有强制要求结果是一个类似字典的对象,只是约定

默认实现返回由缺省方法创建的缺省 create_analysis OrderedDictrets

create_analysis()

意味着被子类覆盖。提供创建保存分析的结构的机会。

默认行为是创建一个OrderedDict named rets

print(*args, **kwargs)

打印通过标准Writerfile对象返回get_analysis的结果,该对象缺省将内容写入标准输出

pprint(*args, **kwargs)

打印使用漂亮的打印 Python 模块 (pprint) 传回get_analysis 的结果

()

len通过实际返回分析器操作的策略的当前长度来支持调用analyzers

推荐阅读

相关文章

Backtrader期货补偿与现货补偿

版本1.9.32.116 增加了对社区中呈现的有趣用例 的支持 以期货开始交易,包括实物交割 让一个指针告诉你一些事情 如果需要, close 现货价格操作,有效地取消实物交割,无论是为了接收货物还是为了必须交付货物(并希望获利)来头寸。

Backtrader教程:数据馈送 - 展期交割

并非每个供应商都为可以交易的工具提供连续的未来。有时提供的数据是仍然有效的到期日期的数据,即:仍在交易的日期 这在回溯测试方面并不是很有帮助,因为数据分散在几个不同的仪器上,这些仪器另外...时间重叠。 能够正确地将这些仪器的数据从过去连接到连续的流中,可以减轻疼痛。

Backtrader迪克森移动平均线

下面的reddit帖子以自己的作者Nathan Dickson(reddit句柄)命名了这个平均值Dickson移动平均线。 在一次对reddit Algotrading 的定期访问中,我发现了一篇关于移动平均线的帖子,该移动平均线试图模仿Jurik移动平均线(又名JMA)。

数据多时间帧

有时投资决策是使用不同的时间框架做出的: 每周评估趋势 每天执行条目 或者5分钟对60分钟。 这意味着需要将多个时间帧的数据组合在 backtrader 中以支援此类组合。 对它的本机支持已经内置。

Backtrader教程:日期时间 - 管理

在 1.5.0 版之前, backtrader 使用直接的方法来进行时间管理,因为数据源计算的任何日期时间都只是按面值使用。 对于任何用户输入也是如此,例如可以提供给任何数据源的参数fromdate (或 sessionstart)的情况 考虑到直接控制冻结的数据源以进行回溯测试,这种方法很好。

Backtrader卡尔曼等

注意 对以下指令的支持从提交开始 发布1.9.30.x 将是包含它的第1个版本 。 backtrader的原始目标之一是成为纯python,即:仅使用标准发行版中可用的软件包。只有一个例外是matplotlib在没有重新发明轮子的情况下进行绘图。

Backtrader 多数据范例

社区中的几个主题似乎以如何跟踪订单为导向,特别是当几个data feeds在起作用时,还包括当多个订单一起工作时,

Backtrader现实咬合

上一篇文章设法拷贝了该BTFD 策略,发现真正的收益 16x 而不是 31x。 但正如拷贝期间所指出的: 不收取佣金 使用2x 杠杆不收取利息 这就提出了一个显而易见的问题: 当收取佣金和利息时,这16x中有多少会存在? 幸运的是,前面的示例足够灵活,可以对其进行试验。

Backtrader动量策略

在另一篇伟大的文章中,泰迪·科克(Teddy Koker)再次展示了算法交易策略的发展之路: 研究优先应用 pandas 回溯测试,然后使用 backtrader 荣誉!!! 该帖子可以在以下位置找到: 泰迪·科克(Teddy Koker)给我留言,问我是否可以评论 backtrader的用法。

Backtrader终极振荡器

backtrader开发启动时的目标之一是使开发新的指针变得非常容易(至少对作者本人而言),以在数学和视觉上测试想法。 门票#102 是关于将 UltimateOscillator 添加到 backtrader 注意 它将在下一个版本中添加,同时可以使用下面的代码使用它。 票证中所示的参考: 以及: 无需在这里重复。