不可知論
在繼續之前,讓我們記住, backtrader
者試圖對數據代表什麼保持不可知論。不同的佣金方案可以應用於相同的數據集。
讓我們看看它是如何做到的。
使用代理快捷方式
這使最終用戶遠離CommissionInfo
對象,因為可以通過單個函數調用創建/設置佣金方案。在常規的cerebro
創建/設置過程中,只需在broker
成員屬性上添加對setcommission
的調用。以下調用設置了與盈透證券合作時Eurostoxx50期貨的常規佣金計劃:
cerebro.broker.setcommission(commission=2.0, margin=2000.0, mult=10.0)
由於大多數用戶通常只測試一個儀器,這就是它的全部。如果您已為數據饋送name
,因為圖表上同時考慮了多個工具,此調用可以稍微擴展為如下所示:
cerebro.broker.setcommission(commission=2.0, margin=2000.0, mult=10.0, name='Eurostoxxx50')
在這種情況下,這種即時佣金計劃將僅適用於名稱與Eurostoxx50
匹配的工具。
setcommission參數的含義
commission
(默認值:0.0
)以絕對或百分比計算的貨幣單位每項行動的成本。
在上面的例子中,每份
buy
合約 2.0 歐元,sell
每份合約 2.0 歐元。這裡的重要問題是何時使用絕對值或百分比值。
如果
margin
評估為False
(例如為False 、0 或 None),則認為commission
表示price
乘以size
操作值的百分比如果
margin
是其他東西,則認為該操作是在諸如工具之類的futures
上進行的,而commission
是size
合約的固定價格
margin
(默認值:None
)使用諸如工具之類的
futures
進行操作時需要保證金。如上所述如果設置了無
margin
,則commission
將被理解為以百分比表示並應用於buy
或sell
操作的price * size
組成部分如果設置了
margin
,commission
將被理解為乘以buy
或sell
操作的size
分量的固定值
mult
(默認值:1.0)對於
future
類似的工具,這決定了應用於損益計算的乘數。這就是使期貨同時具有吸引力和風險的原因。
name
(默認:無)將佣金計劃的應用限制在與
name
匹配的工具上這可以在創建數據饋送期間進行設置。
如果未設置,該方案將適用於系統中存在的任何數據。
現在舉兩個例子:股票與期貨
上面的期貨示例:
cerebro.broker.setcommission(commission=2.0, margin=2000.0, mult=10.0)
股票的一個例子:
cerebro.broker.setcommission(commission=0.005) # 0.5% of the operation value
筆記
第二種語法不設置保證金,並且 mult 和 backtrader嘗試一種聰明的方法,將佣金考慮為基於%
。
要完全指定佣金方案,需要創建CommissionInfo
的子類
創建永久佣金計劃
可以通過直接使用CommissionInfo
類來創建更永久的佣金方案。用戶可以選擇在某處有這個定義:
import backtrader as bt commEurostoxx50 = bt.CommissionInfo(commission=2.0, margin=2000.0, mult=10.0)
稍後使用addcommissioninfo
將其應用到另一個 Python 模塊中:
from mycomm import commEurostoxx50 ... cerebro.broker.addcommissioninfo(commEuroStoxx50, name='Eurostoxxx50')
CommissionInfo
是一個使用params
聲明的對象,就像backtrader
環境中的其他對像一樣。因此,上述也可以表示為:
import backtrader as bt class CommEurostoxx50(bt.CommissionInfo): params = dict(commission=2.0, margin=2000.0, mult=10.0)
然後:
from mycomm import CommEurostoxx50 ... cerebro.broker.addcommissioninfoCommEuroStoxx50(), name='Eurostoxxx50')
現在與 SMA Crossover 進行“真實”比較
使用 SimpleMovingAverage 交叉作為進入/退出信號,相同的數據集將使用類似futures
的佣金計劃進行測試,然後使用類似的stocks
進行測試。
筆記
期貨頭寸不僅可以被賦予進入/退出行為,而且在每種情況下都可以被賦予反轉行為。但是這個例子是關於比較佣金計劃的。
代碼(完整策略見底部)是相同的,可以在定義策略之前選擇方案。
futures_like = True if futures_like: commission, margin, mult = 2.0, 2000.0, 10.0 else: commission, margin, mult = 0.005, None, 1
只需將futures_like
設置為false即可與stocks
類似方案一起運行。
添加了一些日誌代碼來評估不同佣金方案的影響。讓我們只關注前兩個操作。
對於期貨:
2006-03-09, BUY CREATE, 3757.59 2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 2000.00, Comm 2.00 2006-04-11, SELL CREATE, 3788.81 2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 2000.00, Comm 2.00 2006-04-12, OPERATION PROFIT, GROSS 328.00, NET 324.00 2006-04-20, BUY CREATE, 3860.00 2006-04-21, BUY EXECUTED, Price: 3863.57, Cost: 2000.00, Comm 2.00 2006-04-28, SELL CREATE, 3839.90 2006-05-02, SELL EXECUTED, Price: 3839.24, Cost: 2000.00, Comm 2.00 2006-05-02, OPERATION PROFIT, GROSS -243.30, NET -247.30
對於股票:
2006-03-09, BUY CREATE, 3757.59 2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 3754.13, Comm 18.77 2006-04-11, SELL CREATE, 3788.81 2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 3786.93, Comm 18.93 2006-04-12, OPERATION PROFIT, GROSS 32.80, NET -4.91 2006-04-20, BUY CREATE, 3860.00 2006-04-21, BUY EXECUTED, Price: 3863.57, Cost: 3863.57, Comm 19.32 2006-04-28, SELL CREATE, 3839.90 2006-05-02, SELL EXECUTED, Price: 3839.24, Cost: 3839.24, Comm 19.20 2006-05-02, OPERATION PROFIT, GROSS -24.33, NET -62.84
第一次操作的價格如下:
買入(執行)-> 3754.13 / 賣出(執行)-> 3786.93
期貨盈虧(含佣金):324.0
股票損益(含佣金):-4.91
嘿!!委員會已經完全吞噬了stocks
業務的任何利潤,但對futures
業務的影響只是很小的一部分。
第二次操作:
買入(執行)->
3863.57
/ 賣出(執行)->3389.24
期貨盈虧(含佣金):-
-247.30
股票損益(含佣金):-
-62.84
這種對futures
的負面操作的影響明顯更大
但:
期貨累計淨損益:
324.00 + (-247.30) = 76.70
股票累計淨損益:
(-4.91) + (-62.84) = -67.75
累積效應可以在下面的圖表中看到,從圖中也可以看出,在全年結束時,期貨產生了更大的利潤,但也遭受了更大的回撤(水下更深)
但重要的是:無論是futures
還是stocks
……都可以進行回測。
期貨佣金
股票佣金
編碼
from __future__ import (absolute_import, division, print_function, unicode_literals) import backtrader as bt import backtrader.feeds as btfeeds import backtrader.indicators as btind futures_like = True if futures_like: commission, margin, mult = 2.0, 2000.0, 10.0 else: commission, margin, mult = 0.005, None, 1 class SMACrossOver(bt.Strategy): def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def notify(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - Nothing to do return # Check if an order has been completed # Attention: broker could reject order if not enougth cash if order.status in [order.Completed, order.Canceled, order.Margin]: if order.isbuy(): self.log( 'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm self.opsize = order.executed.size else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) gross_pnl = (order.executed.price - self.buyprice) * \ self.opsize if margin: gross_pnl *= mult net_pnl = gross_pnl - self.buycomm - order.executed.comm self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (gross_pnl, net_pnl)) def __init__(self): sma = btind.SMA(self.data) # > 0 crossing up / < 0 crossing down self.buysell_sig = btind.CrossOver(self.data, sma) def next(self): if self.buysell_sig > 0: self.log('BUY CREATE, %.2f' % self.data.close[0]) self.buy() # keep order ref to avoid 2nd orders elif self.position and self.buysell_sig < 0: self.log('SELL CREATE, %.2f' % self.data.close[0]) self.sell() if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() # Add a strategy cerebro.addstrategy(SMACrossOver) # Create a Data Feed datapath = ('../../datas/2006-day-001.txt') data = bt.feeds.BacktraderCSVData(dataname=datapath) # Add the Data Feed to Cerebro cerebro.adddata(data) # set commission scheme -- CHANGE HERE TO PLAY cerebro.broker.setcommission( commission=commission, margin=margin, mult=mult) # Run over everything cerebro.run() # Plot the result cerebro.plot()
參考
類反向交易者 .CommInfoBase ()
佣金計劃的基類。
參數:
commission
(定義:0.0
):以百分比或貨幣單位表示的基本佣金值mult
(def1.0
): 應用於資產價值/利潤的乘數margin
(定義:None
):打開/持有操作所需的貨幣單位數量。僅當類中的最終_stocklike
屬性設置為False
時才適用automargin
(def:False
): 由方法get_margin
用於自動計算以下策略所需的保證金/保證如果 param
automargin
評估為False
,則使用 parammargin
如果
automargin < 0
,則使用 parammult
並使用mult * price
使用參數
automargin
並使用automargin * price
如果automargin > 0
commtype
(def:None
): 支持的值為CommInfoBase.COMM_PERC
(佣金被理解為 %)和CommInfoBase.COMM_FIXED
(佣金被理解為貨幣單位)None
的默認值是支持的值,以保持與舊CommissionInfo
對象的兼容性。如果commtype
設置為 None,則以下內容適用:margin
為None
:內部_commtype
設置為COMM_PERC
並且_stocklike
設置為True
(使用股票操作 %-wise)margin
不是None
:_commtype
設置為COMM_FIXED
和_stocklike
設置為False
(使用期貨固定往返佣金操作)
如果此參數設置為
None
以外的其他值,則它將傳遞給內部_commtype
屬性,並且對參數stocklike
和內部屬性_stocklike
stocklike
(def:False
): 指示該工具是 Stock-like 還是 Futures-like (參見上面的commtype
討論)percabs
(def:False
):commtype
設置為 COMM_PERC 時,參數commission
是否必須理解為 XX% 或 0.XX如果此參數為
True
:0.XX 如果此參數為False
:XX%interest
(def:0.0
)如果該值非零,則為持有賣空頭寸收取的年利息。這主要用於股票賣空
公式:
days * price * abs(size) * (interest / 365)
必須以絕對值指定:0.05 -> 5%
筆記
可以通過覆蓋方法來更改行為:
_get_credit_interest
interest_long
(def:False
)某些產品(例如 ETF)會收取空頭和多頭頭寸的利息。如果 ths 為
True
且interest
不為零,則將在兩個方向上收取利息leverage
(def:1.0
)與所需現金相關的資產槓桿率
- ``_stocklike``()
用於股票類/期貨類行為的最終值
-``_commtype``()
用於 PERC 與 FIXED 佣金的最終價值
這兩個在內部使用而不是聲明的參數來啟用()
上述對遺留 ``CommissionInfo``() 的兼容性檢查
目的()
類反向交易者 .CommissionInfo ()
實際佣金計劃的基類。
創建 CommInfoBase 是為了支持backtrader提供的原始、不完整的支持。新的佣金計劃派生自此類,它是CommInfoBase
的子類。
percabs
的默認值也更改為True
參數:
percabs
(def: True ):commtype
設置為 COMM_PERC 時,參數commission
是否必須理解為 XX% 或 0.XX如果此參數為真:0.XX 如果此參數為假:XX%
獲取槓桿()
返回此佣金計劃允許的槓桿水平
getsize(價格,現金)
返回在給定價格下滿足現金操作所需的大小
獲取運營成本(大小,價格)
返回操作所需的現金金額
getvaluesize(大小,價格)
返回給定價格的大小值。對於類似未來的對象,它固定為size * margin
獲取價值(位置,價格)
返回給定價格的頭寸值。對於類似未來的對象,它固定為size * margin
get_margin(價格)
返回給定價格的單個資產項目所需的實際保證金/擔保。默認實現具有此策略:
如果 param
automargin
評估為False
,則使用 parammargin
使用參數
mult
,即mult * price
ifautomargin < 0
使用參數
automargin
,即automargin * price
ifautomargin > 0
獲得佣金(尺寸,價格)
計算給定價格的操作佣金
_getcommission(大小,價格,偽執行)
計算給定價格的操作佣金
pseudoexec:如果為True ,則操作尚未執行
盈虧(大小、價格、新價格)
返回頭寸的實際盈虧
現金調整(大小,價格,新價格)
計算給定價格差異的現金調整
get_credit_interest(數據,pos,dt)
計算賣空或特定產品的信用額度
_get_credit_interest(數據、大小、價格、天數、dt0、dt1)
此方法以經紀人收取的信用利息返回成本。
在size > 0
的情況下,僅當類interest_long
的參數為True
時才會調用此方法
信貸利率的計算公式為:
公式: days * price * abs(size) * (interest / 365)
參數:
* `data`: data feed for which interest is charged * `size`: current position size. > 0 for long positions and < 0 for short positions (this parameter will not be `0`) * `price`: current position price * `days`: number of days elapsed since last credit calculation (this is (dt0 - dt1).days) * `dt0`: (datetime.datetime) current datetime * `dt1`: (datetime.datetime) datetime of previous calculation
dt0
和dt1
在默認實現中不使用,並作為覆蓋方法的額外輸入提供