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