將 CommInfo 對象改造成實際涉及的最重要的部分:
保留原來的
CommissionInfo類和行為為輕鬆創建用戶定義的佣金打開大門
使格式 xx% 成為新佣金方案的默認值,而不是 0.xx(只是個人喜好問題),保持行為可配置
筆記
請參閱下面的CommInfoBase文檔字符串以獲取參數參考
定義佣金計劃
它涉及 1 或 2 個步驟
子類
CommInfoBase只需更改默認參數就足夠了。
backtrader已經使用模塊backtrader .commissions中的一些定義來做到這一點。期貨的常規行業標準是每份合約和每輪固定金額。定義可以如下:class CommInfo_Futures_Fixed(CommInfoBase): params = ( ('stocklike', False), ('commtype', CommInfoBase.COMM_FIXED), )對於股票和 perc-wise 佣金:
class CommInfo_Stocks_Perc(CommInfoBase): params = ( ('stocklike', True), ('commtype', CommInfoBase.COMM_PERC), )如上所述,此處解釋百分比的默認值(作為參數
commission傳遞)是: xx% 。如果希望舊的/其他行為0.xx ,可以輕鬆完成:class CommInfo_Stocks_PercAbs(CommInfoBase): params = ( ('stocklike', True), ('commtype', CommInfoBase.COMM_PERC), ('percabs', True), )覆蓋(如果需要)
_getcommission方法定義為:
def _getcommission(self, size, price, pseudoexec): '''Calculates the commission of an operation at a given price pseudoexec: if True the operation has not yet been executed '''
下面的實際示例中的更多詳細信息
如何將此應用到平台
一旦CommInfoBase子類就位,訣竅就是使用broker.addcommissioninfo而不是通常的broker.setcommission 。後者將在內部使用舊的CommissionInfoObject 。
做起來比說的容易:
... comminfo = CommInfo_Stocks_PercAbs(commission=0.005) # 0.5% cerebro.broker.addcommissioninfo(comminfo)
addcommissioninfo方法定義如下:
def addcommissioninfo(self, comminfo, name=None):
self.comminfo[name] = comminfo
設置name意味著comminfo對象將僅適用於具有該名稱的資產。默認值None意味著它適用於系統中的所有資產。
一個實際的例子
Ticket #45詢問適用於期貨的佣金計劃,以百分比計算,並使用合約的整個“虛擬”價值的佣金百分比。即:在佣金計算中包括未來乘數。
這應該很容易:
import backtrader as bt
class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
params = (
('stocklike', False), # Futures
('commtype', bt.CommInfoBase.COMM_PERC), # Apply % Commission
# ('percabs', False), # pass perc as xx% which is the default
)
def _getcommission(self, size, price, pseudoexec):
return size * price * self.p.commission * self.p.mult
將其放入系統:
comminfo = CommInfo_Fut_Perc_Mult(
commission=0.1, # 0.1%
mult=10,
margin=2000 # Margin is needed for futures-like instruments
)
cerebro.addcommissioninfo(comminfo)
如果首選格式0.xx作為默認值,只需將 param percabs設置為True :
class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
params = (
('stocklike', False), # Futures
('commtype', bt.CommInfoBase.COMM_PERC), # Apply % Commission
('percabs', True), # pass perc as 0.xx
)
comminfo = CommInfo_Fut_Perc_Mult(
commission=0.001, # 0.1%
mult=10,
margin=2000 # Margin is needed for futures-like instruments
)
cerebro.addcommissioninfo(comminfo)
這一切都應該解決問題。
解釋pseudoexec
讓我們回顧一下_getcommission的定義:
def _getcommission(self, size, price, pseudoexec):
'''Calculates the commission of an operation at a given price
pseudoexec: if True the operation has not yet been executed
'''
pseudoexec arg 的目的可能看起來晦澀難懂,但它是有目的的。
平台可能會調用該方法來進行可用現金的預計算和一些其他任務
這意味著該方法可能(並且實際上會)使用相同的參數多次調用
pseudoexec指示調用是否對應於訂單的實際執行。儘管乍一看這似乎並不“相關”,但如果考慮到以下情況:
一旦談判合約數量超過5000個單位,經紀人提供期貨往返佣金50%的折扣
在這種情況下,如果沒有
pseudoexec,對該方法的多次非執行調用將很快觸發折扣到位的假設。
讓場景發揮作用:
import backtrader as bt
class CommInfo_Fut_Discount(bt.CommInfoBase):
params = (
('stocklike', False), # Futures
('commtype', bt.CommInfoBase.COMM_FIXED), # Apply Commission
# Custom params for the discount
('discount_volume', 5000), # minimum contracts to achieve discount
('discount_perc', 50.0), # 50.0% discount
)
negotiated_volume = 0 # attribute to keep track of the actual volume
def _getcommission(self, size, price, pseudoexec):
if self.negotiated_volume > self.p.discount_volume:
actual_discount = self.p.discount_perc / 100.0
else:
actual_discount = 0.0
commission = self.p.commission * (1.0 - actual_discount)
commvalue = size * price * commission
if not pseudoexec:
# keep track of actual real executed size for future discounts
self.negotiated_volume += size
return commvalue
pseudoexec的目的和存在現在希望很清楚。
CommInfoBase 文檔字符串和參數
請參閱佣金:股票與期貨以供CommInfoBase參考