backtrader訂單詳情


本文來源:碼農甲,個人學習筆記,詳情見原博主文章

提前小結:


訂單創建
通過調用Strategy的buy()、sell()、close()方法來返回訂單實例。

訂單取消
通過調用Strategy的cancel(order)方法來取消訂單

訂單通知通過調用Strategy的notify_order(order)方法來通知order的狀態。

訂單類型: ExecTypes = ['Market', 'Close', 'Limit', 'Stop', 'StopLimit', 'StopTrail',
'StopTrailLimit', 'Historical']

 

 

1、Market訂單
以下一根K線的開盤價執行訂單。

2、Close訂單
當下一根K線結束時,以下一根K線的收盤價執行訂單。

3、Limit訂單

在Limit訂單創建時,會設置一個price和valid時間,如果超過valid時間訂單仍未滿足執行條件,訂單就會過期被取消。在valid時間內,訂單會按照下面描述的價格匹配規則判斷訂單是否會成交。

4、Stop訂單

在Stop訂單創建時,會設置一個price和valid時間,如果超過valid時間訂單仍未滿足執行條件,訂單就會過期被取消。在valid時間內,訂單會按照下面描述的價格匹配規則判斷訂單是否會成交。

5、StopLimit訂單

在StopLimit訂單創建時,會設置price、plimit和valid時間,如果超過valid時間訂單仍未滿足執行條件,訂單就會過期被取消。在valid時間內,訂單會按照下面描述的價格匹配規則判斷訂單是否會成交。

6、StopTrail訂單

給訂單設置跟蹤量(trail amount)或者跟蹤比例(trail percent),用於計算跟蹤價差,訂單會使用跟蹤價差按照下面描述的觸發價格(跟蹤價格/trail price/stop price/trigger price)計算規則計算更新觸發價格,若價格回撤至觸發價格,則訂單成交。

7、StopTrailLimit訂單


在StopLimit訂單中,觸發價格stopprice和限制價格limitprice均為固定值,而在StopTrailLimit訂單中觸發價格stopprice和限制價格limitprice都會隨着收盤價的變化進行變化。


在backtrader中,Strategy類是用戶制定回測策略的核心。
我們可以用Strategy的各個方法來表示它的整個生命周期:孕育期——出生——兒童期——成年期——繁殖期——死亡。
孕育期:init
當實例化Strategy時,__init__方法將被調用。技術指標和一些其他的屬性需要在這時候創建。例如:
def __init__(self):
self.sma = btind.SimpleMovingAverage(period=15)
上面的代碼創建了一個15日簡單移動均線的技術指標。
出生:start
backtrader的核心cerebro會告訴strategy是時候開始行動了。這里默認會創建一個空的start方法。在出生階段,strategy的創建可能被中斷,並拋出StrategySkipError異常。
兒童期:prenext
在孕育期聲明的技術指標,有的需要經過某個周期長度才能得到有效數值,這個周期稱為最小周期(minimum period)。
例如,在__init__方法中,我們創建了一個15日均線的指標,這個指標就需要經過15根K線才能計算出有效的數值,前14根K線無法得到15日均線的數值。backtrader將在訪問到15根K線以后,才會調用prenext方法。prenext方法默認不進行任何操作。
成年期:next
當backtrader經過了minimum period(在上面的例子中,就是訪問到第15根K線時),並且有足夠的空間來存儲將要計算得到的數據時,strategy就開始執行next來進行具體的買賣操作。
這里實際上調用且僅調用一次nextstart方法,來作為從prenext轉到next標志。在nextstart的默認實現中,僅僅是調用了一次next。
繁殖期:None
strategy是不會做復制的。但是當我們使用不同的參數來優化策略時,backtrader就會多次實例化strategy,在這種情況下,也可以看作是對strategy進行了復制。
死亡:stop
backtrader告知strategy是時候重置把所有事情安排妥當了。backtrader提供一個默認為空的stop方法。
Strategy也會收到通知,並且在每個next周期內都會被通知一次,這些通知包括:
通過notify_order(order)發出訂單狀態變化的通知
通過notify_trade(trade)發出交易開始/更新/關閉的通知
通過notify_cashvalue(cash, value)發出代理手中當前現金和資產的通知
通過notify_fund(cash, value, fundvalue, shares)發出代理手中當前現金和資產,以及正在交易的資金和股票的通知
通過notify_store(msg, *args, **kwargs)發出的事件通知(需要單獨實現)
在next方法中,Strategy可以通過以下操作來嘗試盈利:
使用buy方法,來做多或者減少/關閉空頭交易
使用sell方法,來做空或者減少/關閉多頭交易
使用close方法,來關閉一個現有的交易
使用cancel方法,來取消一個尚未執行的訂單
當調用buy和sell方法后,都會生成訂單,並且返回一個order(或者order子類)的實例,每個實例都包含有一個唯一的ref標識符,用於區分不同的order


訂單創建
通過調用Strategy的buy()、sell()、close()方法來返回訂單實例。

訂單取消
通過調用Strategy的cancel(order)方法來取消訂單
訂單通知
通過調用Strategy的notify_order(order)方法來通知order的狀態。
訂單可能參數
data(默認值:None)
order所要操作的數據。如果為None,則系統中的第一組數據(第一只股票/品種)將被使用,也就是self.datas[0]、self.data0、self.data,上面3種形式均可以表示系統中的第一組數據。
size(默認值:None)
交易單位,size是一個正數。對於買單,如果size=100,就是買100個單位數量的倉位;對於賣單,如果size=100,就是賣100個單位數量的倉位。
如果size=None,sizer實例就會通過getsizer方法來獲取size的值。也就是說,除了使用buy、sell方法來設置單個訂單的交易單位大小,還有方法設置全局交易單位的大小(通過Cerebro.addsizer方法來設置),這樣就避免了每個order都要設置交易單位。
price(默認值:None)
交易價格。
默認值None適用於Market、Close訂單(后面的exectype參數會介紹各類型訂單的意義),由市場決定具體的交易價格。
對於Limit、Stop、StopLimit訂單,必須顯式給price賦值,price值決定了交易的觸發點(trigger point)。
對於StopTrail、StopTrailLimit訂單,是否顯示設置price,將決定不同的交易觸發點。(后續文章將詳細介紹)
plimit(默認值:None)
只適用於StopLimit訂單。在StopLimit訂單中,plimit值被設置為隱含的Limit訂單price值,而price值被用於觸發當前StopLimit訂單的Stop條件。(后續文章將詳細介紹)
exectype(默認值:None)
可能的取值
Order.Market或者None:Market訂單將以下一個可行的價格進行交易,在回測中,就將以下一根K線的開盤價進行交易。
Order.Limit:在給定的價位price或者更好的價位執行的訂單。
Order.Stop:當價格突破price時,觸發訂單成交。
Order.StopLimit:當價格突破price時觸發訂單(類似於Order.Stop訂單),之后以給定的價位plimit或者更好的價位執行訂單(相當於以參數plimit為price的Order.Limit訂單)。
Order.StopTrail:根據收盤價的變化,動態調整訂單的交易價格,以實現利潤的保護。
Order.StopTrailLimit:Order.StopTrail和Order.Limit的組合,按照Order.StopTrail條件觸發,按照Order.Limit條件成交。
Order.Historical:尚未發現相關說明及應用。
valid(默認值:None)
可能的取值:
None。生成的訂單將不會過期,將一直在市場中等待滿足條件后執行或者等待被手動取消。
datetime.datetime或者datetime.date的實例。這個日期將被用來創建這樣一個訂單,如果截止到該給定的日期,該訂單仍未滿足執行條件,那么這個訂單就會過期而取消。
Order.DAY或者timedelta()。生成一個單日訂單,有效期為1天,單日未滿足執行條件,訂單就會過期取消。
numeric value。對應於matplotlib中的日期格式,將被用來創建訂單,訂單有效期截止日為該日期。
tradeid(默認值:0)
這是backtrader應用的一個內部值,用於跟蹤相同資產上的重疊交易。當通知訂單狀態的變化時,此tradeid被發送回策略。
∗∗kwargs
其他代理的實現可能支持額外的參數。backtrader將kwarg向下傳遞到創建的order對象。
close方法將首先檢查當前的持倉情況,然后根據持倉情況對應地使用buy或者sell方法來清空倉位。如果用戶不指定具體的size值,size會被自動計算。如果指定了size值,那么將實現部分close或者reversal訂單。



訂單通知

為了收到訂單通知,需要在用戶自定義的Strategy子類中,重寫notify_order方法,該方法默認為空。notify_order方法將會被以如下方式使用:

notify_order方法會在Strategy的next方法前被調用
在同一個next周期內,同一個order的通知,可以以相同或者不同的狀態在notify_order方法中出現多次。
例如:一個訂單先被提交給代理,然后立即被代理接受,且已經滿足了執行的條件,它的執行就會在下一個next方法被調用前就已經完成。在這個例子中,至少有以下3個狀態通知產生:
Order.Submitted:產生於訂單提交給代理
Order.Accepted:產生於代理接受訂單,等待被執行
Order.Completed:產生於訂單滿足了執行條件,被立即執行完成
在實盤交易中,對於訂單狀態同為Order.Partial的通知可能會出現多次,因為實盤中訂單可能會被拆分為多筆交易被執行完成。而在回測中,由於不考慮成交量的匹配,所以不會出現這種情況。

被執行的訂單數據被記錄在屬性order.executed中,它是一個類型為OrderData的實例,包含size和price字段。

訂單創建時的數據被記錄在order.created中,這些數據在order的整個生命周期中保持不變。

訂單狀態值
Order.Created:order實例被創建后的狀態。當使用buy、sell、close創建訂單時,該狀態對用戶不可見,需要手動創建order的實例,才能獲取到該狀態。
Order.Submitted:當order實例被發送給broker后的狀態。在回測模式下,訂單發送是一個即時動作,不需要花費時間。而在實盤中,訂單發送將要實際花費時間,代理收到訂單后,將訂單轉發給交易所,隨即通知訂單已提交。
Order.Accepted:當order處於該狀態時,該order已經在系統或者交易所中等待被執行,會根據設置的exectype、size、price、valid等參數確定何時被執行。
Order.Partial:order部分成交時的狀態。order.executed屬性里記錄了已經成交的size及平均價格。order.executed.exbits里包含了分批成交的詳細情況完整列表。
Order.Complete:order全部成交的狀態(平均成交價格被計算並記錄下來)。
Order.Rejected:order被broker拒絕的狀態。如果某個參數不被broker所接受,那么order也將不被broker接受。訂單被拒的原因將通過Strategy的notify_store方法通知用戶。該狀態對於回測代理不可見。
Order.Margin:資金不足,訂單無法成交,之前接受的訂單會被從系統中刪除。
Order.Cancelled(或者Order.Canceled): 對用戶訂單取消要求的確認。用戶通過Strategy的cancel方法提交取消訂單申請,可能無法成功地取消訂單。訂單可能已經成交,但是代理尚未反饋成交結果,或者成交通知還沒有發送到Strategy。因此需要Order.Canncelled對是否成功取消訂單進行確認。
Order.Expired:在該狀態下,之前被提交的包含有效時間的訂單已經過期,訂單被從系統中刪除。


order類型
翻看backtrader源代碼,在order.py中可以看到ExecTypes列表共有8種不同類型的訂單,即按照執行類型,可以分為以下8種:
ExecTypes = ['Market', 'Close', 'Limit', 'Stop', 'StopLimit', 'StopTrail',
'StopTrailLimit', 'Historical']
各種執行類型的簡單說明可以參見上文中exectype參數描述部分,后續文章將進行詳細描述。
order成交原則
在backtrader中,代理(broker)使用以下2個原則來進行訂單交易:
1. 當前數據已經產生,不能被用於執行交易。
例如,Strategy的邏輯如下:
if self.data.close > self.sma: # sma表示簡單移動平均線
self.buy()
在這個邏輯中,將收盤價close與移動平均線做比較,如果滿足條件,就下買單。但是買單是無法用close進行交易的,因為close是已經產生的數據。只能用下一根K線的某個價位成交,成交價格取決於order類型。
訂單的首個可交易的時間在下一根K線上。
2. 成交量在交易中不發揮作用
在實際交易中,成交量是會影響交易的。如果交易員是在進行非流動資產的買賣,或者是在K線的極端點(最高點或者最低點)進行的交易,成交量將影響實盤交易。
但是觸及最高點/最低點是很少發生的(A股例外,有漲跌停。。。),所選資產將有足夠的流動性來吸收任何常規交易的指令。因此backtrader假設成交量在交易中不發揮作用。


Market訂單

執行規則:以下一根K線的開盤價執行訂單。
原理:假設在某一時刻滿足了交易的條件,這時生成一個Market訂單,如果想成交這一訂單,就需要下一個將要出現價格點位,這個點位就是下一根K線的開盤價(open)。
對於Market訂單,參數price和valid將被忽略。
Market訂單以下一根K線的開盤價成交
# 檢查是否持倉
if self.position:
# 檢查是否達到賣出條件
if self.buysell < 0:
...
if self.p.exectype == 'Market':
self.sell(exectype = bt.Order.Market)
self.log('SELL CREATE, exectype Market, close %.2f' %
self.data.close[0])
...
# 不在場內且出現買入信號
elif self.buysell > 0:
...
if self.p.exectype == 'Market':
self.buy(exectype=bt.Order.Market) # Market是默認的訂單類型
self.log('BUY CREATE, exectype Market, close %.2f' %
self.data.close[0])



Close訂單
執行規則:當下一根K線結束時,以下一根K線的收盤價執行訂單。
原理:以日線回測為例,它包含了已經結束的日K數據,在滿足交易條件后,訂單將以下一根K線的收盤價(close)立即成交。大多數回測數據屬於這種情況,但是也有例外的情況,比如分時數據。在下一個分時K線產生之前,當前的分時K線由於分時時段未結束,數據會保持不斷的更新。在這種情況下,只有當前分時時段結束,該分時K線不再變化,才會以收盤價進行交易。
# 檢查是否持倉
if self.position:
# 檢查是否達到賣出條件
if self.buysell < 0:
...
elif self.p.exectype == 'Close':
self.sell(exectype = bt.Order.Close)
self.log('SELL CREATE, exectype Close, close %.2f' %
self.data.close[0])
...

# 不在場內且出現買入信號
elif self.buysell > 0:
...
elif self.p.exectype == 'Close':
self.buy(exectype=bt.Order.Close)
self.log('BUY CREATE, exectype Close, close %.2f' %
self.data.close[0])



Limit訂單

執行規則
在Limit訂單創建時,會設置一個price和valid時間,如果超過valid時間訂單仍未滿足執行條件,訂單就會過期被取消。在valid時間內,訂單會按照下面描述的價格匹配規則判斷訂單是否會成交。
價格匹配
Limit訂單使用K線4個價格點(Open/High/Low/Close)來推斷是否有比price更優的成交價格。
對於買單
如果某根K線的open低於設定的price,則以open值成交。訂單在這根K線的開始階段就被執行完成。
如果某根K線的open高於設定的price,但是low低於price,也就是price在這根K線的范圍內,那么訂單將以price值成交。
對於賣單
如果某根K線的open值高於設定的price,則以open值成交。訂單在這根K線的開始階段就被執行完成。
如果某根K線的open值低於設定的price,但是high高於price,也就是price在這根K線的范圍內,那么訂單將以price值成交。
# 檢查是否持倉
if self.position:
# 檢查是否達到賣出條件
if self.buysell < 0:
if self.p.valid:
valid = self.data.datetime.date(0) + \
datetime.timedelta(days=self.p.valid)
else:
valid = None
...
elif self.p.exectype == 'Limit':
price = self.data.close * (1.0 + self.p.perc1 / 100.0)
self.sell(exectype=bt.Order.Limit, price=price, valid=valid)
if self.p.valid:
txt = 'SELL CREATE, exectype Limit, close %.2f, price %.2f, valid: %s'
self.log(txt % (self.data.close[0], price, valid.strftime('%Y-%m-%d')))
else:
txt = 'SELL CREATE, exectype Limit, close %.2f, price %.2f'
self.log(txt % (self.data.close[0], price))
...

# 不在場內且出現買入信號
elif self.buysell > 0:
if self.p.valid:
valid = self.data.datetime.date(0) + \
datetime.timedelta(days=self.p.valid)
else:
valid = None
...
elif self.p.exectype == 'Limit':
price = self.data.close * (1.0 - self.p.perc1 / 100.0)
self.buy(exectype=bt.Order.Limit, price=price, valid=valid)
if self.p.valid:
txt = 'BUY CREATE, exectype Limit, close %.2f, price %.2f, valid: %s'
self.log(txt % (self.data.close[0], price, valid.strftime('%Y-%m-%d')))
else:
txt = 'BUY CREATE, exectype Limit, close %.2f, price %.2f'
self.log(txt % (self.data.close[0], price))

為了說明Limit訂單可能出現的所有成交情況,在代碼中使用p.perc1 = 0.5,來控制價格回撤的比例,使用p.valid = 4,來控制訂單的有效期。
買單的3種情況:
. 過期取消. 以開盤價成交.以設定的price成交
賣單的3種情況:
. 過期取消. 以開盤價成交. 以設定的price成交



Stop訂單
執行規則
在Stop訂單創建時,會設置一個price和valid時間,如果超過valid時間訂單仍未滿足執行條件,訂單就會過期被取消。在valid時間內,訂單會按照下面描述的價格匹配規則判斷訂單是否會成交。
價格匹配
Stop訂單使用K線4個價格點(Open/High/Low/Close)來判斷是否有效突破設定的price值。
對於買單
如果某根K線的open高於設定的price,則立刻以open值成交。對於空頭來說,若已持有做空的倉位,價格較設定的price持續走高,這時要及時平倉止損(stop a loss),因此這類訂單成為Stop訂單。
如果某根K線的open低於設定的price,但是high高於price,也就是price在這根K線的范圍內,那么訂單將以price值成交。
對於賣單
如果某根K線的open值低於設定的price,則以open值成交。
如果某根K線的open值高於設定的price,但是low低於price,也就是price在這根K線的范圍內,那么訂單將以price值成交。



StopLimit訂單創建

執行規則

在StopLimit訂單創建時,會設置price、plimit和valid時間,如果超過valid時間訂單仍未滿足執行條件,訂單就會過期被取消。在valid時間內,訂單會按照下面描述的價格匹配規則判斷訂單是否會成交。

價格匹配

StopLimit訂單使用K線4個價格點(Open/High/Low/Close)以及price和plimit,來判斷訂單是否會成交。

首先以price作為觸發價格,使用Stop訂單價格匹配規則判斷訂單是否會被觸發,參閱筆記(29)。

對於已觸發訂單,以plimit作為限制價格,使用Limit訂單價格匹配規則判斷訂單是否會成交,參閱筆記(28)。

StopTrail訂單

執行規則

給訂單設置跟蹤量(trail amount)或者跟蹤比例(trail percent),用於計算跟蹤價差,訂單會使用跟蹤價差按照下面描述的觸發價格(跟蹤價格/trail price/stop price/trigger price)計算規則計算更新觸發價格,若價格回撤至觸發價格,則訂單成交。

觸發價格計算規則

假設已經通過buy方法建倉,那么對於使用sell方法的平倉StopTrail訂單,將會按照下面的規則計算跟蹤價格:

指定price值,如果沒有指定,則以最新的收盤價close作為price值

根據trailamount或trailpercent計算觸發價格

如果指定了trailamount,觸發價格stopprice = price - trailamount

如果指定了trailpercent,觸發價格stopprice = price * (1 - trailpercent)

如果同時制定了trailamount和trailpercent,則按照上面給定trailamount的情況計算觸發價格

檢查在下一根K線是否達到觸發價格

如果達到觸發價格,那么訂單將按照Stop訂單規則成交(官網上描述訂單會按照Market訂單規則成交,經過實驗和查看源代碼,應該是按照Stop訂單規則成交)

如果未達到觸發價格,那么觸發價格將會使用新的收盤價close結合trailamount及trailpercent,按照上面的計算方式計算出一個新的觸發價格newstopprice

如果新的觸發價格高於原觸發價格(newstopprice > stopprice),那么就更新觸發價格(stopprice = newstopprice)

如果新的觸發價格低於或等於原觸發價格(newstopprice <= stopprice),那么觸發價格保持不變

也就是說,觸發價格隨收盤價的上漲而上漲,如果收盤價不變或下跌,觸發價格則保持不變,由此來實現保護利潤的目的。

類似地,假設已經通過sell方法建倉,那么對於使用buy方法的平倉StopTrail訂單,成交規則與上述描述的過程相反,即觸發價格隨收盤價下跌而更新

 
        

StopTrailLimit訂單

其中,是否指定參數中的price值,StopTrailLimit會產生大不相同的兩種訂單執行邏輯。目前還不知道這是backtrader有意為之,還是實現出現了問題。下面分別就指定參數price值及不指定參數price值分開討論(這里假定限制價格plimit已指定,不指定plimit又是另一個故事了,考慮到我們是分析StopTrailLimit訂單,因此假定plimit已指定)。

在之前筆記中分析過,Limit類型的訂單不適合做平倉操作,因為可能造成長時間無法平倉,而造成重大的損失。因此,以下示例均使用buy方法進行建倉來演示StopTrailLimit訂單的執行邏輯。

指定參數price值

1. 訂單邏輯

當指定參數price值時,訂單的執行邏輯與StopLimit訂單相似。二者的區別在於,在StopLimit訂單中,觸發價格stopprice和限制價格limitprice均為固定值,而在StopTrailLimit訂單中觸發價格stopprice和限制價格limitprice都會隨着收盤價的變化進行變化。

在StopTrailLimit訂單中,在觸發價格與限制價格更新的同時,會檢測新的K線是否滿足當前觸發價格與限制價格條件下StopLimit訂單的執行邏輯,若已滿足則按照StopLimit訂單的規則執行訂單,即達到觸發價格后,再按照StopLimit訂單的邏輯執行訂單。

2. 初始化

在初始化階段,使用指定的price值及跟蹤比例trailpercent來計算觸發價格,即stopprice = price * (1 + trailpercent)

然后使用指定的price值及plimit值計算一個偏差值limitoffset = price - plimit

最后使用limitoffset及觸發價格stopprice來更新限制價格limitprice = stopprice -
limitoffset。后續在更新觸發價格stopprice及限制價格limitprice時,始終保持二者存在這一固定的差值limitoffset。

3. 價格更新與訂單執行

按照Stop訂單規則判斷訂單已被觸發,則按照StopLimit訂單規則執行訂單

按照Stop訂單規則判斷訂單未被觸發

如果收盤價高於(或等於)StopTrailLimit買單創建后的最低收盤價及初始指定的price值,則不更新觸發價格stopprice及限制價格limitprcie

如果收盤價低於StopTrailLimit買單創建后的最低收盤價或初始指定的price值,則更新觸發價格stopprice及限制價格limitprcie。觸發價格stopprice = price * (1 + trailpercent),其中price為所在K線的收盤價,trailpercent為給定的跟蹤比例。限制價格limitprice = stopprice - limitoffset,limitprice為之前計算的觸發價格及限制價格之間的固定差值。





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM