BackTrader 中文文档(九)(1)

简介: BackTrader 中文文档(九)


原文:www.backtrader.com/

期货和现货补偿

原文:www.backtrader.com/docu/order-creation-execution/futurespot/future-vs-spot/

发布1.9.32.116添加了对在社区中提出的一个有趣用例的支持。

  • 通过未来开始交易,其中包括实物交割
  • 让指标告诉你些什么。
  • 如果需要,通过对现货价格进行操作来关闭头寸,有效地取消物理交割,无论是为了收到货物还是为了交付货物(并有望获利)。
    未来到期日与现货价格操作在同一天发生。

这意味着:

  • 平台从两种不同的资产中获取数据点。
  • 平台必须以某种方式理解资产之间的关系,并且操作现货价格将关闭在期货上开放的头寸。
    实际上,未来并没有关闭,只有物理交割是补偿的。

使用补偿概念,backtrader添加了一种让用户向平台传达在一个数据源上的事情将对另一个数据源产生补偿效果的方法。使用模式

import backtrader as bt
cerebro = bt.Cerebro()
data0 = bt.feeds.MyFavouriteDataFeed(dataname='futurename')
cerebro.adddata(data0)
data1 = bt.feeds.MyFavouriteDataFeed(dataname='spotname')
data1.compensate(data0)  # let the system know ops on data1 affect data0
cerebro.adddata(data1)
...
cerebro.run()

将所有内容放在一起

例子总是值得一千篇文章,所以让我们把所有的东西放在一起。

  • 使用backtrader源中的标准示例数据之一。这将是未来的。
  • 通过重复使用相同的数据源并添加一个过滤器,该过滤器将随机将价格移动到上/下几个点,以创建一个价差,来模拟类似但不同的价格。如下所示:
# The filter which changes the close price
def close_changer(data, *args, **kwargs):
    data.close[0] += 50.0 * random.randint(-1, 1)
    return False  # length of stream is unchanged` 
  • 将绘图到相同的轴上会混合默认包含的BuyObserver标记,因此标准观察器将被禁用,并手动重新添加以使用不同的每个数据标记进行绘图。
  • 位置将随机输入,并在 10 天后退出。
    这与期货到期期限不符,但这只是为了实现功能,而不是检查交易日历。

!!! 注意

A simulation including execution on the spot price on the day of
  future expiration would require activating `cheat-on-close` to
  make sure the orders are executed when the future expires. This is
  not needed in this sample, because the expiration is being chosen
  at random.
  • 注意策略
  • buy操作在data0上执行。
  • sell操作在data1上执行。
class St(bt.Strategy):
    def __init__(self):
        bt.obs.BuySell(self.data0, barplot=True)  # done here for
        BuySellArrows(self.data1, barplot=True)  # different markers per data
    def next(self):
        if not self.position:
            if random.randint(0, 1):
                self.buy(data=self.data0)
                self.entered = len(self)
        else:  # in the market
            if (len(self) - self.entered) >= 10:
                self.sell(data=self.data1)` 

执行:

$ ./future-spot.py --no-comp
• 1

使用此图形输出。

它是有效的:

  • buy操作以指向上的绿色三角形的形式发出信号,图例告诉我们它们属于data0,如预期的那样。
  • sell操作以向下箭头的形式发出信号,图例告诉我们它们属于data1,如预期的那样。
  • 交易正在关闭,即使它们是以data0开仓并以data1平仓,也能实现期望的效果(在现实生活中,这意味着避免通过期货获得的商品的实物交割)。

如果没有补偿,人们可能会想象会发生什么。让我们来做一下:

$ ./future-spot.py --no-comp

输出结果

很明显,这是失败的:

  • 逻辑期望data0上的仓位在data1上的操作关闭,并且只有在市场中没有仓位时才开放data0上的仓位。
  • 补偿已被停用,并且对data0的初始操作(绿色三角形)从未关闭,因此不会启动任何其他操作,而data1上的空头仓位开始累积。

示例用法

$ ./future-spot.py --help
usage: future-spot.py [-h] [--no-comp]
Compensation example
optional arguments:
  -h, --help  show this help message and exit
  --no-comp

示例代码

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import random
import backtrader as bt
# The filter which changes the close price
def close_changer(data, *args, **kwargs):
    data.close[0] += 50.0 * random.randint(-1, 1)
    return False  # length of stream is unchanged
# override the standard markers
class BuySellArrows(bt.observers.BuySell):
    plotlines = dict(buy=dict(marker='$\u21E7$', markersize=12.0),
                     sell=dict(marker='$\u21E9$', markersize=12.0))
class St(bt.Strategy):
    def __init__(self):
        bt.obs.BuySell(self.data0, barplot=True)  # done here for
        BuySellArrows(self.data1, barplot=True)  # different markers per data
    def next(self):
        if not self.position:
            if random.randint(0, 1):
                self.buy(data=self.data0)
                self.entered = len(self)
        else:  # in the market
            if (len(self) - self.entered) >= 10:
                self.sell(data=self.data1)
def runstrat(args=None):
    args = parse_args(args)
    cerebro = bt.Cerebro()
    dataname = '../../datas/2006-day-001.txt'  # data feed
    data0 = bt.feeds.BacktraderCSVData(dataname=dataname, name='data0')
    cerebro.adddata(data0)
    data1 = bt.feeds.BacktraderCSVData(dataname=dataname, name='data1')
    data1.addfilter(close_changer)
    if not args.no_comp:
        data1.compensate(data0)
    data1.plotinfo.plotmaster = data0
    cerebro.adddata(data1)
    cerebro.addstrategy(St)  # sample strategy
    cerebro.addobserver(bt.obs.Broker)  # removed below with stdstats=False
    cerebro.addobserver(bt.obs.Trades)  # removed below with stdstats=False
    cerebro.broker.set_coc(True)
    cerebro.run(stdstats=False)  # execute
    cerebro.plot(volume=False)  # and plot
def parse_args(pargs=None):
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description=('Compensation example'))
    parser.add_argument('--no-comp', required=False, action='store_true')
    return parser.parse_args(pargs)
if __name__ == '__main__':
    runstrat()

StopTrail(Limit)

原文:www.backtrader.com/docu/order-creation-execution/trail/stoptrail/

版本1.9.35.116StopTrailStopTrailLimit订单执行类型添加到回测武器库。

注意

这仅在回测中实现,尚未针对实时经纪人实现

注意

用版本1.9.36.116更新。交互式经纪人支持StopTrailStopTrailLimitOCO

  • OCO总是将第 1 个订单作为参数oco指定为一组
  • StopTrailLimit:经纪人模拟和IB经纪人具有相同的行为。指定:price作为初始触发价格(也指定trailamount),然后plimi作为初始限价。两者之间的差异将确定limitoffset(限价与停止触发价格之间的距离)

用法模式完全集成到策略实例的标准buysellclose市场操作方法中。注意:

  • 指示希望的执行类型,如exectype=bt.Order.StopTrail
  • 以及是否必须使用固定距离或百分比距离计算跟踪价格
  • 固定距离:trailamount=10
  • 百分比距离:trailpercent=0.02(即:2%

如果通过发出buy进入市场,这是sellStopTrailtrailamount一起的操作:

  • 如果未指定price,则使用最新的close价格
  • trailamount从价格中减去以找到stop(或触发)价格
  • 下一个迭代的经纪人检查触发价格是否已达到
  • 如果:订单以Market执行类型的方法执行
  • 如果,则使用最新的close价格减去trailamount距离重新计算stop价格
  • 如果新价格上涨,则更新
  • 如果新价格将下跌(或根本不变),则将其丢弃

也就是说:跟踪止损价格随价格上涨而上涨,但如果价格开始下跌,则保持不变,以潜在地获利。

如果通过sell进入市场,然后通过StopTrail发出buy订单只是做相反的操作,即:价格向下跟随。

一些用法模式

# For a StopTrail going downwards
# last price will be used as reference
self.buy(size=1, exectype=bt.Order.StopTrail, trailamount=0.25)
# or
self.buy(size=1, exectype=bt.Order.StopTrail, price=10.50, trailamount=0.25)
# For a StopTrail going upwards
# last price will be used as reference
self.sell(size=1, exectype=bt.Order.StopTrail, trailamount=0.25)
# or
self.sell(size=1, exectype=bt.Order.StopTrail, price=10.50, trailamount=0.25)

也可以指定trailpercent而不是trailamount,价格与价格的距离将被计算为价格的百分比

# For a StopTrail going downwards with 2% distance
# last price will be used as reference
self.buy(size=1, exectype=bt.Order.StopTrail, trailpercent=0.02)
# or
self.buy(size=1, exectype=bt.Order.StopTrail, price=10.50, trailpercent=0.0.02)
# For a StopTrail going upwards with 2% difference
# last price will be used as reference
self.sell(size=1, exectype=bt.Order.StopTrail, trailpercent=0.02)
# or
self.sell(size=1, exectype=bt.Order.StopTrail, price=10.50, trailpercent=0.02)

对于StopTrailLimit

  • 唯一的区别在于当触发跟踪止损价格时会发生什么。
  • 在这种情况下,订单以Limit订单的形式执行(与StopLimit订单的行为相同,但在这种情况下,触发价格是动态的)
    注意:必须指定plimit=x.xbuysell,这将是限价
    注意限价不像停止/触发价格那样动态更改

例如总是值得一看,因此通常的backtrader示例,其中

  • 使用移动平均线上穿进入市场多头
  • 使用跟踪止损退出市场

使用50点固定价格距离的执行

$ ./trail.py --plot --strat trailamount=50.0

这产生了以下图表

和以下输出:

**************************************************
2005-02-14,3075.76,3025.76,3025.76
----------
2005-02-15,3086.95,3036.95,3036.95
2005-02-16,3068.55,3036.95,3018.55
2005-02-17,3067.34,3036.95,3017.34
2005-02-18,3072.04,3036.95,3022.04
2005-02-21,3063.64,3036.95,3013.64
...
...
**************************************************
2005-05-19,3051.79,3001.79,3001.79
----------
2005-05-20,3050.45,3001.79,3000.45
2005-05-23,3070.98,3020.98,3020.98
2005-05-24,3066.55,3020.98,3016.55
2005-05-25,3059.84,3020.98,3009.84
2005-05-26,3086.08,3036.08,3036.08
2005-05-27,3084.0,3036.08,3034.0
2005-05-30,3096.54,3046.54,3046.54
2005-05-31,3076.75,3046.54,3026.75
2005-06-01,3125.88,3075.88,3075.88
2005-06-02,3131.03,3081.03,3081.03
2005-06-03,3114.27,3081.03,3064.27
2005-06-06,3099.2,3081.03,3049.2
2005-06-07,3134.82,3084.82,3084.82
2005-06-08,3125.59,3084.82,3075.59
2005-06-09,3122.93,3084.82,3072.93
2005-06-10,3143.85,3093.85,3093.85
2005-06-13,3159.83,3109.83,3109.83
2005-06-14,3162.86,3112.86,3112.86
2005-06-15,3147.55,3112.86,3097.55
2005-06-16,3160.09,3112.86,3110.09
2005-06-17,3178.48,3128.48,3128.48
2005-06-20,3162.14,3128.48,3112.14
2005-06-21,3179.62,3129.62,3129.62
2005-06-22,3182.08,3132.08,3132.08
2005-06-23,3190.8,3140.8,3140.8
2005-06-24,3161.0,3140.8,3111.0
...
...
...
**************************************************
2006-12-19,4100.48,4050.48,4050.48
----------
2006-12-20,4118.54,4068.54,4068.54
2006-12-21,4112.1,4068.54,4062.1
2006-12-22,4073.5,4068.54,4023.5
2006-12-27,4134.86,4084.86,4084.86
2006-12-28,4130.66,4084.86,4080.66
2006-12-29,4119.94,4084.86,4069.94

而不是等待通常的下穿模式,系统使用跟踪止损退出市场。例如,让我们看看第一次操作。

  • 进入多头时的收盘价:3075.76
  • 系统计算的跟踪止损价:3025.76(相距50个单位)
  • 样本计算的跟踪止损价:3025.76(每行显示的最后价格)

在第一次计算之后:

  • 收盘价上涨至3086.95,止损价调整为3036.95
  • 以下收盘价不超过3086.95,触发价格不变

在其他两次操作中也可以看到相同的模式。

为了比较,仅使用30点固定距离的执行(仅图表)

$ ./trail.py --plot --strat trailamount=30.0

和图表

最后一次执行后跟随trailpercent=0.02

$ ./trail.py --plot --strat trailpercent=0.02

相应的图表。

示例用法

$ ./trail.py --help
usage: trail.py [-h] [--data0 DATA0] [--fromdate FROMDATE] [--todate TODATE]
                [--cerebro kwargs] [--broker kwargs] [--sizer kwargs]
                [--strat kwargs] [--plot [kwargs]]
StopTrail 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: )

示例代码

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
    params = dict(
        ma=bt.ind.SMA,
        p1=10,
        p2=30,
        stoptype=bt.Order.StopTrail,
        trailamount=0.0,
        trailpercent=0.0,
    )
    def __init__(self):
        ma1, ma2 = self.p.ma(period=self.p.p1), self.p.ma(period=self.p.p2)
        self.crup = bt.ind.CrossUp(ma1, ma2)
        self.order = None
    def next(self):
        if not self.position:
            if self.crup:
                o = self.buy()
                self.order = None
                print('*' * 50)
        elif self.order is None:
            self.order = self.sell(exectype=self.p.stoptype,
                                   trailamount=self.p.trailamount,
                                   trailpercent=self.p.trailpercent)
            if self.p.trailamount:
                tcheck = self.data.close - self.p.trailamount
            else:
                tcheck = self.data.close * (1.0 - self.p.trailpercent)
            print(','.join(
                map(str, [self.datetime.date(), self.data.close[0],
                          self.order.created.price, tcheck])
                )
            )
            print('-' * 10)
        else:
            if self.p.trailamount:
                tcheck = self.data.close - self.p.trailamount
            else:
                tcheck = self.data.close * (1.0 - self.p.trailpercent)
            print(','.join(
                map(str, [self.datetime.date(), self.data.close[0],
                          self.order.created.price, tcheck])
                )
            )
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=(
            'StopTrail 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()


BackTrader 中文文档(九)(2)https://developer.aliyun.com/article/1505289

相关文章
|
8天前
|
Python
BackTrader 中文文档(十)(3)
BackTrader 中文文档(十)
14 0
|
8天前
|
编解码 C++ 索引
BackTrader 中文文档(九)(3)
BackTrader 中文文档(九)
13 0
|
8天前
|
存储
BackTrader 中文文档(八)(4)
BackTrader 中文文档(八)
12 0
|
8天前
|
存储 编译器 API
BackTrader 中文文档(十)(1)
BackTrader 中文文档(十)
12 0
|
8天前
BackTrader 中文文档(七)(2)
BackTrader 中文文档(七)
17 3
|
8天前
|
存储 索引
BackTrader 中文文档(十)(4)
BackTrader 中文文档(十)
12 0
|
8天前
|
存储 Python
BackTrader 中文文档(八)(1)
BackTrader 中文文档(八)
15 0
|
8天前
BackTrader 中文文档(十)(2)
BackTrader 中文文档(十)
11 0
|
8天前
|
索引
BackTrader 中文文档(七)(4)
BackTrader 中文文档(七)
17 0
|
8天前
BackTrader 中文文档(九)(4)
BackTrader 中文文档(九)
12 0

热门文章

最新文章