版本1.9.32.116
增加了对社区中呈现的有趣用例 的支持
-
以期货开始交易,包括实物交割
-
让一个指针告诉你一些事情
-
如果需要, close 现货价格操作,有效地取消实物交割,无论是为了接收货物还是为了必须交付货物(并希望获利)来头寸。
期货在现货价格操作发生的同一天到期
这意味着:
-
该平台提供来自两个不同资产的数据点
-
该平台必须以某种方式了解资产是相关的,并且现货价格的操作将 close 头寸 open 未来
现实中,未来并不封闭,只有实物交割才得到补偿
使用这种补偿概念,增加了一种方式,backtrader
让用户向平台传达一个 data feed 的东西会对另一个产生补偿作用。使用模式
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
。这将是未来 -
模拟一个相似但不同的价格,通过重用相同的Feed并添加一个筛检程序,该筛检程序将价格随机移动到高于/低于某个点,以创建点差。简单如下:
# 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
的标记,因此标准 observers 将被禁用并手动重新添加以使用不同的每数据标记进行打印 -
仓位将随机输入并在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
使用此图形输出。
它的工作原理是:
-
buy
操作以指向上方的绿色三角形发出信号,图例告诉我们它们属于data0
预期 -
sell
操作由指向下方的箭头表示,图例告诉我们它们属于data1
预期 -
交易正在被关闭,即使它们正在open
data0
和被关闭data1
,也达到了预期的效果(在现实生活中,这是为了避免通过未来获得的货物的实际交付)
人们只能想像,如果在不进行补偿的情况下应用相同的逻辑,会发生什么。让我们来做吧:
$ ./future-spot.py --no-comp
和输出
很明显,这失败了:
-
该逻辑期望在 上
data0
止损由操作data1
平仓,并且仅在不在市场上时open仓位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()