大小调整器 - 智能押注#
一个 策略 提供了交易的方法,例如: 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
_getsizing
methodMember Attribs:
strategy
: will be set by the strategy in which the sizer is workingGives 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 workingGives 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 operationcash
: current available cash in the brokerdata
: target of the operationisbuy
: will beTrue
for buy operations andFalse
for sell operations
The method has to return the actual size (an int) to be executed. If
0
is returned nothing will be executed.The absolute value of the returned value will be used