Backtrader 教程:佣金计划 - 扩展

  |  

佣金和相关功能由单个类CommissionInfo管理,该类主要通过调用broker.setcommission进行实例化。

该概念仅限于具有保证金和每份合约固定佣金的期货以及具有基于价格/规模百分比的佣金的股票。不是最灵活的计划,即使它已经达到了目的。

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

    这是兼容性的关键。如果值为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按日线交易

似乎在世界某个地方有一种权益(Interest)可以总结如下: 使用每日柱线引入订单,但使用开盘价 这来自工单#105订单执行逻辑与当前数据和#101动态投注计算中的对话 backtrader 尝试尽可能保持现实,并且在处理每日柱线时适用以下前提: 当每日柱被评估时,柱线已经结束 这是有道理的,

Backtrader改进代码

时不时地,带有 backtrader 代码的示例会在互联网上弹出。在我看来,有几个是中国人。最新的一个在这里: 标题是: backtrader-学习笔记2,这显然(感谢谷歌)翻译成 backtrader- 学习笔记2。

Backtrader追踪订单

版本1.9.35.116将StopTrail和StopTrailLimit订单运行类型添加到回测库中。笔记这仅在回测中实现,还没有针对实时经纪人的实现笔记更新为1.9.36.116版本。盈透证券支持StopTrail 、 StopTrailLimit和OCO 。

Backtrader 教程:绘图 - 同一轴

上一篇future-spot 将原始数据和稍微(随机)修改的数据绘制在同一空间上,但不在同一轴上。从该帖子中恢复第一张图片。有人能看见:图表左右两侧有不同的刻度当查看在原始数据周围振荡+- 50点的摆动红线(随机数据)时,这一点最为明显。在图表上,视觉印像是这些随机数据大多总是高于原始数据。

Backtrader期货补偿与现货补偿

版本1.9.32.116 增加了对社区中呈现的有趣用例 的支持 以期货开始交易,包括实物交割 让一个指针告诉你一些事情 如果需要, close 现货价格操作,有效地取消实物交割,无论是为了接收货物还是为了必须交付货物(并希望获利)来头寸。

Backtrader教程:数据馈送 - 扩展(Extending DataFeed)

GitHub 中的问题实际上是在推动文档部分的完成,或者説明我了解我是否backtrader 具有我从一开始就设想的易用性和灵活性以及在此过程中做出的决定。 在本例中为问题 #9。

Backtrader扩展数据馈送

GitHub 中的问题实际上是在推动文档部分的完成,或者说明我了解 backtrader 是否具有我从最初时刻就设想的易用性和灵活性以及在此过程中做出的决定。 在本例中为问题 #9。

数据多时间帧

有时投资决策是使用不同的时间框架做出的: 每周评估趋势 每天执行条目 或者5分钟对60分钟。 这意味着需要将多个时间帧的数据组合在 backtrader 中以支援此类组合。 对它的本机支持已经内置。

Backtrader python 隐藏的细节

只有当遇到 backtrader 的真实用户时,人们才能意识到平台中使用的抽象和Python功能是否有意义。 在不撇开python的座右铭的情况下, backtrader 试图为用户提供尽可能多的控制权,同时通过将Python提供的隐藏功能付诸行动来简化使用。 第一个示例是系列文章的第一篇。

Backtrader多重交易

即使在相同的数据上运行,现在也可以为每笔交易添加唯一标识符。根据Tick Data and Resampling 版本backtrader的请求,支持“MultiTrades”,即:为订单分配tradeid的能力。此 id 被传递给Trades ,这使得有可能拥有不同类别的交易并同时打开它们。