Backtrader信号策略

  |  

操作 backtrader 也是可能的,而无需编写策略。虽然这是首选方式,但由于构成机器的对象层次结构,使用信号也是可能的。

注意

可从版本获得1.8.0.x

快速摘要:

  • 而不是编写策略类,实例化指针,编写买入/卖出逻辑...

  • 最终用户添加信号(无论如何指针),其余部分在后台完成

简单范例:

import backtrader as bt

data = bt.feeds.OneOfTheFeeds(dataname='mydataname')
cerebro.adddata(data)

cerebro.add_signal(bt.SIGNAL_LONGSHORT, MySignal)
cerebro.run()

Et voilá!.

当然,信号本身是缺失的。让我们定义一个非常愚蠢的信号,它产生:

  • Long 指示价格是否 close 高于简单移动平均线

  • Short 指示价格是否 close 低于简单移动平均线

定义:

class MySignal(bt.Indicator):
    lines = ('signal',)
    params = (('period', 30),)

    def __init__(self):
        self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)

现在它真的完成了。当run 运行时, Cerebro 将负责实例化一个特殊的策略实例,该实例知道如何处理信号。

初始常见问题

  • 如何确定买入/卖出操作 volume

    cerebro实例会自动FixedSize向策略添加sizer。最终用户可以更改sizer以更改策略cerebro.addsizer

  • 订单如何运行?

    运行类型为Market “有效”,直到“取消”为止

信号技术细节

从技术和理论的角度来看,可以这样描述:

  • 一个可调用对象,在调用时返回另一个对象(仅一次)

    在大多数情况下,这是类的实例化,但不得是

  • __getitem__支持接口。唯一请求的键/索引将是0

从实际的角度来看,看看上面的例子,一个信号是:

  • 来自backtrader生态系统的lines对象,主要是指针

    这在使用其他指针时很有说明,例如在示例中使用简单移动平均线时。

信号指示

信号在查找signal[0] 时提供指示,含义为:

  • > 0 -> long indication

  • ´< 0 -> short indication

  • ´== 0 -> 无适应症

该范例使用self.data - SMA 和运行简单的算术运算:

  • 问题 along indication 当 高于dataSMA

  • 问题 ashort indicationdata 低于 SMA

注意

当 没有为data 指示特定价格字段时 close ,价格就是参考价格。

信号类型

下面指示的常量,如上面的示例所示,可直接从主 bactrader 模块获得,如下所示:

import backtrader as bt

bt.SIGNAL_LONG

有5种类型的信号,分为2组。

主要组

  • LONGSHORT:两者都 longshort 这个信号中获取指示

  • LONG:

    • long 适应症需要做多
    • short 指示用于 close 多头头寸。但:

    • 如果系统中存在LONGEXIT (见下文)信号,它将用于退出多头

    • 如果信号SHORT可用而无LONGEXIT可用,它将用于在打开 a 之前closelongshort

  • SHORT:

    • short 适应症被采取短路
    • long 指示用于 close 空头头寸。但:

    • 如果系统中存在SHORTEXIT (见下文)信号,它将用于退出空头

    • 如果信号LONG可用而无SHORTEXIT可用,它将用于在打开之前closeshortlong

离开群组

这 2 个信号旨在覆盖其他信号,并为退出 along/short 仓位提供标准

  • LONGEXITshort 指示用于退出 long 仓位

  • SHORTEXITlong 指示用于退出 short 仓位

累积和订单并发

上面显示的示例信号将持续发出长短指示,因为它只是从价格中SMA减去值,这将始终是和> 0 < 0 (几次== 0close

这将导致连续生成订单,从而产生 2 种情况:

  • Accumulation:即使已经在市场上,信号也会产生新的订单,这将增加市场的可能性

  • Concurrency:新订单将在不等待其他订单运行的情况下生成

为避免这种情况,缺省行为为:

  • 不累积

  • 不允许并发

如果希望这两种行为中的任何一种,可以通过以下方式进行控制cerebro

  • cerebro.signal_accumulate(True) (或 False 重新禁用它)

  • cerebro.signal_concurrency(True) (或 False 重新禁用它)

示例

backtrader源包含用于测试功能的范例。

要使用的主信号。

class SMACloseSignal(bt.Indicator):
    lines = ('signal',)
    params = (('period', 30),)

    def __init__(self):
        self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)

如果指定了该选项,则退出信号。

class SMAExitSignal(bt.Indicator):
    lines = ('signal',)
    params = (('p1', 5), ('p2', 30),)

    def __init__(self):
        sma1 = bt.indicators.SMA(period=self.p.p1)
        sma2 = bt.indicators.SMA(period=self.p.p2)
        self.lines.signal = sma1 - sma2

首次运行:长跑和短跑

$ ./signals-strategy.py --plot --signal longshort

输出

要注意:

  • 绘制信号。这是正常的,因为它只是一个指针,并且它的绘图规则适用

  • 策略是真的longshort.这可以看出,因为现金水平永远不会回到价值水准。

  • 附注:即使是一个愚蠢的想法...(并且没有佣金)该策略没有损失金钱...

第二次运行:仅长

$ ./signals-strategy.py --plot --signal longonly

输出

要注意:

  • 在这里,现金水准回到每次卖出后的价值水准,这意味着策略已经退出市场。

  • 附注:再次没有钱损失...

第三次运行:仅短运行

$ ./signals-strategy.py --plot --signal shortonly

输出

要注意:

  • 1st 操作是预期的卖出,并且比上述 2 个示例中的第 1操作a 晚。直到低于 closeSMA 简单减法 产生一个负数

  • 在这里,现金水准回到每次买入后的价值水准,这意味着策略已经退出市场。

  • 附注:最后系统赔钱

第四次运行:长+长输出

$ ./signals-strategy.py --plot --signal longonly --exitsignal longexit

输出

要注意:

  • 许多交易是相同的,但有些交易被提前中断,因为退出信号中的快速移动平均线穿过慢速移动平均线到下行

  • 该系统显示其长期属性,现金成为每笔交易结束时的价值

  • 附注:再次金钱...即使有一些修改的交易

用法

$ ./signals-strategy.py --help
usage: signals-strategy.py [-h] [--data DATA] [--fromdate FROMDATE]
                           [--todate TODATE] [--cash CASH]
                           [--smaperiod SMAPERIOD] [--exitperiod EXITPERIOD]
                           [--signal {longshort,longonly,shortonly}]
                           [--exitsignal {longexit,shortexit}]
                           [--plot [kwargs]]

Sample for Signal concepts

optional arguments:
  -h, --help            show this help message and exit
  --data DATA           Specific data to be read in (default:
                        ../../datas/2005-2006-day-001.txt)
  --fromdate FROMDATE   Starting date in YYYY-MM-DD format (default: None)
  --todate TODATE       Ending date in YYYY-MM-DD format (default: None)
  --cash CASH           Cash to start with (default: 50000)
  --smaperiod SMAPERIOD
                        Period for the moving average (default: 30)
  --exitperiod EXITPERIOD
                        Period for the exit control SMA (default: 5)
  --signal {longshort,longonly,shortonly}
                        Signal type to use for the main signal (default:
                        longshort)
  --exitsignal {longexit,shortexit}
                        Signal type to use for the exit signal (default: None)
  --plot [kwargs], -p [kwargs]
                        Plot the read data applying any kwargs passed For
                        example: --plot style="candle" (to plot candles)
                        (default: None)

代码

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import argparse
import collections
import datetime

import backtrader as bt

MAINSIGNALS = collections.OrderedDict(
    (('longshort', bt.SIGNAL_LONGSHORT),
     ('longonly', bt.SIGNAL_LONG),
     ('shortonly', bt.SIGNAL_SHORT),)
)


EXITSIGNALS = {
    'longexit': bt.SIGNAL_LONGEXIT,
    'shortexit': bt.SIGNAL_LONGEXIT,
}


class SMACloseSignal(bt.Indicator):
    lines = ('signal',)
    params = (('period', 30),)

    def __init__(self):
        self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)


class SMAExitSignal(bt.Indicator):
    lines = ('signal',)
    params = (('p1', 5), ('p2', 30),)

    def __init__(self):
        sma1 = bt.indicators.SMA(period=self.p.p1)
        sma2 = bt.indicators.SMA(period=self.p.p2)
        self.lines.signal = sma1 - sma2


def runstrat(args=None):
    args = parse_args(args)

    cerebro = bt.Cerebro()
    cerebro.broker.set_cash(args.cash)

    dkwargs = dict()
    if args.fromdate is not None:
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        dkwargs['fromdate'] = fromdate

    if args.todate is not None:
        todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
        dkwargs['todate'] = todate

    # if dataset is None, args.data has been given
    data = bt.feeds.BacktraderCSVData(dataname=args.data, **dkwargs)
    cerebro.adddata(data)

    cerebro.add_signal(MAINSIGNALS[args.signal],
                       SMACloseSignal, period=args.smaperiod)

    if args.exitsignal is not None:
        cerebro.add_signal(EXITSIGNALS[args.exitsignal],
                           SMAExitSignal,
                           p1=args.exitperiod,
                           p2=args.smaperiod)

    cerebro.run()
    if args.plot:
        pkwargs = dict(style='bar')
        if args.plot is not True:  # evals to True but is not True
            npkwargs = eval('dict(' + args.plot + ')')  # args were passed
            pkwargs.update(npkwargs)

        cerebro.plot(**pkwargs)


def parse_args(pargs=None):

    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='Sample for Signal concepts')

    parser.add_argument('--data', required=False,
                        default='../../datas/2005-2006-day-001.txt',
                        help='Specific data to be read in')

    parser.add_argument('--fromdate', required=False, default=None,
                        help='Starting date in YYYY-MM-DD format')

    parser.add_argument('--todate', required=False, default=None,
                        help='Ending date in YYYY-MM-DD format')

    parser.add_argument('--cash', required=False, action='store',
                        type=float, default=50000,
                        help=('Cash to start with'))

    parser.add_argument('--smaperiod', required=False, action='store',
                        type=int, default=30,
                        help=('Period for the moving average'))

    parser.add_argument('--exitperiod', required=False, action='store',
                        type=int, default=5,
                        help=('Period for the exit control SMA'))

    parser.add_argument('--signal', required=False, action='store',
                        default=MAINSIGNALS.keys()[0], choices=MAINSIGNALS,
                        help=('Signal type to use for the main signal'))

    parser.add_argument('--exitsignal', required=False, action='store',
                        default=None, choices=EXITSIGNALS,
                        help=('Signal type to use for the exit signal'))

    # Plot options
    parser.add_argument('--plot', '-p', nargs='?', required=False,
                        metavar='kwargs', const=True,
                        help=('Plot the read data applying any kwargs passed\n'
                              '\n'
                              'For example:\n'
                              '\n'
                              '  --plot style="candle" (to plot candles)\n'))

    if pargs is not None:
        return parser.parse_args(pargs)

    return parser.parse_args()


if __name__ == '__main__':
    runstrat()

推荐阅读

相关文章

Backtrader期货展期

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

Backtrader规范与非规范

这个问题或多或少地出现了几次:这样: backtrader如何最好/规范地实现这一点或那样? 作为 backtrader 的目标之一,可以灵活地 支持尽可能多的情况和用例,答案很简单:“至少在几种方式上”。

Backtrader教程:Cerebro - 优化 - 改进

backtrader版本1.8.12.99改进了在多处理过程中管理data feeds和结果的方式。

Backtrader教程:绘图 - 日期范围

该版本1.9.31.x 增加了制作部分绘图的功能。 使用策略实例中保存的完整时间戳数组的索引 或者使用实际datetime.date 或 datetime.datetime 实例来限制必须绘制的内容。 一切都超过标准cerebro.plot。

Backtrader条形同步

文献和/或行业中缺乏标准公式不是问题,因为问题实际上可以总结为: 条形同步 工单 #23 提出了一些问题,即是否可以 backtrader 考虑计算 相对体积 指针。 请求者需要将给定时刻的 volume 与前一个交易日的相同时刻进行比较。

Backtrader节省内存

1.3.1.92版本已经重新设计并完全实现了以前到位的内存节省方案,尽管没有太多的吹捧和使用。

Backtrader蟒蛇隐藏的力量3

Last,但并非最不重要的一点是,在这个系列中,关于如何在 backtrader 中使用Python的隐藏功能是一些神奇变量是如何出现的。

Backtrader 多数据范例

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

Backtrader动量策略

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

Backtrader熊猫数据馈送

在一些小的增强功能和一些OrderDict调整中,以获得更好的Python 2.6支持, backtrader 的最新版本增加了对分析Pandas Dataframe或Time Series数据的支持。