作弊开启#

发布``1.9.44.116``版本增加了对``作弊开启``的支持。对于那些在柱状图关闭后进行计算,但期望与``开盘``价相匹配的人来说,这似乎是一个受欢迎的功能。

在开盘时,如果出现 开盘*价格的间隙(向上或向下,取决于是否进行``买入``或``卖出``操作)并且资金不足以进行 全仓*操作,则此类使用情况将失败。这会强制经纪人拒绝操作。

虽然人们可以尝试使用正向的``[1]``索引方法来预测未来,但这需要预加载数据,而这并不总是可用的。

模式如下:

cerebro = bt.Cerebro(cheat_on_open=True)

这样做:

  • 在系统中激活了一个额外的循环,调用策略中的``next_open``、``nextstart_open``和``prenext_open``方法

    决定增加一个额外的方法系列是为了清晰地区分那些在检查的价格不再可用且未来未知的常规方法和作弊模式下的操作。

    这样还避免了对常规``next``方法进行两次调用。进入 xxx_open 方法时,以下内容成立:

  • 指标尚未重新计算,并且保存了在上一个周期等效的 xxx 普通方法中看到的值。

  • 经纪人尚未评估新周期的挂单,新的订单可以引入,并且如果可能,将被评估。

请注意:

  • Cerebro 还有一个名为 broker_coo (默认为 True )的参数,告诉 cerebro 如果 cheat-on-open 已启用,则尽可能也在经纪人那里启用它。

    模拟经纪人有一个名为 coo 的参数和一个名为 set_coo 的方法。

尝试 cheat-on-open#

以下示例具有两种不同的策略行为:

  • 如果 cheat-on-openTrue ,它将仅从 next_open 进行操作。

  • 如果 cheat-on-openFalse ,它将仅从 next 进行操作。在这两种情况下,匹配的价格必须是**相同的**。

  • 如果不作弊,订单在前一天结束时下达,在下一个进来的价格(即``开盘``价格)进行匹配。

  • 如果作弊,订单在执行当天下达。由于订单在经纪人评估订单之前下达,它也将与下一个进来的价格(即``开盘``价格)进行匹配。

    第二种情况允许计算“全仓”策略的准确筹码,因为可以直接访问当前的``开盘``价格。

在这两种情况下,

  • 当前的``开盘``和``收盘``价格将从``next``打印出来。

正常执行:

``` $ ./cheat-on-open.py –cerebro cheat_on_open=False

… 2005-04-07 next,开盘 3073.4 收盘 3090.72 2005-04-08 next,开盘 3092.07 收盘 3088.92 策略长度 68 2005-04-08 发送买入,从开盘 False,收盘 3088.92 2005-04-11 以价格 3088.47 执行买入 2005-04-11 next,开盘 3088.47 收盘 3080.6 2005-04-12 next,开盘 3080.42 收盘 3065.18 … ```

欺骗性执行:

$ ./cheat-on-open.py –cerebro cheat_on_open=True

… 2005-04-07 接下来,开盘 3073.4 收盘 3090.72 2005-04-08 接下来,开盘 3092.07 收盘 3088.92 2005-04-11 发送买入,来自开盘为真,收盘 3080.6 2005-04-11 买入以价格 3088.47 执行 2005-04-11 接下来,开盘 3088.47 收盘 3080.6 2005-04-12 接下来,开盘 3080.42 收盘 3065.18 …

命令:

  • 是在2005-04-11“开盘”前发布的

  • 它在2005-04-11以“开盘”价格``3088.47``执行

而且在图表上看到的整体结果也是相同的。

结论 ====作弊的方法是在开盘之前发布订单,这样可以精确计算“全仓”情况下的赌注。

用法示例#

$ ./cheat-on-open.py --help
用法:cheat-on-open.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
                    [--todate TODATE] [--cerebro kwargs] [--broker kwargs]
                    [--sizer kwargs] [--strat kwargs] [--plot [kwargs]]

Cheat-On-Open 示例

可选参数:
  -h, --help           显示帮助消息并退出
  --data0 DATA0        要读取的数据(默认值:../../datas/2005-2006-day-001.txt)
  --fromdate FROMDATE  日期[时间],格式为YYYY-MM-DD[THH:MM:SS](默认值:)
  --todate TODATE      日期[时间],格式为YYYY-MM-DD[THH:MM:SS](默认值:)
  --cerebro kwargs     参数以key=value的格式(默认值:)
  --broker kwargs      参数以key=value的格式(默认值:)
  --sizer kwargs       参数以key=value的格式(默认值:)
  --strat kwargs       参数以key=value的格式(默认值:)
  --plot [kwargs]      参数以key=value的格式(默认值:)

示例源代码#

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

import argparse
import datetime

import backtrader as bt


class St(bt.Strategy):
    params = dict(
        periods=[10, 30],
        matype=bt.ind.SMA,
    )

    def __init__(self):
        self.cheating = self.cerebro.p.cheat_on_open
        mas = [self.p.matype(period=x) for x in self.p.periods]
        self.signal = bt.ind.CrossOver(*mas)
        self.order = None

    def notify_order(self, order):
        if order.status != order.Completed:
            return

        self.order = None
        print('{} {} Executed at price {}'.format(
            bt.num2date(order.executed.dt).date(),
            'Buy' * order.isbuy() or 'Sell', order.executed.price)
        )

    def operate(self, fromopen):
        if self.order is not None:
            return
        if self.position:
            if self.signal < 0:
                self.order = self.close()
        elif self.signal > 0:
            print('{} Send Buy, fromopen {}, close {}'.format(
                self.data.datetime.date(),
                fromopen, self.data.close[0])
            )
            self.order = self.buy()

    def next(self):
        print('{} next, open {} close {}'.format(
            self.data.datetime.date(),
            self.data.open[0], self.data.close[0])
        )

        if self.cheating:
            return
        self.operate(fromopen=False)

    def next_open(self):
        if not self.cheating:
            return
        self.operate(fromopen=True)


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

    cerebro = bt.Cerebro()

    # Data feed kwargs
    kwargs = dict()

    # Parse from/to-date
    dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
    for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
        if a:
            strpfmt = dtfmt + tmfmt * ('T' in a)
            kwargs[d] = datetime.datetime.strptime(a, strpfmt)

    # Data feed
    data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
    cerebro.adddata(data0)

    # Broker
    cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))

    # Sizer
    cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))

    # Strategy
    cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))

    # Execute
    cerebro.run(**eval('dict(' + args.cerebro + ')'))

    if args.plot:  # Plot if requested to
        cerebro.plot(**eval('dict(' + args.plot + ')'))


def parse_args(pargs=None):
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description=(
            'Cheat-On-Open Sample'
        )
    )

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

    # Defaults for dates
    parser.add_argument('--fromdate', required=False, default='',
                        help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')

    parser.add_argument('--todate', required=False, default='',
                        help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')

    parser.add_argument('--cerebro', required=False, default='',
                        metavar='kwargs', help='kwargs in key=value format')

    parser.add_argument('--broker', required=False, default='',
                        metavar='kwargs', help='kwargs in key=value format')

    parser.add_argument('--sizer', required=False, default='',
                        metavar='kwargs', help='kwargs in key=value format')

    parser.add_argument('--strat', required=False, default='',
                        metavar='kwargs', help='kwargs in key=value format')

    parser.add_argument('--plot', required=False, default='',
                        nargs='?', const='{}',
                        metavar='kwargs', help='kwargs in key=value format')

    return parser.parse_args(pargs)


if __name__ == '__main__':
    runstrat()