backtrader.Strategy策略类的详细解析 – backtrader中文教程
Cerebro 实例是backtrader的心脏和大脑。 策略对于用户来说是相同的。
策略在方法中表达的生命周期:
Tips:可以通过从模块中引发 异常StrategySkipError
来中断策略backtrader.errors
- 概念:
__init__
这显然是在实例化期间调用的:
indicators
将在此处创建和其他需要的属性。例子:def __init__(self): self.sma = btind.SimpleMovingAverage(period=15)
- 出生:
start
世界 (
cerebro
) 告诉策略是时候开始踢了。存在默认的空方法。 - 童年:
prenext
indicators
在构想期间宣布将限制策略需要多长时间才能成熟:这称为minimum period
. 上面__init__
创建了一个 带有period=15
.只要系统看到不到
15
吧,prenext
就会被调用(默认实现是no-op) - 成年:
next
一旦系统看到
15
柱并且SimpleMovingAverage
有足够大的缓冲区开始产生值,该策略就足够成熟以真正执行。有一种
nextstart
方法只调用一次,用于标记从prenext
to的切换next
。的默认实现nextstart
是简单地调用next
- 再生产:
None
好吧,策略并没有真正复制。但从某种意义上说,它们确实如此,因为如果优化(使用不同的参数),系统将多次实例化它们
- 死亡:
stop
系统告诉策略该重置并整理好东西的时间已经到来。存在默认的空方法。
在大多数情况下,对于常规使用模式,这将如下所示:
class MyStrategy(bt.Strategy): def __init__(self): self.sma = btind.SimpleMovingAverage(period=15) def next(self): if self.sma > self.data.close: # Do something pass elif self.sma < self.data.close: # Do something else pass
在这个片段中:
- 在
__init__
一个属性被分配一个指示符期间 - 默认的空
start
方法没有被覆盖 prenext
并且nexstart
不被覆盖- 在
next
将指标的值与收盘价进行比较做某事 - 默认的空
stop
方法没有被覆盖
策略,就像现实世界中的交易者一样,会在事件发生时得到通知。实际上next
在回测过程中每个周期一次。该战略将:
- 通过
notify_order(order)
订单中的任何状态更改通知 - 通过
notify_trade(trade)
任何开仓/更新/平仓交易获得通知 - 通过
notify_cashvalue(cash, value)
经纪人的当前现金和投资组合获得通知 - 通过
notify_fund(cash, value, fundvalue, shares)
经纪人的当前现金和投资组合以及基金价值和股票的交易获得通知 - 事件(特定于实现)通过
notify_store(msg, *args, **kwargs)
有关商店通知的说明,请参阅 Cerebro。即使它们也已交付给
cerebro
实例(使用覆盖notify_store
方法或通过 回调) ,它们也会交付给策略
并且策略也像交易者一样有机会在市场操作过程中next
尝试以获取利润的方法
buy
做多或减少/关闭空头头寸的方法sell
做空或减少/关闭多头头寸的方法close
明显平仓的方法cancel
取消尚未执行的订单的方法
如何购买/出售/关闭
和方法Buy
生成Sell
订单。当被调用时,它们返回一个 Order
(或子类)实例,可以用作参考。此订单具有唯一ref
标识符,可用于比较
Tips:特定代理实现的子类Order
可以携带代理提供的额外唯一标识符。
要创建订单,请使用以下参数:
data
(默认None
)必须为哪些数据创建订单。如果
None
那么系统中的第一个数据,self.datas[0] or self.data0
(又名self.data
)将被使用size
(默认None
)用于订单的数据单位的大小(正)。
如果通过检索
None
的实例将用于确定大小。sizer
getsizer
price
(默认None
)使用价格(如果实际格式不符合最小报价大小要求,实时经纪人可能会对实际格式施加限制)
None
对Market
和Close
订单有效(市场决定价格)For
Limit
,Stop
andStopLimit
orders 这个值决定了触发点(在触发的情况下Limit
明显是在哪个价格下单应该匹配)plimit
(默认None
)仅适用于
StopLimit
订单。这是设置隐含限价单的价格,一旦触发止损price
(已使用)exectype
(默认None
)可能的值:
Order.Market
或None
。市价单将以下一个可用价格执行。在回测中,它将是下一个柱的开盘价Order.Limit
. 只能在给定price
或更好的条件下执行的订单Order.Stop
. 像订单一样触发price
和执行的Order.Market
订单Order.StopLimit
. 触发price
并作为隐式限价订单执行的订单,价格为pricelimit
valid
(默认None
)可能的值:
None
:这会生成一个不会过期的订单(又名 Good til cancel)并保留在市场中直到匹配或取消。实际上,经纪人倾向于施加时间限制,但这通常在时间上很遥远,以至于认为它不会过期datetime.datetime
或datetime.date
实例:日期将用于生成在给定日期时间之前有效的订单(也就是好日期)Order.DAY
或0
或timedelta()
:将生成在会话结束前有效的一天(又名日订单)numeric value
matplotlib
:这被假定为与编码 中的日期时间相对应的值(由 使用的那个backtrader
),并将用于生成在该时间之前有效的订单(良好的直到日期)
tradeid
(默认0
)这是一个内部值,用于
backtrader
跟踪同一资产的重叠交易。当通知订单状态的变化时,这tradeid
将被发送回策略。**kwargs
: 额外的代理实现可能支持额外的参数。backtrader
将kwargs传递给创建的订单对象示例:如果直接支持的 4 种订单执行类型
backtrader
不够用,例如 Interactive Brokers,可以将以下内容作为kwargs传递:
orderType='LIT', lmtPrice=10.0, auxPrice=9.8
- 这将覆盖由创建的设置
backtrader
并生成一个触及价格为 9.8 和限价为 10.0的LIMIT IF TOUCHED
订单。
信息位:
- 策略的长度始终等于主数据的长度 (
datas[0]
),当然可以通过len(self)
next
如果正在重播数据或正在传递实时提要并且同一时间点(长度)的新滴答声到达,则可以在不改变长度的情况下调用
会员属性:
env
:这个策略所在的大脑实体datas
: 已传递给 cerebro 的数据馈送数组data/data0
是 datas[0] 的别名dataX
是 datas[X] 的别名
数据馈送也可以按名称访问(请参阅参考资料),如果已分配给它
dnames
:按名称访问数据馈送的替代方法(带有[name]
或带有.name
符号)例如,如果重新采样这样的数据:
... data0 = bt.feeds.YahooFinanceData(datname='YHOO', fromdate=..., name='days') cerebro.adddata(data0) cerebro.resampledata(data0, timeframe=bt.TimeFrame.Weeks, name='weeks') ...
稍后在策略中,可以像这样在每个指标上创建指标:
... smadays = bt.ind.SMA(self.dnames.days, period=30) # or self.dnames['days'] smaweeks = bt.ind.SMA(self.dnames.weeks, period=10) # or self.dnames['weeks'] ...
broker
: 引用与该策略相关的经纪人(来自 cerebro)stats
: list/named tuple-like sequence 保存 cerebro 为此策略创建的观察者analyzers
: list/named tuple-like 序列,包含 cerebro 为此策略创建的分析器position
: 实际上是一个属性,它给出了data0
.可以使用检索所有位置的方法(请参阅参考资料)
成员属性(用于统计/观察员/分析员):
- _orderspending:
next被调用
之前会通知策略的订单列表 - _tradespending:
next被调用
之前将被通知到策略的交易列表 _orders
: 已经通知的订单列表。一个订单可以在列表中多次出现,具有不同的状态和不同的执行位。该列表是用来保存历史的。_trades
: 已经通知的订单列表。就像订单一样,一笔交易可以在列表中多次出现。
Tips:请记住prenext
,nextstart
和next
可以在同一时间点多次调用(当使用每日时间框架时,更新每日柱的价格的刻度)
参考:策略
class backtrader.Strategy(*args, **kwargs)
要为用户定义的策略子类化的基类。
next()
当满足所有数据/指标的最短周期时,将为所有剩余的数据点调用此方法。
nextstart()
此方法将被调用一次,恰好在所有数据/指标的最小周期都已满足时。默认行为是调用 next
prenext()
此方法将在满足策略开始执行的所有数据/指标的最短周期之前调用
start()
在即将开始回测之前调用。
stop()
在回测即将停止之前调用
notify_order(order)
每当有一个变化时收到一个订单
notify_trade(trade)
每当有变化时接收交易
notify_cashvalue(cash, value)
接收当前基金价值,策略经纪商的价值状态
notify_fund(cash, value, fundvalue, shares)
收到当前现金、价值、基金价值和基金份额
notify_store(msg, *args, **kwargs)
收到来自商店提供商的通知
buy(data=None, size=None, price=None, plimit=None, exectype=None, valid=None, tradeid=0, oco=None, trailamount=None, trailpercent=None, parent=None, transmit=True, **kwargs)
创建买入(多头)订单并将其发送给经纪人
data
(默认None
)必须为哪些数据创建订单。如果
None
那么系统中的第一个数据,self.datas[0] or self.data0
(又名self.data
)将被使用size
(默认None
)用于订单的数据单位的大小(正)。
如果通过检索
None
的实例将用于确定大小。sizer
getsizer
price
(默认None
)使用价格(如果实际格式不符合最小报价大小要求,实时经纪人可能会对实际格式施加限制)
None
对Market
和Close
订单有效(市场决定价格)For
Limit
,Stop
andStopLimit
orders 这个值决定了触发点(在触发的情况下Limit
明显是在哪个价格下单应该匹配)plimit
(默认None
)仅适用于
StopLimit
订单。这是设置隐含限价单的价格,一旦触发止损price
(已使用)trailamount
(默认None
)如果订单类型是 StopTrail 或 StopTrailLimit,这是一个绝对数量,它决定了与价格的距离(低于卖出订单,高于买入订单)以保持追踪止损
trailpercent
(默认None
)如果订单类型是 StopTrail 或 StopTrailLimit,这是一个百分比量,它决定了与价格的距离(低于卖出订单,高于买入订单)以保持追踪止损(如果
trailamount
也指定它将被使用)exectype
(默认None
)可能的值:
Order.Market
或None
。市价单将以下一个可用价格执行。在回测中,它将是下一个柱的开盘价Order.Limit
. 只能在给定price
或更好的条件下执行的订单Order.Stop
. 像订单一样触发price
和执行的Order.Market
订单Order.StopLimit
. 触发price
并作为隐式限价订单执行的订单,价格为pricelimit
Order.Close
. 只能以时段收盘价执行的订单(通常在收盘竞价期间)Order.StopTrail
.price
在减号trailamount
(或)触发的订单,trailpercent
如果价格远离止损,则更新订单Order.StopTrailLimit
.price
在减号trailamount
(或)触发的订单,trailpercent
如果价格远离止损,则更新订单
valid
(默认None
)可能的值:
None
:这会生成一个不会过期的订单(又名 Good until cancel)并保留在市场中直到匹配或取消。实际上,经纪人倾向于施加时间限制,但这通常在时间上很遥远,以至于认为它不会过期datetime.datetime
或datetime.date
实例:日期将用于生成在给定日期时间之前有效的订单(又名有效期至日期)Order.DAY
或0
或timedelta()
:将生成在会话结束前有效的一天(又名日订单)numeric value
matplotlib
:这被假定为与编码 中的日期时间相对应的值(由 使用的那个backtrader
),并将用于生成在该时间之前有效的订单(直到日期有效)
tradeid
(默认0
)这是一个内部值,用于
backtrader
跟踪同一资产的重叠交易。当通知订单状态的变化时,这tradeid
将被发送回策略。oco
(默认None
)另一个
order
例子。此订单将成为 OCO(订单取消其他)组的一部分。执行其中一个订单,立即取消同一组中的所有其他订单parent
(默认None
)控制一组订单之间的关系,例如由高端限价卖出和低端止损卖出包围的买入。高位/低位订单保持无效,直到父订单被执行(它们变为有效)或被取消/到期(子订单也被取消)括号订单具有相同的大小
transmit
(默认True
)指示是否必须传输订单,即:不仅放置在经纪人中,而且还发出。这意味着例如控制括号顺序,其中禁用父级和第一组子级的传输并为最后一个子级激活它,这会触发所有括号顺序的完全放置。
**kwargs
: 额外的代理实现可能支持额外的参数。backtrader
将kwargs传递给创建的订单对象示例:如果直接支持的 4 种订单执行类型
backtrader
不够用,例如 Interactive Brokers,可以将以下内容作为kwargs传递:orderType='LIT', lmtPrice=10.0, auxPrice=9.8
这将覆盖由创建的设置
backtrader
并生成一个触及价格为 9.8 和限价为 10.0的LIMIT IF TOUCHED
订单。
- 退货
- 提交的订单
sell(data=None, size=None, price=None, plimit=None, exectype=None, valid=None, tradeid=0, oco=None, trailamount=None, trailpercent=None, parent=None, transmit=True, **kwargs)
创建卖出(空头)订单并将其发送给经纪人
buy
有关参数的说明,请参阅文档
返回:提交的订单
close(data=None, size=None, **kwargs)
多头/空头头寸的平仓
buy
有关参数的说明,请参阅文档
size
:如果None
调用者未提供(默认值:),则从现有位置自动计算
返回:提交的订单
cancel(order)
取消经纪商的订单
buy_bracket(data=None, size=None, price=None, plimit=None, exectype=2, valid=None, tradeid=0, trailamount=None, trailpercent=None, oargs={}, stopprice=None, stopexec=3 , stopargs={}, limitprice=None, limitexec=2, limitargs={}, **kwargs)
创建一个括号定单组(低端 – 买入定单 – 高端)。默认行为如下:
- 发出带有执行的买单
Limit
- 发出低边括号卖单并执行
Stop
- 发出带有执行的高边括号卖单
Limit
。
请参阅下面的不同参数
data
(默认None
)必须为哪些数据创建订单。如果
None
那么系统中的第一个数据,self.datas[0] or self.data0
(又名self.data
)将被使用size
(默认None
)用于订单的数据单位的大小(正)。
如果通过检索
None
的实例将用于确定大小。sizer
getsizer
笔记
相同尺寸适用于支架的所有 3 个订单
price
(默认None
)使用价格(如果实际格式不符合最小报价大小要求,实时经纪人可能会对实际格式施加限制)
None
对Market
和Close
订单有效(市场决定价格)For
Limit
,Stop
andStopLimit
orders 这个值决定了触发点(在触发的情况下Limit
明显是在哪个价格下单应该匹配)plimit
(默认None
)仅适用于
StopLimit
订单。这是设置隐含限价单的价格,一旦触发止损price
(已使用)trailamount
(默认None
)如果订单类型是 StopTrail 或 StopTrailLimit,这是一个绝对数量,它决定了与价格的距离(低于卖出订单,高于买入订单)以保持追踪止损
trailpercent
(默认None
)如果订单类型是 StopTrail 或 StopTrailLimit,这是一个百分比量,它决定了与价格的距离(低于卖出订单,高于买入订单)以保持追踪止损(如果
trailamount
也指定它将被使用)exectype
(默认bt.Order.Limit
)可能的值:(请参阅该方法的文档
buy
valid
(默认None
)可能的值:(请参阅该方法的文档
buy
tradeid
(默认0
)可能的值:(请参阅该方法的文档
buy
oargs
(默认{}
)dict
要传递给主侧顺序的特定关键字参数(在 a 中)。默认的参数**kwargs
将在此之上应用。**kwargs
: 额外的代理实现可能支持额外的参数。backtrader
将kwargs传递给创建的订单对象可能的值:(请参阅该方法的文档
buy
笔记
这
kwargs
将应用于括号的 3 个订单。请参阅下文,了解低端和高端订单的特定关键字参数stopprice
(默认None
)低位止损单的具体价格
stopexec
(默认bt.Order.Stop
)低边订单的特定执行类型
stopargs
(默认{}
)dict
要传递给低端顺序的特定关键字参数(在 a 中)。默认的参数**kwargs
将在此之上应用。limitprice
(默认None
)高位止损单的具体价格
stopexec
(默认bt.Order.Limit
)高端订单的特定执行类型
limitargs
(默认{}
)dict
要传递给高端订单的特定关键字参数(在 a 中)。默认的参数**kwargs
将在此之上应用。
可以使用以下方法抑制高/低侧订单:
limitexec=None
压制高端stopexec=None
抑制低端- 退货
- 包含 3 个订单的列表 [订单、止损边、限价边]
- 如果高/低订单已被抑制,则返回值仍将包含 3 个订单,但那些被抑制的订单的值为
None
sell_bracket(data=None, size=None, price=None, plimit=None, exectype=2, valid=None, tradeid=0, trailamount=None, trailpercent=None, oargs={}, stopprice=None, stopexec=3 , stopargs={}, limitprice=None, limitexec=2, limitargs={}, **kwargs)
创建一个括号定单组(低端 – 买入定单 – 高端)。默认行为如下:
- 发出带执行的卖单
Limit
- 发出高边括号买单并执行
Stop
- 发出带有执行的低边括号买单
Limit
。
bracket_buy
参数含义见
可以使用以下方法抑制高/低侧订单:
stopexec=None
压制高端limitexec=None
抑制低端- 退货
- 包含 3 个订单的列表 [订单、止损边、限价边]
- 如果高/低订单已被抑制,则返回值仍将包含 3 个订单,但那些被抑制的订单的值为
None
order_target_size(data=None, target=0, **kwargs)
下订单以重新平衡头寸,使其最终大小为target
以当前position
大小为起点实现target
- 如果
target
>pos.size
-> 购买target - pos.size
- 如果
target
<pos.size
-> 卖出pos.size - target
它返回:
- 生成的订单
或者
None
如果没有发出命令 (target == position.size
)
order_target_value(data=None, target=0.0, price=None, **kwargs)
下订单以重新平衡头寸以获得最终价值 target
以电流value
为起点实现target
- 如果没有
target
,则关闭数据 - 如果
target
>value
则购买数据 - 如果
target
<value
则出售数据
它返回:
- 生成的订单
或者
None
如果没有下达命令
order_target_percent(data=None, target=0.0, **kwargs)
下订单以重新平衡头寸以获得 target
当前投资组合百分比的最终值value
target
以十进制表示:0.05
->5%
它用于order_target_value
执行订单。
例子
target=0.05
和投资组合价值是100
value
要达到的是0.05 * 100 = 5
5
作为target
值传递给order_target_value
以电流value
为起点实现target
position.size
用于确定位置是否为long
/ short
- 如果
target
>value
- 买如果
pos.size >= 0
(增加多头头寸) - 卖出如果
pos.size < 0
(增加空头头寸)
- 买如果
- 如果
target
<value
- 卖出如果
pos.size >= 0
(减少多头头寸) - 买如果
pos.size < 0
(减少空头头寸)
- 卖出如果
它返回:
- 生成的订单
或者
None
如果没有发出命令 (target == position.size
)
getsizer()
如果使用自动 statke 计算,则返回正在使用的 sizer
也可作为sizer
setsizer(sizer)
替换默认(固定赌注)sizer
getsizing(data=None, isbuy=True)
返回由 sizer 实例针对当前情况计算的权益
getposition(data=None, broker=None)
返回给定代理中给定数据的当前位置。
如果两者都是None,将使用主要数据和默认代理
position
也有房源
getpositionbyname(name=None, broker=None)
返回给定代理中给定名称的当前位置。
如果两者都是None,将使用主要数据和默认代理
属性 positionbyname 也可用
getpositionsbyname(broker=None)
直接从代理返回当前的按名称位置
如果给定broker
为无,将使用默认代理
positionsbyname
也有房源
getdatanames()
返回现有数据名称的列表
getdatabyname(name)
使用环境 (cerebro) 按名称返回给定数据
add_timer(when, offset=datetime.timedelta(0), repeat=datetime.timedelta(0), weekdays=[], weekcarry=False, monthdays=[], monthcarry=True, allow=None, tzdata=None, cheat=False, *args, **kwargs)
Tips:可以在__init__
或期间调用start
安排一个计时器来调用指定的回调或 notify_timer
一个或多个策略。
- 参数
当( – ) – 可以
datetime.time
实例(见下文tzdata
)bt.timer.SESSION_START
引用会话开始bt.timer.SESSION_END
引用会话结束offset
这必须是一个datetime.timedelta
实例
用于偏移值
when
。SESSION_START
它与和结合使用具有有意义的用途,以指示在会话开始后SESSION_END
调用计时器之类的事情。15 minutes
repeat
这必须是一个datetime.timedelta
实例指示在第一次通话后,是否将在同一会话中以预定的
repeat
增量安排进一步的通话一旦计时器超过会话结束,它将重置为原始值
when
weekdays
: 一个排序的迭代器,带有整数,指示在哪些天(iso 代码,星期一是 1,星期日是 7)可以实际调用计时器如果未指定,计时器将在所有日子都处于活动状态
weekcarry
(默认值:False
)。如果True
没有看到工作日(例如:交易假期),计时器将在第二天执行(即使在新的一周)monthdays
:一个排序的迭代器,带有整数,指示必须在每月的哪几天执行计时器。例如总是在每月的第15天如果未指定,计时器将在所有日子都处于活动状态
monthcarry
(默认值:True
)。如果没有看到这一天(周末、交易假日),则计时器将在下一个可用日期执行。allow
(默认值:None
)。一个回调,它接收一个 datetime.date` 实例,True
如果计时器允许该日期,则返回,否则返回False
tzdata
可以是None
(默认)、pytz
实例或data feed
实例。None
:when
以面值解释(这意味着将其视为 UTC 处理,即使它不是)pytz
实例:when
将被解释为在时区实例指定的本地时间中指定。data feed
实例:将被解释为在数据馈送实例when
的参数指定的本地时间中指定。tz
笔记
如果
when
isSESSION_START
或SESSION_END
并且tzdata
isNone
,系统中的第一个数据 馈送(akaself.data0
)将用作查找会话时间的参考。cheat
(默认False
)如果True
在经纪人有机会评估订单之前调用计时器。这打开了基于开盘价发出订单的机会,例如在会话开始之前*args
: 任何额外的参数都将传递给notify_timer
**kwargs
: 任何额外的 kwargs 将被传递给notify_timer
返回值:
- 创建的计时器
notify_timer(timer, when, *args, **kwargs)
收到定时器通知,timer
返回的定时器在哪里add_timer
,when
是调用时间。args
并且kwargs
是传递给add_timer
实际when
时间可以晚一些,但系统可能之前无法调用定时器。该值是定时器值,不是系统时间。