大小调整器 - 智能押注#
一个 策略 提供了交易的方法,例如: buy , sell 和 close 。我们来看一下 buy 的签名:
def buy(self, data=None,
        size=None, price=None, plimit=None,
        exectype=None, valid=None, tradeid=0, **kwargs):
请注意,如果调用者没有指定, size 的默认值为 None 。这就是 大小调整器 发挥重要作用的地方:
size=None请求 策略 向其 * 大小调整器* 请求实际的押注量
显然, 策略*有一个 大小调整器 :是的,确实!背后的机制会为 * 策略 * 添加一个默认的大小调整器,如果用户未添加大小调整器。默认添加到 * 策略 的大小调整器是 SizerFix 。定义的初始行:
class SizerFix(SizerBase):
    params = (('stake', 1),)
很容易猜到,这个 大小调整器 只是使用 1 单位的押注量进行 买入/卖出 (无论是股份还是合同…)
使用 大小调整器#
来自 Cerebro ============可以通过 Cerebro 使用两种不同的方法添加 Sizers :
addsizer(sizercls, *args, **kwargs)添加一个 Sizer ,该 Sizer 将应用于添加到 cerebro 的任何策略。这可以说是默认 Sizer 。示例:
cerebro = bt.Cerebro() cerebro.addsizer(bt.sizers.SizerFix, stake=20) # 策略的默认sizer
addsizer_byidx(idx, sizercls, *args, **kwargs)Sizer 仅添加到“idx”所引用的 Strategy 中
可以从
addstrategy的返回值获得此“idx”。如下所示:cerebro = bt.Cerebro() cerebro.addsizer(bt.sizers.SizerFix, stake=20) # 策略的默认sizer idx = cerebro.addstrategy(MyStrategy, myparam=myvalue) cerebro.addsizer_byidx(idx, bt.sizers.SizerFix, stake=5) cerebro.addstrategy(MyOtherStrategy)在这个例子中:
系统中已添加了一个默认的 Sizer 。这个 Sizer 适用于所有没有指定特定 Sizer 的策略
对于 MyStrategy ,在收集了其插入位置 idx 之后,添加了一个特定的 Sizer (更改了
stake参数)
添加了第二个策略 MyOtherStrategy 到系统中。对于它没有添加特定的 Sizer
这意味着:
MyStrategy 最终将拥有一个内部的特定 Sizer
MyOtherStrategy 将获得默认的 Sizer
注意
default 并不意味着策略共享一个单一的 Sizer 实例。每个 strategy 都会收到一个不同的实例来代表 default sizer
要共享一个单一的实例,需要将要共享的 sizer 定义为一个单例类。如何定义单例类超出了 backtrader 的范围
来自 Strategy**Strategy 类提供了一个 API: setsizer 和 getsizer (还有一个 property sizer )来管理 Sizer 。它们的签名如下:
def setsizer(self, sizer):接受一个已经实例化的 Sizer
def getsizer(self):返回当前的 Sizer 实例
sizer是一个可直接 get/set 的属性
在这种情况下, Sizer 可以是以下的其中一种情况:
作为参数传递给策略
在
__init__中使用属性sizer或setsizer进行设置,例如:
- class MyStrategy(bt.Strategy):
params = ((‘sizer’, None),)
- def __init__(self):
- if self.p.sizer is not None:
self.sizer = self.p.sizer
这样的做法可以在与 cerebro 调用发生的相同级别上创建一个 Sizer ,并将其作为参数传递给系统中的所有策略,从而实现共享一个 Sizer 。Sizer 开发
*** ** ** ** ** ** **
做这件事很容易:
继承自
backtrader.Sizer这将使你能够访问
self.strategy和self.broker,虽然在大多数情况下不需要这样做。可以通过broker访问以下内容
使用
self.strategy.getposition(data)获取数据的仓位
通过
self.broker.getvalue()获取完整的投资组合价值当然,也可以使用
self.strategy.broker.getvalue()其他一些参数已经在下面了
重写方法
_getsizing(self, comminfo, cash, data, isbuy)
comminfo: CommissionInfo 实例,包含关于数据的佣金信息,允许计算仓位价值、操作成本、操作的佣金
cash: 经纪人当前可用的现金- data : 操作的目标
- isbuy : 对于“买入”操作将为 True ,对于“卖出”操作将为 False 
该方法返回“买入/卖出”操作的所需 size
返回的符号无关紧要,即:如果操作是“卖出”操作( isbuy 为`False ),该方法可以返回 5`或`-5`。只有绝对值将被“卖出”操作使用。
Sizer 已经去到了 broker 并请求给定 data 的 佣金信息 ,实际的 现金*水平并提供对作为操作目标的 data*的直接引用
现在来看看 FixedSize sizer的定义:
import backtrader as bt
class FixedSize(bt.Sizer):
    params = (('stake', 1),)
    def _getsizing(self, comminfo, cash, data, isbuy):
        return self.params.stake
这很简单,因为 Sizer 没有进行计算,参数只是存在其中。但是这种机制应该允许构建复杂的 尺寸*(也被称为 定位*)系统来管理进入/退出市场时的风险。
另一个例子: 一个位置颠倒者 :
```python class FixedReverser(bt.FixedSize):
- def _getsizing(self, comminfo, cash, data, isbuy):
position = self.broker.getposition(data) size = self.p.stake * (1 + (position.size != 0)) return size
这个示例是在现有的 FixedSize 基础上构建的,以继承 params ,并且重写了 _getsizing 方法:
- 通过 - broker属性获取 data 的- position
- 使用 - position.size来决定是否增加固定的股份
- 返回计算出的值 
这样一来,决定是否反向或开仓的负担就从 策略*移交给了 Sizer ,*Sizer 处于控制之中,可以随时替换而不影响逻辑。
实际的 Sizer 适用性
**********************不考虑复杂的大小算法,可以使用两种不同的大小调整器来将策略从”仅做多”调整为”做多做空”。只需在”cerebro”执行中更改”Sizer”,策略的行为就会改变。一个非常简单的 close 交叉 SMA 算法:
```python class CloseSMA(bt.Strategy):
params = ((‘period’, 15),)
- def __init__(self):
sma = bt.indicators.SMA(self.data, period=self.p.period) self.crossover = bt.indicators.CrossOver(self.data, sma)
- def next(self):
- if self.crossover > 0:
self.buy()
- elif self.crossover < 0:
self.sell()
注意,策略并不考虑当前的 持仓*(通过查看 ``self.position`` )来决定是否需要实际执行 买入 或*卖出 。只考虑 CrossOver 的*信号*。大小调整器将负责所有事情。
这个大小调整器将在只有当已经存在一个仓位时,卖出时返回一个*非零*的大小:
```python class LongOnly(bt.Sizer):
params = ((‘stake’, 1),)
- def _getsizing(self, comminfo, cash, data, isbuy):
- if isbuy:
return self.p.stake
# 卖出情况 position = self.broker.getposition(data) if not position.size:
return 0 # 如果没有仓位则不卖出
`
```python
return self.p.stake
`
将所有内容放在一起(假设已经导入了 backtrader 并且已经向系统添加了一个 data ):
...
cerebro.addstrategy(CloseSMA)
cerebro.addsizer(LongOnly)
...
cerebro.run()
...
图表(来自于源代码中的示例,用于测试此代码)。
 
                只需将 Sizer 更改为上面显示的 FixedReverser 即可实现 Long-Short 版本:
...
cerebro.addstrategy(CloseSMA)
cerebro.addsizer(FixedReverser)
...
cerebro.run()
...
输出的图表。
 
                注意这些区别: - *交易*次数已经增加了
现金水平永远不会回到原本的 价值,因为策略总是处于* 市场*中
这两种方法都是负面的,但这只是一个例子。
bt.Sizer 参考
- class backtrader.Sizer(*args, **kwargs)#
- This is the base class for Sizers. Any sizer should subclass this and override the - _getsizingmethod- Member Attribs: - strategy: will be set by the strategy in which the sizer is working- Gives access to the entire api of the strategy, for example if the actual data position would be needed in - _getsizing:- position = self.strategy.getposition(data) 
- broker: will be set by the strategy in which the sizer is working- Gives access to information some complex sizers may need like portfolio value, .. 
 - _getsizing(comminfo, cash, data, isbuy)#
- This method has to be overriden by subclasses of Sizer to provide the sizing functionality - Params:
- comminfo: The CommissionInfo instance that contains information about the commission for the data and allows calculation of position value, operation cost, commision for the operation
- cash: current available cash in the broker
- data: target of the operation
- isbuy: will be- Truefor buy operations and- Falsefor sell operations
 
 - The method has to return the actual size (an int) to be executed. If - 0is returned nothing will be executed.- The absolute value of the returned value will be used 
 
