似乎在世界某個地方有一種权益(Interest)可以總結如下:
- 使用每日柱線引入訂單,但使用開盤價
這來自工單#105订单执行逻辑与当前数据和#101动态投注计算中的對話
backtrader 嘗試盡可能保持現實,並且在處理每日柱線時適用以下前提:
- 當每日柱被評估時,柱線已經結束
這是有道理的,因為所有價格(open/high/low/close)元件都是已知的。實際上,當價格已知時,允許對open
價格採取行動似乎是不合邏輯的 close
。
明顯的方法是使用日內數據並輸入開盤價何時已知。但日內數據似乎並不那麼普遍。
這就是將篩選器添加到 data feed 可以提供説明的地方。具有以下特性的過濾器:
- 將每日數據轉換為類似日內的數據
起泡的藤壺!!!好奇的讀者會立即指出,例如Minutes
向上採樣是 Days
合乎邏輯的並且有效,但是向下採樣 Days
到 Minutes
是無法完成的。
這是100%正確的。下面介紹的篩檢程式不會嘗試這一點,而是一個謙卑而簡單的目標:
-
將每日酒吧分成兩部分
-
只有開盤價而沒有 volume
-
第 2個 柱,它是常規每日柱的副本
-
這仍然可以作為一種合乎邏輯的方法:
-
看到開盤價后,交易者可以採取行動
-
訂單在當天的其餘時間內匹配(實際上可能會匹配也可能不匹配,具體取決於執行類型和價格約束)
完整代碼如下所示。讓我們看一個示例運行,其中包含每日柱的255
已知數據:
$ ./daysteps.py --data ../../datas/2006-day-001.txt
輸出:
Calls,Len Strat,Len Data,Datetime,Open,High,Low,Close,Volume,OpenInterest 0001,0001,0001,2006-01-02T23:59:59,3578.73,3578.73,3578.73,3578.73,0.00,0.00 - I could issue a buy order during the Opening 0002,0001,0001,2006-01-02T23:59:59,3578.73,3605.95,3578.73,3604.33,0.00,0.00 0003,0002,0002,2006-01-03T23:59:59,3604.08,3604.08,3604.08,3604.08,0.00,0.00 - I could issue a buy order during the Opening 0004,0002,0002,2006-01-03T23:59:59,3604.08,3638.42,3601.84,3614.34,0.00,0.00 0005,0003,0003,2006-01-04T23:59:59,3615.23,3615.23,3615.23,3615.23,0.00,0.00 - I could issue a buy order during the Opening 0006,0003,0003,2006-01-04T23:59:59,3615.23,3652.46,3615.23,3652.46,0.00,0.00 ... ... 0505,0253,0253,2006-12-27T23:59:59,4079.70,4079.70,4079.70,4079.70,0.00,0.00 - I could issue a buy order during the Opening 0506,0253,0253,2006-12-27T23:59:59,4079.70,4134.86,4079.70,4134.86,0.00,0.00 0507,0254,0254,2006-12-28T23:59:59,4137.44,4137.44,4137.44,4137.44,0.00,0.00 - I could issue a buy order during the Opening 0508,0254,0254,2006-12-28T23:59:59,4137.44,4142.06,4125.14,4130.66,0.00,0.00 0509,0255,0255,2006-12-29T23:59:59,4130.12,4130.12,4130.12,4130.12,0.00,0.00 - I could issue a buy order during the Opening 0510,0255,0255,2006-12-29T23:59:59,4130.12,4142.01,4119.94,4119.94,0.00,0.00
將發生以下情況:
-
next
稱為:510 times
即255 x 2
-
len
策略和數據的總數255
達到 ,這是預期的:數據只有那麼多柱 -
每當
len
數據增加時,4個價格成分具有相同的值,open
即價格這裡列印出一個註釋,以表明在這個開放階段可以採取行動,例如購買。
有效:
- 每日 data feed 每天重播2個步驟,可以選擇在價格組成部分和其他價格組成部分之間
open
採取行動
該篩選器將添加到下一版本中的預設 backtrader 分發版中。
包含篩選器的範例代碼。
from __future__ import (absolute_import, division, print_function, unicode_literals) import argparse from datetime import datetime, time import backtrader as bt class DayStepsFilter(object): def __init__(self, data): self.pendingbar = None def __call__(self, data): # Make a copy of the new bar and remove it from stream newbar = [data.lines[i][0] for i in range(data.size())] data.backwards() # remove the copied bar from stream openbar = newbar[:] # Make an open only bar o = newbar[data.Open] for field_idx in [data.High, data.Low, data.Close]: openbar[field_idx] = o # Nullify Volume/OpenInteres at the open openbar[data.Volume] = 0.0 openbar[data.OpenInterest] = 0.0 # Overwrite the new data bar with our pending data - except start point if self.pendingbar is not None: data._updatebar(self.pendingbar) self.pendingbar = newbar # update the pending bar to the new bar data._add2stack(openbar) # Add the openbar to the stack for processing return False # the length of the stream was not changed def last(self, data): '''Called when the data is no longer producing bars Can be called multiple times. It has the chance to (for example) produce extra bars''' if self.pendingbar is not None: data.backwards() # remove delivered open bar data._add2stack(self.pendingbar) # add remaining self.pendingbar = None # No further action return True # something delivered return False # nothing delivered here class St(bt.Strategy): params = () def __init__(self): pass def start(self): self.callcounter = 0 txtfields = list() txtfields.append('Calls') txtfields.append('Len Strat') txtfields.append('Len Data') txtfields.append('Datetime') txtfields.append('Open') txtfields.append('High') txtfields.append('Low') txtfields.append('Close') txtfields.append('Volume') txtfields.append('OpenInterest') print(','.join(txtfields)) self.lcontrol = 0 def next(self): self.callcounter += 1 txtfields = list() txtfields.append('%04d' % self.callcounter) txtfields.append('%04d' % len(self)) txtfields.append('%04d' % len(self.data0)) txtfields.append(self.data.datetime.datetime(0).isoformat()) txtfields.append('%.2f' % self.data0.open[0]) txtfields.append('%.2f' % self.data0.high[0]) txtfields.append('%.2f' % self.data0.low[0]) txtfields.append('%.2f' % self.data0.close[0]) txtfields.append('%.2f' % self.data0.volume[0]) txtfields.append('%.2f' % self.data0.openinterest[0]) print(','.join(txtfields)) if len(self.data) > self.lcontrol: print('- I could issue a buy order during the Opening') self.lcontrol = len(self.data) def runstrat(): args = parse_args() cerebro = bt.Cerebro() data = bt.feeds.BacktraderCSVData(dataname=args.data) data.addfilter(DayStepsFilter) cerebro.adddata(data) cerebro.addstrategy(St) cerebro.run(stdstats=False, runonce=False, preload=False) if args.plot: cerebro.plot(style='bar') def parse_args(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description='Sample for pivot point and cross plotting') parser.add_argument('--data', required=False, default='../../datas/2005-2006-day-001.txt', help='Data to be read in') parser.add_argument('--plot', required=False, action='store_true', help=('Plot the result')) return parser.parse_args() if __name__ == '__main__': runstrat()