Backtrader擴展佣金計劃

  |  

佣金和相關功能由單個類 CommissionInfo 管理,該類主要通過調用 broker.setcommission 進行實例化。

有一些帖子討論了這種行為。

  • 佣金:股票與期貨

  • 提高佣金:股票與期貨

該概念僅限於具有保證金和每份合約固定佣金的期貨以及具有基於價格/規模百分比的佣金的股票。不是最靈活的計劃,即使它已經達到了目的。

關於我自己的實現,只有一件事我不喜歡,那就是CommissionInfo採用絕對值 (0.xx) 而不是相對值 (xx%) 的百分比值

GitHub #29上的增強請求導致了一些返工,以便:

  • 保持CommissionInfobroker.setcommission與原始行為兼容

  • 對代碼進行一些清理

  • 使委員會計劃靈活,以支持增強請求和進一步的可能性

拿到樣品前的實際工作:

class CommInfoBase(with_metaclass(MetaParams)):
    COMM_PERC, COMM_FIXED = range(2)

    params = (
        ('commission', 0.0), ('mult', 1.0), ('margin', None),
        ('commtype', None),
        ('stocklike', False),
        ('percabs', False),
    )

引入了CommissionInfo的基類,它向組合中添加了新參數:

  • commtype (默認值:無)

    這是兼容性的關鍵。如果值為None ,則CommissionInfo對象和broker.setcommission的行為將像以前一樣工作。就是這樣:

    • 如果設置了margin ,那麼佣金計劃適用於每份合約固定佣金的期貨

    • 如果未設置margin ,佣金計劃適用於基於百分比方法的股票

    如果值為COMM_PERCCOMM_FIXED (或任何其他派生類),這顯然決定了佣金是固定的還是基於百分比的

  • stocklike (默認值: False

    如上所述,舊的CommissionInfo對像中的實際行為由參數margin確定

    如上所述,如果commtype設置為None以外的其他值,則此值指示該資產是否為類似期貨的資產(將使用保證金並執行基於條形的現金調整 9 或者這是類似股票的資產

  • percabs (默認值: False

    如果為False ,則百分比必須以相對形式傳遞 (xx%)

    如果為True ,則百分比必須作為絕對值 (0.xx) 傳遞

    CommissionInfoCommInfoBase的子類,將此參數的默認值更改為True以保持兼容的行為

所有這些參數也可以在broker.setcommission中使用,現在看起來像這樣:

def setcommission(self,
                  commission=0.0, margin=None, mult=1.0,
                  commtype=None, percabs=True, stocklike=False,
                  name=None):

請注意以下事項:

  • percabsTrue以保持與上面提到的CommissionInfo對象的舊調用兼容的行為

測試commissions-schemes的舊樣本已經過重新設計,以支持命令參數和新行為。使用幫助:

$ ./commission-schemes.py --help
usage: commission-schemes.py [-h] [--data DATA] [--fromdate FROMDATE]
                             [--todate TODATE] [--stake STAKE]
                             [--period PERIOD] [--cash CASH] [--comm COMM]
                             [--mult MULT] [--margin MARGIN]
                             [--commtype {none,perc,fixed}] [--stocklike]
                             [--percrel] [--plot] [--numfigs NUMFIGS]

Commission schemes

optional arguments:
  -h, --help            show this help message and exit
  --data DATA, -d DATA  data to add to the system (default:
                        ../../datas/2006-day-001.txt)
  --fromdate FROMDATE, -f FROMDATE
                        Starting date in YYYY-MM-DD format (default:
                        2006-01-01)
  --todate TODATE, -t TODATE
                        Starting date in YYYY-MM-DD format (default:
                        2006-12-31)
  --stake STAKE         Stake to apply in each operation (default: 1)
  --period PERIOD       Period to apply to the Simple Moving Average (default:
                        30)
  --cash CASH           Starting Cash (default: 10000.0)
  --comm COMM           Commission factor for operation, either apercentage or
                        a per stake unit absolute value (default: 2.0)
  --mult MULT           Multiplier for operations calculation (default: 10)
  --margin MARGIN       Margin for futures-like operations (default: 2000.0)
  --commtype {none,perc,fixed}
                        Commission - choose none for the old CommissionInfo
                        behavior (default: none)
  --stocklike           If the operation is for stock-like assets orfuture-
                        like assets (default: False)
  --percrel             If perc is expressed in relative xx{'const': True,
                        'help': u'If perc is expressed in relative xx%
                        ratherthan absolute value 0.xx', 'option_strings': [u'
                        --percrel'], 'dest': u'percrel', 'required': False,
                        'nargs': 0, 'choices': None, 'default': False, 'prog':
                        'commission-schemes.py', 'container':
                        <argparse._ArgumentGroup object at
                        0x0000000007EC9828>, 'type': None, 'metavar':
                        None}atherthan absolute value 0.xx (default: False)
  --plot, -p            Plot the read data (default: False)
  --numfigs NUMFIGS, -n NUMFIGS
                        Plot using numfigs figures (default: 1)

讓我們運行一些程序來重新創建原始佣金計劃帖子的原始行為。

期貨佣金(固定和有保證金)

執行和圖表:

$ ./commission-schemes.py --comm 2.0 --margin 2000.0 --mult 10 --plot

輸出顯示固定佣金為 2.0 個貨幣單位(默認賭注為 1):

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, TRADE PROFIT, GROSS 328.00, NET 324.00
...

股票佣金(perc 和無保證金)

執行和圖表:

$ ./commission-schemes.py --comm 0.005 --margin 0 --mult 1 --plot

為了提高可讀性,可以使用相對百分比值:

$ ./commission-schemes.py --percrel --comm 0.5 --margin 0 --mult 1 --plot

現在0.5直接表示0.5%

作為兩種情況下的輸出:

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: 3754.13, Comm 18.93
2006-04-12, TRADE PROFIT, GROSS 32.80, NET -4.91
...

期貨佣金(perc 和保證金)

使用新參數,基於 perc 的方案的期貨:

$ ./commission-schemes.py --commtype perc --percrel --comm 0.5 --margin 2000 --mult 10 --plot

毫不奇怪,通過改變委員會......最終結果已經改變

輸出顯示佣金現在是可變的:

2006-03-09, BUY CREATE, 3757.59
2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 2000.00, Comm 18.77
2006-04-11, SELL CREATE, 3788.81
2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 2000.00, Comm 18.93
2006-04-12, TRADE PROFIT, GROSS 328.00, NET 290.29
...

在上一次運行中設置 2.0 貨幣單位(默認賭注為 1)

另一篇文章將詳細介紹新課程和男士熟食佣金計劃的實施。

示例代碼

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import argparse
import datetime

import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind


class SMACrossOver(bt.Strategy):
    params = (
        ('stake', 1),
        ('period', 30),
    )

    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_order(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))
            else:  # Sell
                self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                         (order.executed.price,
                          order.executed.value,
                          order.executed.comm))

    def notify_trade(self, trade):
        if trade.isclosed:
            self.log('TRADE PROFIT, GROSS %.2f, NET %.2f' %
                     (trade.pnl, trade.pnlcomm))

    def __init__(self):
        sma = btind.SMA(self.data, period=self.p.period)
        # > 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(size=self.p.stake)  # 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(size=self.p.stake)


def runstrategy():
    args = parse_args()

    # Create a cerebro
    cerebro = bt.Cerebro()

    # Get the dates from the args
    fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
    todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')

    # Create the 1st data
    data = btfeeds.BacktraderCSVData(
        dataname=args.data,
        fromdate=fromdate,
        todate=todate)

    # Add the 1st data to cerebro
    cerebro.adddata(data)

    # Add a strategy
    cerebro.addstrategy(SMACrossOver, period=args.period, stake=args.stake)

    # Add the commission - only stocks like a for each operation
    cerebro.broker.setcash(args.cash)

    commtypes = dict(
        none=None,
        perc=bt.CommInfoBase.COMM_PERC,
        fixed=bt.CommInfoBase.COMM_FIXED)

    # Add the commission - only stocks like a for each operation
    cerebro.broker.setcommission(commission=args.comm,
                                 mult=args.mult,
                                 margin=args.margin,
                                 percabs=not args.percrel,
                                 commtype=commtypes[args.commtype],
                                 stocklike=args.stocklike)

    # And run it
    cerebro.run()

    # Plot if requested
    if args.plot:
        cerebro.plot(numfigs=args.numfigs, volume=False)


def parse_args():
    parser = argparse.ArgumentParser(
        description='Commission schemes',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,)

    parser.add_argument('--data', '-d',
                        default='../../datas/2006-day-001.txt',
                        help='data to add to the system')

    parser.add_argument('--fromdate', '-f',
                        default='2006-01-01',
                        help='Starting date in YYYY-MM-DD format')

    parser.add_argument('--todate', '-t',
                        default='2006-12-31',
                        help='Starting date in YYYY-MM-DD format')

    parser.add_argument('--stake', default=1, type=int,
                        help='Stake to apply in each operation')

    parser.add_argument('--period', default=30, type=int,
                        help='Period to apply to the Simple Moving Average')

    parser.add_argument('--cash', default=10000.0, type=float,
                        help='Starting Cash')

    parser.add_argument('--comm', default=2.0, type=float,
                        help=('Commission factor for operation, either a'
                              'percentage or a per stake unit absolute value'))

    parser.add_argument('--mult', default=10, type=int,
                        help='Multiplier for operations calculation')

    parser.add_argument('--margin', default=2000.0, type=float,
                        help='Margin for futures-like operations')

    parser.add_argument('--commtype', required=False, default='none',
                        choices=['none', 'perc', 'fixed'],
                        help=('Commission - choose none for the old'
                              ' CommissionInfo behavior'))

    parser.add_argument('--stocklike', required=False, action='store_true',
                        help=('If the operation is for stock-like assets or'
                              'future-like assets'))

    parser.add_argument('--percrel', required=False, action='store_true',
                        help=('If perc is expressed in relative xx% rather'
                              'than absolute value 0.xx'))

    parser.add_argument('--plot', '-p', action='store_true',
                        help='Plot the read data')

    parser.add_argument('--numfigs', '-n', default=1,
                        help='Plot using numfigs figures')

    return parser.parse_args()


if __name__ == '__main__':
    runstrategy()

推薦閱讀

相關文章

Backtrader細分傭金計劃

不久前,委員會計劃的實施進行了重新設計。最重要的是:涉及的部分返工: 保留原始的傭金資訊類和行為 打開大門,輕鬆創建使用者定義的傭金 將格式 xx% 作為新傭金方案的預設值,而不是 0.xx(只是一個品味問題),保持行為可配置 擴展委員會概述了基本要素。

BacktraderPython Hidden Powers 2

讓我們進一步討論一下Python的隱藏功能如何在 backtrader 中使用,以及如何實現它以嘗試實現主要目標:易用性 這些定義是什麼? 例如指標: import backtrader as bt class MyIndicator(bt.

Backtrader教程:經紀人 - 體積灌裝 - 灌裝機

backtrader經紀商類比在使用volume執行訂單時具有預設策略: 忽略 volume 這是基於2個前提: 在市場中交易的流動性足以一次性完全吸收買入/賣出訂單 真正的 volume 匹配需要真正的狼 一個簡單的例子是Fill or Kill 訂單。

Backtrader對逐筆報價數據重新取樣

backtrader 已經可以從分鐘數據中重新採樣。接受價格變動數據不是問題,只需將 4 個常用欄位(open、 high、 low、 close)設置為價格變動值。 但是傳遞要重新採樣的逐筆報價數據再次生成相同的數據。作為或版本 1.1.11.88,情況已不再如此。

Backtrader觀察員和統計

在 backtrader 內部運行的策略主要處理數據 和 指標。 數據被添加到Cerebro 實例中,並最終成為策略輸入的一部分(解析並用作實例的屬性),而指標由策略本身聲明和管理。

Backtrader Python隐藏的细节

只有當遇到 backtrader 的真實使用者時,人們才能意識到平臺中使用的抽象和Python功能是否有意義。 在不撇開python的座右銘的情況下, backtrader 試圖為使用者提供盡可能多的控制權,同時通過將Python提供的隱藏功能付諸行動來簡化使用。 第一個示例是系列文章的第一篇。

Backtrader教程:日期時間 - 管理

在 1.5.0 版之前, backtrader 使用直接的方法來進行時間管理,因為數據源計算的任何日期時間都只是按面值使用。 對於任何使用者輸入也是如此,例如可以提供給任何數據源的參數fromdate (或 sessionstart)的情況 考慮到直接控制凍結的數據源以進行回溯測試,這種方法很好。

Backtrader多數據範例

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

Backtrader傭金計劃

發佈 backtrader 使用示例使我對缺失的東西有了深刻的瞭解。

Backtrader教程:策略 - 信號

操作 backtrader 也是可能的,而無需編寫策略。雖然這是首選方式,但由於構成機器的對象層次結構,使用信號也是可能的。