Backtrader 教程:佣金計劃

  |  

不可知論

在繼續之前,讓我們記住, 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上進行的,而commissionsize合約的固定價格

  • margin (默認值: None

    使用諸如工具之類的futures進行操作時需要保證金。如上所述

    • 如果設置了margin ,則commission將被理解為以百分比表示並應用於buysell操作的price * size組成部分

    • 如果設置了margincommission將被理解為乘以buysell操作的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 (def 1.0 ): 應用於資產價值/利潤的乘數

  • margin (定義: None ):打開/持有操作所需的貨幣單位數量。僅當類中的最終_stocklike屬性設置為False時才適用

  • automargin (def: False ): 由方法get_margin用於自動計算以下策略所需的保證金/保證

    • 如果 param automargin評估為False ,則使用 param margin

    • 如果automargin < 0 ,則使用 param mult並使用mult * price

    • 使用參數automargin並使用automargin * price如果automargin > 0

  • commtype (def: None ): 支持的值為CommInfoBase.COMM_PERC (佣金被理解為 %)和CommInfoBase.COMM_FIXED (佣金被理解為貨幣單位)

    None的默認值是支持的值,以保持與舊CommissionInfo對象的兼容性。如果commtype設置為 None,則以下內容適用:

    • marginNone :內部_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 為Trueinterest不為零,則將在兩個方向上收取利息

  • 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 ,則使用 param margin

  • 使用參數mult ,即mult * price if automargin < 0

  • 使用參數automargin ,即automargin * price if automargin > 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

dt0dt1在默認實現中不使用,並作為覆蓋方法的額外輸入提供

推薦閱讀

相關文章

Backtrader策略選擇

休士頓我們有一個問題: cerebro 不應多次運行。這不是第1次 ,而不是認為使用者做錯了,這似乎是一個用例。 這個有趣的用例是通過票證177出現的。在這種情況下, cerebro 被多次用於評估從外部數據源獲取的不同策略。 backtrader 仍然可以支援此用例,但不能以直接嘗試的方式支援。

Backtrader教程:經紀人 - 開倉作弊

“發佈”1.9.44.116 添加了對 Cheat-On-Open的支援。這似乎是那些全力以赴的人的需求功能,他們在酒吧 close 后進行了計算,但希望與 open 價格相匹配。 當開盤價跳空(上漲或下跌,取決於是否buysell有效)並且現金不足以進行全面運營時,這樣的用例就會失敗。這將強制代理拒絕該操作。

Backtrader改進代碼

時不時地,帶有 backtrader 代碼的示例會在互聯網上彈出。在我看來,有幾個是中國人。最新的一個在這裡: 標題是: backtrader-學習筆記2,這顯然(感謝谷歌)翻譯成 backtrader- 學習筆記2。

Backtrader教程:數據饋送 - 擴展 (Extending DataFeed)

GitHub 中的問題實際上是在推動文檔部分的完成,或者説明我瞭解我是否backtrader 具有我從一開始就設想的易用性和靈活性以及在此過程中做出的決定。 在本例中為問題 #9。

Backtrader 教程:經紀人 - 滑點

回測不能保證真實的市場狀況。無論市場模擬有多好,在真實的市場條件下都會發生滑點。這意味著:要求的價格可能不匹配。集成的回測代理支持滑點。

Backtrader跨越數位

《backtrader》的發佈1.9.27.105糾正了一個疏忽。這是一個疏忽,因為拼圖的所有部分都已到位,但啟動並不是在所有角落都進行的。 該機制使用一個名為的屬性_mindatas,因此讓我們將其稱為: mindatas。 社區問了這個問題,答案並不是很到位。

Backtrader數據多時間幀

有時投資決策是使用不同的時間框架做出的: 每周評估趨勢 每天執行條目 或者5分鐘對60分鐘。 這意味著需要將多個時間幀的數據組合在 backtrader 中以支援此類組合。 對它的本機支持已經內置。

Backtrader節省記憶體

1.3.1.92版本已經重新設計並完全實現了以前到位的記憶體節省方案,儘管沒有太多的吹捧和使用。

Backtrader多數據範例

社區中的幾個主題似乎以如何跟蹤訂單為導向,特別是當幾個data feeds在起作用時,還包括當多個訂單一起工作時,

Backtrader開發指標

經過 backtrader 微調(因為它已經運行了一段時間),我決定不僅通過GitHub分享它,還告訴世界它在那裡,並在“Reddit”中發佈它的存在。 在評論了為什麼交易/演算法交易平臺會彈出,以及關於支持許多同時交易的即時交易的平臺的私人問題之後,我得出的結論是,我自己的孩子應該擁有自己的博客。 我們來了。