def buy(self, data=None,
size=None, price=None, plimit=None,
exectype=None, valid=None, tradeid=0, **kwargs):
注意,如果调用者未指定,则size的默认值为None。Sizers发挥重要作用的地方:
意味着Strategies有一个Sizer:后台机制会向Strategy添加默认的Sizer,如果用户没有添加,则会添加默认的Sizer。strategy的默认Sizer是SizerFix。定义的初始化:
class SizerFix(SizerBase):
params = (('stake', 1),)
默认的Sizer只是使用1单位的stake(无论是股票、合约等)买入/卖出。
可以通过2种不同的方法向Cerebro添加Sizers:
cerebro = bt.Cerebro()
cerebro.addsizer(bt.sizers.SizerFix, stake=20) # default sizer for strategies
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)
在这个例子中:
系统中添加了一个默认的Sizer,适用于所有没有指定具体Sizer的策略
对于MyStrategy,在得到增加策略的idx后,可以添加一个特定的sizer(更改stake参数)
第二个策略MyOtherStrategy被添加到系统中。没有为它指定特定的Sizer 。
说明:
注意:
default并不意味着策略共享单个Sizer实例。每个strategy都会收到不同的default sizer实例
要共享单个实例,应该共享的sizer应该是单例类。如何定义一个超出了backtrader的范围 。
Strategy类提供了API:setsizer和getsizer(以及sizer属性)来管理Sizer。定义:
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。
Subclass from backtrader.Sizer
This gives you access to self.strategy and self.broker although it shouldn’t be needed in most cases. Things that can be accessed with the broker
data’s position with self.strategy.getposition(data)
complete portfolio value through self.broker.getvalue()
Notice this could of course also be done with self.strategy.broker.getvalue()
Some of the other things are already below as arguments
1.从backtrader.Sizer子类中继承
可以访问self.strategy和self.broker,尽管在大多数情况下不需要。可以使用broker访问
注意,也可以使用self.strategy.broker.getvalue()完成
This method returns the desired size for the buy/sell operation
The returned sign is not relevant, ie: if the operation is a sell operation (isbuy will be False) the method may return 5 or -5. Only the absolute value will be used by the sell operation.
2.重写方法_getsizing(self, comminfo, cash, data, isbuy)
此方法返回buy/sell操作的所需size
返回的操作信号不相关,比如:如果操作是卖出操作(isbuy将为False),则该方法可以返回5或-5。只有卖出使用绝对值。
Sizer已经传给broker并请求给定数据的佣金信息、实际的现金水平,并提供对数据的直接引用,操作的目的。
FixedSizesizer的定义:
import backtrader as bt
class FixedSize(bt.Sizer):
params = (('stake', 1),)
def _getsizing(self, comminfo, cash, data, isbuy):
return self.params.stake
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
size = self.p.stake * (1 + (position.size != 0))
基于现有的FixedSize来继承params并覆盖_getsizing:
将减轻策略的负担,即决定是否必须撤销或开立头寸,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:
不考虑复杂的sizer算法,两种不同的sizer可用于将策略从仅做多转变为做多-做空。只需改变cerebro执行中的Sizer,策略就会改变行为。
下面是非常简单的收盘价交叉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.
注意,策略不考虑当前仓位(通过self.position查看)来决定是否实际买入或卖出。只有考虑来自交叉的信号。sizer将负责一切。
如果仓位已开,此sizer将只负责在卖出时返回非零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
将所有合并(并假设backtrader已经导入并且数据已加载到系统中):
...
cerebro.addstrategy(CloseSMA)
cerebro.addsizer(LongOnly)
...
cerebro.run()
...
python ./sizertest.py --plot --longonly
图示:
...
cerebro.addstrategy(CloseSMA)
cerebro.addsizer(FixedReverser)
...
cerebro.run()
...
执行
python ./sizertest.py --plot
不同之处:
无论如何两种方法都是负面的,不成功的,只是一个例子而已。
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
#
# Copyright (C) 2015-2023 Daniel Rodriguez
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
###############################################################################
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
import random
import backtrader as bt
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()
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
class FixedReverser(bt.Sizer):
params = (('stake', 1),)
def _getsizing(self, comminfo, cash, data, isbuy):
position = self.strategy.getposition(data)
size = self.p.stake * (1 + (position.size != 0))
return size
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
cerebro.broker.set_cash(args.cash)
dkwargs = dict()
if args.fromdate:
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
dkwargs['fromdate'] = fromdate
if args.todate:
todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
dkwargs['todate'] = todate
data0 = bt.feeds.YahooFinanceCSVData(dataname=args.data0, **dkwargs)
cerebro.adddata(data0, name='Data0')
cerebro.addstrategy(CloseSMA, period=args.period)
if args.longonly:
cerebro.addsizer(LongOnly, stake=args.stake)
else:
cerebro.addsizer(bt.sizers.FixedReverser, stake=args.stake)
cerebro.run()
if args.plot:
pkwargs = dict()
if args.plot is not True: # evals to True but is not True
pkwargs = eval('dict(' + args.plot + ')') # args were passed
cerebro.plot(**pkwargs)
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Sample for sizer')
parser.add_argument('--data0', required=False,
default='../../datas/yhoo-1996-2015.txt',
help='Data to be read in')
parser.add_argument('--fromdate', required=False,
default='2005-01-01',
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--todate', required=False,
default='2006-12-31',
help='Ending date in YYYY-MM-DD format')
parser.add_argument('--cash', required=False, action='store',
type=float, default=50000,
help=('Cash to start with'))
parser.add_argument('--longonly', required=False, action='store_true',
help=('Use the LongOnly sizer'))
parser.add_argument('--stake', required=False, action='store',
type=int, default=1,
help=('Stake to pass to the sizers'))
parser.add_argument('--period', required=False, action='store',
type=int, default=15,
help=('Period for the Simple Moving Average'))
# Plot options
parser.add_argument('--plot', '-p', nargs='?', required=False,
metavar='kwargs', const=True,
help=('Plot the read data applying any kwargs passed\n'
'\n'
'For example:\n'
'\n'
' --plot style="candle" (to plot candles)\n'))
if pargs is not None:
return parser.parse_args(pargs)
return parser.parse_args()
if __name__ == '__main__':
runstrat()
class backtrader.Sizer()
Sizers的基类。任何sizer都应该对此子类化并覆盖_getsizing方法
成员属性:
position = self.strategy.getposition(data)
提供一些复杂Sizer可能需要的信息,如投资组合价值
_getsizing(comminfo, cash, data, isbuy)
方法必须由Sizer的子类覆盖以提供调整功能
参数:
comminfo: CommissionInfo 实例包含有关数据佣金的信息,并允许计算头寸价值、运营成本和运营佣金
cash: broker中当前可用现金
data: 数据源对象
isbuy: True 是 buy, False 是 sell
方法必须返回要执行的实际sizer(int)。如果返回0,将不执行任何操作。
将使用返回值的绝对值 。
class backtrader.sizers.FixedSize()
sizer只是为任何操作返回一个固定的sizer。通过指定份额参数,根据系统希望用于交易的份额数量来控制size。
参数:
stake
(default: 1
)
tranches
(default: 1
)
class backtrader.sizers.FixedReverser()
sizer返回需要的固定sizer 来反转开仓位置,或开仓的固定大小
stake
(default: 1
)class backtrader.sizers.PercentSizer()
sizer返回可用现金的百分比
参数:
percents
(default: 20
)class backtrader.sizers.AllInSizer()
sizer返回经纪人的所有可用现金
参数:
percents
(default: 100
)class backtrader.sizers.PercentSizerInt()
This sizer return percents of available cash in form of size truncated to an int
sizer取整数的int,返回可用现金的百分比 。
参数:
percents
(default: 20
)class backtrader.sizers.AllInSizerInt()
This sizer return all available cash of broker with the size truncated to an int
sizer返回取整数broker的所有可用现金 。
参数:
percents
(default: 100
)