用户定义的佣金
原文: https://www.backtrader.com/docu/user-defined-commissions/commission-schemes-subclassing/
将 CommInfo 对象修改为实际化身的最重要部分包括:
-
保留原有的
CommissionInfo
类和行为 -
打开大门,轻松创建用户定义的佣金
-
使新佣金方案的默认格式为 xx%,而不是 0.xx(只是口味问题),保持行为可配置
笔记
参数参考见CommInfoBase
文件串下方
确定佣金方案
它包括 1 到 2 个步骤
-
子类化
CommInfoBase
只需更改默认参数就足够了。
backtrader
已经在模块backtrader.commissions
中提供了一些定义。期货的常规行业标准是每笔合约和每轮交易的固定金额。定义如下:py class CommInfo_Futures_Fixed(CommInfoBase): params = ( ('stocklike', False), ('commtype', CommInfoBase.COMM_FIXED), )
对于股票和 perc-wise 佣金:
py class CommInfo_Stocks_Perc(CommInfoBase): params = ( ('stocklike', True), ('commtype', CommInfoBase.COMM_PERC), )
如上所述,此处解释百分比(作为参数
commission
传递)的默认值为:xx%。如果希望旧的/其他行为0.xx,则可以轻松完成:py class CommInfo_Stocks_PercAbs(CommInfoBase): params = ( ('stocklike', True), ('commtype', CommInfoBase.COMM_PERC), ('percabs', True), )
-
覆盖
_getcommission
方法(如果需要)定义为:
```py 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询问一种适用于期货的佣金方案,该方案是按百分比计算的,并在整个合同“虚拟”价值上使用佣金百分比。ie:包括佣金计算中的未来乘数。
这应该很容易:
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,只需将参数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
参考佣金:股票与期货