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