Backtrader中文笔记之Cheat On Open

这个感觉就是只能用来,在当前的开盘前下单,用的当天的开盘价可以参考买入股份,信号的处理,买入的时间,买入的价格,与正常的没有任何区别

 

Release 1.9.44.116 adds support for Cheat-On-Open. This seems to be a demanded feature for people who go all-in, having made a calculation after the close of a bar, but expecting to be matched against the open price.

版本1.9.44.116增加了对Cheat-On-Open的支持。对于那些在bar关闭后做过计算,但希望与开盘价相匹配的人来说,这似乎是他们所需要的功能。

Such a use case fails when the opening price gaps (up or down, depending on whether buy or sell is in effect) and the cash is not enough for an all-in operation. This forces the broker to reject the operation.

当开盘价出现缺口(上涨或下跌,取决于买入还是卖出)且现金不足以进行全面操作时,这样的用例就失败了。这将强制代理拒绝该操作。

And although people can try to look into the future with a positive [1] index approach, this requires preloading data which is not always available.

尽管人们可以尝试用积极的[1]指数方法来展望未来,但这需要预加载数据,而这并不总是可用的。

The pattern:

cerebro = bt.Cerebro(cheat_on_open=True)

 

This:

  • Activates an extra cycle in the system which calls the methods in the strategy next_open, nextstart_open and prenext_open

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

     

    The decision to have an additional family of methods has been made to make a clear separation between the regular methods which operate on the basis that the prices being examined are no longer available and the future is unknown and the operation in cheating mode.

  • 决定增加一系列方法是为了明确区分常规方法和作弊模式下的操作方法,这些方法是基于被检查的价格不再可用且未来未知。
  •  

    This also avoids having 2 calls to the regular next method.

  • 这也避免了对常规next方法的两次调用。

 

The following holds true when inside a xxx_open method:

在xxx_open方法中,以下情况适用:

  • The indicators have not been recalculated and hold the values that were last seen during the previous cycle in the equivalent xxx regular methods

  • 这些指标尚未重新计算,并保留了上一个周期中采用等效xxx常规方法最后看到的数值【使用的是上一个周期的指标】关键
  • The broker has not yet evaluated the pending orders for the new cycle and new orders can be introduced which will be evaluated if possible.

  • 【券商经纪人】尚未评估新周期的待定订单,可以引入新订单,如果可能,将对其进行评估。

Notice that:

  • Cerebro also has a broker_coo (default: True) parameter which tells cerebro that if cheat-on-open has been activated, it shall try to activate it also in the broker if possible.

  • Cerebro也有一个broker_coo(默认值:True)参数,它告诉大脑,如果“欺骗打开”被激活,它也应尽可能在代理中激活它。
  •  

    The simulation broker has a parameter named: coo and a method to set it named set_coo

  • 模拟券商【经纪人】有一个名为:coo的参数和一个设置它的方法set_coo

 

 

Trying cheat-on-open

The sample below has a strategy with 2 different behaviors:

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

  • If cheat-on-open is True, it will only operate from next_open

  • 如果cheat-on-open为True,它将只操作next_open
  • If cheat-on-open is False, it will only operate from next

  • 如果cheat-on-open为False,它将只操作next

In both cases the matching price must be the same

在这两种情况下,匹配价格必须相同

  • If not cheating, the order is issued at the end of the previous day and will be matched with the next incoming price which is the open price

  • 如果不作弊,订单将在前一天结束时发出,并将与下一个进入价格匹配,即开盘价。
  • If cheating, the order is issued on the same day it is executed. Because the order is issued before the broker has evaluated orders, it will also be matched with the next incoming price, the open price.

  • 如果作弊,命令在执行当天发出。因为订单是在经纪人评估订单之前发出的,它还将与下一个入市价格,即开盘价相匹配。
  •  

    This second scenario, allows calculation of exact stakes for all-in strategies, because one can directly access the current open price.

  • 第二种情况下,可以计算所有策略的确切风险,因为可以直接获得当前的开盘价。

In both cases

  • The current open and close prices will be printed from next.
  • 当前的开盘价和收盘价将从下一页打印出来。

 

Regular execution:

 

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

...
2005-04-07 next, open 3073.4 close 3090.72
2005-04-08 next, open 3092.07 close 3088.92
Strat Len 68 2005-04-08 Send Buy, fromopen False, close 3088.92
2005-04-11 Buy Executed at price 3088.47
2005-04-11 next, open 3088.47 close 3080.6
2005-04-12 next, open 3080.42 close 3065.18
...

 

 

 

The order:

  • Is issued on 2005-04-08 after the close

  • 在2005-04-08收盘之后发出定单
  • It is executed on 2005-04-11 with the open price of 3088.47

  • 执行在2005-04-11的开盘价3088.47

Cheating execution:

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

...
2005-04-07 next, open 3073.4 close 3090.72
2005-04-08 next, open 3092.07 close 3088.92
2005-04-11 Send Buy, fromopen True, close 3080.6
2005-04-11 Buy Executed at price 3088.47
2005-04-11 next, open 3088.47 close 3080.6
2005-04-12 next, open 3080.42 close 3065.18
...

 

 

 

The order:

  • Is issued on 2005-04-11 before the open

  • 在4月11日之前发出定单
  • It is executed on 2005-04-11 with the open price of 3088.47

  • 执行在4月11日的开盘价

And the overall result as seen on the chart is also the same.

图上的结果也是一样的

 

Conclusion

结论

Cheating on the open allows issuing orders before the open which can for example allow the exact calculation of stakes for all-in scenarios.

在公开市场上作弊允许在公开之前发布命令,这可以允许在所有场景中精确计算购买股数【赌注】。

 

Sample usage

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

Cheat-On-Open Sample

optional arguments:
  -h, --help           show this help message and exit
  --data0 DATA0        Data to read in (default:
                       ../../datas/2005-2006-day-001.txt)
  --fromdate FROMDATE  Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
  --todate TODATE      Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
  --cerebro kwargs     kwargs in key=value format (default: )
  --broker kwargs      kwargs in key=value format (default: )
  --sizer kwargs       kwargs in key=value format (default: )
  --strat kwargs       kwargs in key=value format (default: )
  --plot [kwargs]      kwargs in key=value format (default: )

 

Sample source

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()

 

posted @ 2020-09-21 14:27  就是想学习  阅读(835)  评论(0编辑  收藏  举报