不可知論
在繼續之前,讓我們記住, 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和內部屬性_stocklikestocklike(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_interestinterest_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 * priceifautomargin < 0使用參數
automargin,即automargin * priceifautomargin > 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在默認實現中不使用,並作為覆蓋方法的額外輸入提供