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
有了这个图形输出。
它有效:
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()