Sizers
- Smart Staking
A Strategy offers methods to trade, namely: buy, sell and close. Let’s see the signature of buy:
策略提供了交易的方法,即:買入、賣出和成交。讓我們看看buy的簽名:
def buy(self, data=None,
size=None, price=None, plimit=None,
exectype=None, valid=None, tradeid=0, **kwargs):
Notice that size has a default value of None if the caller does not specify it. This is where Sizers play an important role:
請注意,如果調用方未指定大小,則size的默認值為None。這就是Sizers發揮重要作用的地方:
size=Nonerequests that the Strategy asks its Sizer for the actual stake- size=None請求策略向其Sizer請求實際的股份
This obviously implies that Strategies have a Sizer: Yes, indeed!. The background machinery adds a default sizer to a Strategy if the user has not added one. The default Sizer added to a strategy is SizerFix. The initial lines of the definition:
這顯然意味着策略里面有Sizer:是的,確實如此!。如果用戶沒有添加,則后台機制將默認的大小寫器添加到策略中。添加到策略中的默認Sizer是SizerFix。定義的初始行:
class SizerFix(SizerBase):
params = (('stake', 1),)
It is easy to guess that this Sizer simply buys/sells using a stake of 1 units (be it shares, contracts, …)
很容易猜測,這個規模的Sizer只是用1個單位的股份進行買賣(無論是股票、合同等)
Using Sizers
From Cerebro
Sizers can be added via Cerebro with 2 different methods:
Sizers有兩個不同的方法通過Cerebro添加
addsizer(sizercls, *args, **kwargs)
Adds a Sizer that will be applied to any strategy added to cerebro. This is, so to to say, the default Sizer. Example:
添加一個Sizer,它將應用於添加到大腦的任何策略。可以說,這是默認的Sizer。例子:
cerebro = bt.Cerebro() cerebro.addsizer(bt.sizers.SizerFix, stake=20) # default sizer for strategies
addsizer_byidx(idx, sizercls, *args, **kwargs)
The Sizer will only be added to the Strategy referenced by idx
Sizer只能通過策略返回的參考idx被添加
This idx can be gotten as return value from addstrategy. As in:
這個idx可以作為addstrategy的返回值獲得。如:
cerebro = bt.Cerebro() cerebro.addsizer(bt.sizers.SizerFix, stake=20) # default sizer for strategies idx = cerebro.addstrategy(MyStrategy, myparam=myvalue) cerebro.addsizer_byidx(idx, bt.sizers.SizerFix, stake=5) cerebro.addstrategy(MyOtherStrategy)
In this example:
-
A default Sizer has been added to the system. This one applies to all strategies which don’t have a specific Sizer assigned
- 系統中已添加了一個默認的Sizer。這一條適用於所有沒有指定特定尺寸的策略。
-
For MyStrategy and after collecting its insertion idx, a specific sizer (changing the
stakeparam) is added - 對於MyStrategy,在收集其插入idx之后,將添加一個特定的sizer(更改stake param)
-
A 2nd strategy, MyOtherStrategy, is added to the system. No specific Sizer is added for it
- 第二個策略,MyOtherStrategy,被添加到系統中。沒有為它添加特定的Sizer
-
This means that:
- 這意味着
-
-
MyStrategy will finally have an internal specific Sizer
- MyStrategy最終會有一個內部特定的Sizer
-
MyOtherStrategy will get the default sizer
- MyOtherStrategy將獲得默認Sizer
-
Note
default doesn’t mean that that the strategies share a single Sizer instance. Each strategy receives a different instance of the default sizer
默認並不意味着這些策略共享一個Sizer實例。每個策略都會收到一個不同的默認sizer實例
To share a single instance, the sizer to be shared should be a singleton class. How to define one is outside of the scope of backtrader
要共享單個實例,要共享的sizer應該是一個singleton類(單例)。如何定義一個超出了backtrader的范圍
From Strategy
The Strategy class offers an API: setsizer and getsizer (and a property sizer) to manage the Sizer. The signatures:
Strategy類提供了一個API: setzer和getsizer(以及一個屬性sizer)來管理sizer。簽名:
-
def setsizer(self, sizer): it takes an already instantiated Sizer - def setzer(self,sizer):它需要一個已經實例化的sizer
-
def getsizer(self): returns the current Sizer instance - def getsizer(self):返回當前的Sizer實例
-
sizerit is the property which can be directly get/set - sizer它是可以直接獲取/設置的屬性
In this scenario the Sizer can be for example:
在這種情況下,Sizer可以是:
-
Passed to the strategy as a parameter
- 作為參數傳遞給策略
-
Be set during
__init__using the propertysizerorsetsizeras in: - 在初始化期間使用屬性sizer或setsizer進行設置,如下所示:
class MyStrategy(bt.Strategy):
params = (('sizer', None),)
def __init__(self):
if self.p.sizer is not None:
# 通過property進行設置
self.sizer = self.p.sizer
This would for example allow to create a Sizer at the same level as the cerebro calls are happening and pass it as a parameter to all strategies that go in the system, which effectevily allows sharing a Sizer
例如,這將在發生大腦調用的同一時間級別創建一個Sizer,並將其作為參數傳遞給系統中的所有策略,從而有效地允許共享一個Sizer。
Sizer Development
Doing it is easy:
這樣做很容易:
-
Subclass from
backtrader.Sizer - 子類來自於
backtrader.SizerThis gives you access to
self.strategyandself.brokeralthough it shouldn’t be needed in most cases. Things that can be accessed with thebroker - 這樣你就可以訪問
self.strategy以及self.broker雖然在大多數情況下不需要它。這個可以讓你訪問broker-
data’s position with
self.strategy.getposition(data) - 數據的position通過self.strategy.getposition取到(數據)
-
complete portfolio value through
self.broker.getvalue() - 完整的投資價值通過
self.broker.getvalue()Notice this could of course also be done with
self.strategy.broker.getvalue() - 注意這當然也可以用self.strategy.broker.getvalue()
Some of the other things are already below as arguments
-
- 其他一些事情已經作為論據在下面了
-
Override the method
_getsizing(self, comminfo, cash, data, isbuy) - 重寫方法
_getsizing(self, comminfo, cash, data, isbuy)-
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 - comminfo:包含數據佣金信息的CommissionInfo實例,允許計算頭寸值、操作成本、操作佣金
-
cash: current available cash in the broker - cash:當前經紀人可用的現金
-
data: target of the operation - data:操作的目標
-
isbuy: will beTruefor buy operations andFalsefor sell operations - isbuy:對於buy操作為True,對於sell操作為False
This method returns the desired
sizefor the buy/sell operation -
-
此方法返回buy/sell操作所需的大小
The returned sign is not relevant, ie: if the operation is a sell operation (
isbuywill beFalse) the method may return5or-5. Only the absolute value will be used by the sell operation. - 返回的符號與此無關,即:如果操作是sell操作(isbuy將為False),則該方法可能返回5或-5。只有絕對值將被sell操作使用。
-
Sizerhas already gone to thebrokerand requested the commission information for the given data, the actual cash level and provides a direct reference to the data which is the target of the operation - Sizer已經去找經紀人,要求提供給定數據的佣金信息、實際現金水平,並提供直接參考數據,這是操作的目標
Let’s go for the definition of the FixedSize sizer:
讓我們定一個FixedSize
import backtrader as bt
class FixedSize(bt.Sizer):
params = (('stake', 1),)
def _getsizing(self, comminfo, cash, data, isbuy):
return self.params.stake
This is pretty simple in that the Sizer makes no calculations and the parameters are just there.
這很簡單,因為Sizer不進行計算,參數就在那里。
But the mechanism should allow the construction of complex sizing (aka positioning) systems to manage the stakes when entering/exiting the market.
但該機制應允許構建復雜的規模(又名定位)系統,以便在進入/退出市場時管理股權。
Another example: A position rerverser:
另一個例子:位置變換器:
class FixedRerverser(bt.FixedSize):
def _getsizing(self, comminfo, cash, data, isbuy):
position = self.broker.getposition(data)
size = self.p.stake * (1 + (position.size != 0))
return size
This one builds on the existing FixedSize to inherit the params and overrides _getsizing to:
它基於現有的FixedSize來繼承參數,並重寫_getsizing以:
-
Get the
positionof the data via the attributebroker - 通過data的屬性broker來獲取持倉情況
-
Use
position.sizeto decide if to double the fixed stake - 使用
position.size來計算是否需要兩倍的量 -
Return the calculated value
- 返回計算好的值
This would remove the burden from the Strategy to decide if a position has to be reversed or opened, the Sizer is in control and can at any time be replaced without affecting the logic.
這將減輕策略的負擔,以決定是否必須逆轉或打開頭寸,規模大小是在控制之中,可以隨時替換而不影響邏輯。
Practical Sizer Applicability
實際Sizer的適用性
Wihtout considering complex sizing algorithms, two different sizers can be used to turn a strategy from Long-Only to Long-Short. Simply by changing the Sizer in the cerebro execution, the strategy will change behavior. A very simple close crosses SMA algorithm:
在不考慮復雜的大小調整算法的情況下,可以使用兩種不同的大小sizers來將策略從“僅多單”轉換為“多空單”。通過改變執行策略,大腦的行為會改變。一種非常簡單的收盤價超越SMA算法:
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()
Notice how the strategy doesn’t consider the current position (by looking at self.position) to decide whether a buy or sell has to actually be done. Only the signal from the CrossOver is considered. The Sizers will be in charge of everything.
注意策略是不考慮當前倉位(通過查看自我定位)決定到底是買還是賣。只考慮來自交叉口的信號。所有的事都由Sizers負責。
This sizer will take care of only returning a non-zero size when selling if a position is already open:
如果倉位已經打開,則在賣出時,此sizer只負責返回非零大小:
class LongOnly(bt.Sizer):
params = (('stake', 1),)
def _getsizing(self, comminfo, cash, data, isbuy):
if isbuy:
return self.p.stake
# Sell situation,空倉不給賣空
position = self.broker.getposition(data)
if not position.size:
return 0 # do not sell if nothing is open
return self.p.stake
Putting it all together (and assuming backtrader has already been imported and a data has been added to the system):
把它們放在一起(假設backtrader已經導入,並且數據已經添加到系統中):
... cerebro.addstrategy(CloseSMA) cerebro.addsizer(LongOnly) ... cerebro.run() ...
The chart (from the sample included in the sources to test this).
圖表(源代碼中包含的樣本)。

The Long-Short version simply changes the Sizer to be the FixedReverser shown above:
長短版只需將Sizer更改為上面顯示的FixedReverser:
... cerebro.addstrategy(CloseSMA) cerebro.addsizer(FixedReverser) ... cerebro.run() ...
The output chart.

Notice the differences:
注意區別:
-
The number of trades has duplicated
- 交易數量重復了
-
The cash level never goes back to be the value because the strategy is always in the market
- 現金水平永遠不會回到價值,因為策略總是在市場上
Both approaches are anyhow negative, but this is only an example.
這兩種方法都是消極的,但這只是一個例子。
bt.Sizer Reference
class backtrader.Sizer()
This is the base class for Sizers. Any sizer should subclass this and override the _getsizing method
這是sizer的基類。任何sizer都應將其子類化並重寫_getsizing方法
Member Attribs:
成員屬性:
strategy: will be set by the strategy in which the sizer is working
策略:在任意一個sizer的工作狀態都可以設置策略
Gives access to the entire api of the strategy, for example if the actual data position would be needed in_getsizing:
提供對策略的整個api的訪問權限,例如,如果需要實際的數據倉位就可以通過_getsizing方法
position = self.strategy.getposition(data)
-
broker: will be set by the strategy in which the sizer is working - broker:在任意一個sizer的工作狀態都可以設置broker
-
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
此方法必須由Sizer的子類重寫才能提供調整功能
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 `True` for *buy* operations and `False` for *sell* operations
The method has to return the actual size (an int) to be executed. If 0 is returned nothing will be executed.
該方法必須返回要執行的實際大小(int)。如果返回的是0,則不執行任何操作。
The absolute value of the returned value will be used
將使用返回值的絕對值
