用户定义佣金#
重新设计CommInfo对象以实际运行的最重要部分包括:
保留原始的“CommissionInfo”类和行为
为用户定义的佣金提供便利性
将格式xx%设置为新的佣金方案的默认值,而不是0.xx(只是个人喜好),保持行为可配置
备注
有关参数参考,请参阅“CommInfoBase”的文档字符串如下所示
定义佣金方案#
涉及1或2个步骤
继承“CommInfoBase”
只需更改默认参数可能就足够了。“backtrader”已经在模块“backtrader.commissions”中对一些定义进行了更改。期货的常规行业标准是每个合同和每轮固定金额。可以通过以下方式进行定义:```python
- class CommInfo_Futures_Fixed(CommInfoBase):
- params = (
(‘stocklike’, False), (‘commtype’, CommInfoBase.COMM_FIXED),
)
# 对于股票和基于百分比的佣金 class CommInfo_Stocks_Perc(CommInfoBase):
- params = (
(‘stocklike’, True), (‘commtype’, CommInfoBase.COMM_PERC),
)
# 如上所述,默认情况下,百分比的解释(作为参数“commission”传递)为: xx% 。如果想要旧的/其他的行为为 0.xx # 可以轻松做到 class CommInfo_Stocks_PercAbs(CommInfoBase):
- params = (
(‘stocklike’, True), (‘commtype’, CommInfoBase.COMM_PERC), (‘percabs’, True),
)
# 2. 覆盖(如果需要) _getcommission
方法
# 定义如下: def _getcommission(self, size, price, pseudoexec):
‘’’计算给定价格的操作的佣金
pseudoexec: 如果为True,则表示此操作尚未执行 ‘’’
# 更多实际示例的详细信息请参见下面如何在平台上应用此功能#
一旦创建了 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 #45 <https://github.com/mementum/backtrader/issues/45> _询问一种针对期货的佣金模式,按百分比计算,并在佣金计算中使用合同的整个“虚拟”价值。即:佣金计算中包含期货乘数。应该很简单:
``` python import backtrader as bt
- class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
- params = (
(‘stocklike’, False), # 期货 (‘commtype’, bt.CommInfoBase.COMM_PERC), # 应用百分比佣金
)
- def _getcommission(self, size, price, pseudoexec):
return size * price * self.p.commission * self.p.mult
将其纳入系统中:
``` python comminfo = CommInfo_Fut_Perc_Mult(
commission=0.1, # 0.1% mult=10, margin=2000 # 期货类似工具需要保证金
)
cerebro.addcommissioninfo(comminfo) ```
如果将格式 0.xx 设为默认值,只需将参数 percabs
设置为 True
:
``` python class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
- params = (
(‘stocklike’, False), # 期货 (‘commtype’, bt.CommInfoBase.COMM_PERC), # 应用百分比佣金 (‘percabs’, True), # 将 percentage 设为 0.xx
)
- comminfo = CommInfo_Fut_Perc_Mult(
commission=0.001, # 0.1% mult=10, margin=2000 # 期货类似工具需要保证金
) ```cerebro.addcommissioninfo(comminfo)
这一切都应该能解决问题。
解释“pseudoexec”#
让我们回顾一下 _getcommission
的定义:
- def _getcommission(self, size, price, pseudoexec):
‘’’根据给定价格计算操作的手续费
pseudoexec: 如果为True,则表示该操作尚未执行 ‘’’
pseudoexec
参数的目的可能看起来有些模糊,但它确实有一个用途。
平台可能会调用该方法来预先计算可用现金和其他一些任务
这意味着该方法可能会(实际上也会)以相同的参数多次调用
pseudoexec
表示该调用是否对应于订单的实际执行。虽然乍一看可能看起来不相关,但考虑到以下情况,它是相关的: - 当交易合约的数量超过5000单位时,经纪人会提供50%的期货往返佣金折扣。
在这种情况下,如果
pseudoexec
不存在,对该方法的多次非执行调用将迅速触发折扣生效的假设。
让场景起作用:
import backtrader as bt
- class CommInfo_Fut_Discount(bt.CommInfoBase):
- params = (
(‘stocklike’, False), # 期货 (‘commtype’, bt.CommInfoBase.COMM_FIXED), # 应用佣金
# 折扣的自定义参数 (‘discount_volume’, 5000), # 达到折扣的最少合约数 (‘discount_perc’, 50.0), # 50.0% 的折扣
)
negotiated_volume = 0 # 用来跟踪实际合约数量的属性
- 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:
# 为了未来折扣保持跟踪实际的执行数量 self.negotiated_volume += size返回
commvalue
。
现在希望对 pseudoexec
的目的和用途有了一定的了解。
CommInfoBase文档字符串和参数#
参见:佣金: 股票 vs 期货 获取 CommInfoBase
的参考资料。