Skip to content

有信号的战略

原文: https://www.backtrader.com/docu/signal_strategy/signal_strategy/

无需编写策略即可操作反向交易者。尽管这是首选方式,但由于构成机器的对象层次结构,使用信号也是可能的。

快速总结:

  • 而不是编写一个策略类,实例化指标,编写买入/卖出逻辑…

  • 最终用户添加信号(无论如何都是指示器),其余在后台完成

快速示例:

import backtrader as bt

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

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

瞧!。

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

  • 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大脑将负责实例化一个特殊的策略实例,该实例知道如何处理信号

首字母常见问题

  • 如何确定买入/卖出操作的数量?

    一个大脑实例自动向策略添加一个FixedSizesizer。最终用户可以通过cerebro.addsizer更改 sizer 以更改策略

  • 如何执行命令?

    执行类型为Market,有效期为良好,直至取消

信号技术细节

从技术和理论的角度来看,可以如下所述:

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

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

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

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

  • 来自反向交易者生态系统的对象,主要是指标

    这有助于使用其他指标,如示例中使用简单移动平均线时。

信号指示

signal[0]查询时信号发出指示,含义为:

  • > 0->long indication

  • < 0->short indication

  • == 0->无显示

该示例使用self.data - SMA和进行简单运算:

  • data高于SMA时发出long indication

  • data低于SMA时发出short indication

笔记

data没有指定具体价格字段时,close价格为参考价格。

信号类型

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

import backtrader as bt

bt.SIGNAL_LONG 

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

主要组别

  • LONGSHORT:此信号的longshort指示均已获取

  • LONG

    • long迹象被认为是长期的

    • short指示关闭多头位置。但是:

    • 如果系统中存在LONGEXIT(见下文)信号,则该信号将用于退出长时间运行

    • 如果有SHORT信号,但没有LONGEXIT信号,则在打开 ashort之前先关闭 along

  • SHORT

    • short迹象被认为是做空

    • long指示关闭空头仓位。但是:

    • 如果系统中存在SHORTEXIT(见下文)信号,则该信号将用于退出短路

    • 如果有LONG信号,但没有SHORTEXIT信号,则在打开 along之前先关闭 ashort

退出组

这两个信号旨在覆盖其他信号,并为存在的 along/short位置提供标准

  • LONGEXITshort显示退出long位置

  • SHORTEXITlong显示退出short位置

累加与顺序并发

上面显示的样本信号将以恒定的基础发出指示,因为它只是从close价格中减去SMA值,而这将始终是> 0< 00在数学上是可能的,但不太可能真正发生)

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

  • 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 

输出

!image

注意:

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

  • 策略实际上是longshort。这是因为现金水平再也不会回到价值水平

  • 旁注:即使是一个愚蠢的想法……(而且没有佣金),该战略也没有赔钱…

第二轮:仅限长期

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

输出

!image

注意:

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

  • 旁注:再一次没有钱丢了…

第三轮:仅限短期

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

输出

!image

注意:

  • 1st操作是预期的卖出操作,发生时间晚于上述两个示例中的 1st操作。直到close低于SMA并且简单的减法产生负数

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

  • 旁注:最后系统会赔钱

第四轮:长+长退出

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

输出

!image

注意:

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

  • 系统显示其longonly属性,现金在每次交易结束时成为价值

  • 旁注:再次赚钱…即使有一些修改的交易

用法

$ ./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() 

我们一直在努力

apachecn/AiLearning

【布客】中文翻译组