策略
策略
Cerebro
实例是 backtrader
的泵心和控制大脑。对于平台用户来说,Strategy
是相同的。
策略 在方法中表达的生命周期
注意
策略可以通过从模块 backtrader.errors
中引发 StrategySkipError
异常来在出生期间中断
这将避免在回测过程中执行策略。请参阅Exceptions
部分
- 概念:
__init__
显然这是在实例化期间调用的:indicators
将在此处创建以及其他所需的属性。例如:
def __init__(self): self.sma = btind.SimpleMovingAverage(period=15)`
- 出生:
start
世界(cerebro
)告诉策略是时候开始行动了。存在一个默认的空方法。 - 童年期:
prenext
在概念阶段声明的indicators
将对策略需要成熟的时间施加限制:这称为最小周期
。在__init__
中创建了一个带有period=15
的 SimpleMovingAverage。
只要系统看到的条数少于15
条,将调用prenext
(默认实现是空操作) - 成年期:
next
一旦系统看到了15
条数据,并且SimpleMovingAverage
有足够大的缓冲区开始产生值,策略就足够成熟以实际执行。
有一个nextstart
方法,它被调用一次,标记从prenext
到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 以了解store通知的说明。即使它们也已经传递给了一个cerebro
实例(通过覆盖notify_store
方法或通过回调传递),这些通知也将传递给策略
而且策略也像交易员一样在next
方法期间有机会在市场中操作,以尝试获得利润
buy
方法,用于做多或减少/平仓空头头寸sell
方法,用于做空或减少/平仓多头头寸close
方法,显然关闭现有头寸cancel
方法,用于取消尚未执行的订单
如何购买/出售/平仓
Buy
和Sell
方法生成订单。调用时,它们返回一个Order
(或子类)实例,可用作引用。此订单具有唯一的ref
标识符,可用于比较
注意
特定经纪人实现的Order
子类可能携带经纪人提供的其他唯一标识符。
要创建订单,请使用以下参数:
data
(默认值:None
)
必须为其创建订单的数据。如果是None
,那么系统中的第一个数据,self.datas[0] or self.data0
(又名self.data
)将被使用size
(默认值:None
)
要使用的数据单位(正数)的大小,用于订单
如果是None
,则将使用通过getsizer
检索的sizer
实例来确定大小。price
(默认值:None
)
要使用的价格(现实经纪人可能对实际格式施加限制,如果不符合最低跳动大小要求)
对于Market
和Close
订单,None
是有效的(市场确定价格)
对于Limit
、Stop
和StopLimit
订单,此值确定触发点(在Limit
的情况下,触发显然是订单应该匹配的价格)plimit
(默认值:None
)
仅适用于StopLimit
订单。这是触发Limit订单的价格,一旦Stop被触发(使用了price
)exectype
(默认值:None
)可能的值:
Order.Market
或None
。市价单将以下一个可用价格执行。在回测中,它将是下一个柱的开盘价Order.Limit
。只能以给定的price
或更好的价格执行的订单Order.Stop
。当价格达到price
时触发的订单,并像Order.Market
订单一样执行Order.StopLimit
。当价格达到price
时触发的订单,并作为隐式Limit订单以由pricelimit
给出的价格执行
valid
(默认值:None
)可能的值:
None
:这将生成一个不会过期的订单(又称Good til cancel),并保持在市场上直到匹配或取消。实际上,经纪人倾向于强加一个时间限制,但通常是在很远的时间内,可以考虑它不会过期datetime.datetime
或datetime.date
实例:将使用该日期生成订单,有效期直到给定的日期时间(又称截止日期)Order.DAY
或0
或timedelta()
: 生成到 Session End(又名 day 订单)为止的一天有效订单numeric value
: 假设这是对应于matplotlib
编码中的日期时间的值(backtrader
使用的日期时间编码),将用于生成直到该时间有效的订单(good til date)
tradeid
(默认值:0
)
这是backtrader
应用的内部值,用于跟踪同一资产上的重叠交易。当通知订单状态变化时,此tradeid
将发送回 strategy。**kwargs
: 其他经纪人实现可能支持额外的参数。backtrader
将这些 kwargs 传递给创建的订单对象
例如: 如果backtrader
直接支持的 4 种订单执行类型不够用,例如 Interactive Brokers 的情况下可以将以下内容作为 kwargs 传递:
orderType='LIT', lmtPrice=10.0, auxPrice=9.8`
- 这将覆盖
backtrader
创建的设置,并生成一个 touched 价格为 9.8, limit 价格为 10.0 的LIMIT IF TOUCHED
订单。
信息位:
- 策略具有与主数据(
datas[0]
)长度相等的 length,当然可以用len(self)
获得
如果正在重播数据或传递了实时数据,并且新的数据到达相同时间点(长度)的话,可以调用next
而不更改 长度
成员属性:
env
: 此策略所在的 cerebro 实体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
: 保存由 cerebro 为该策略创建的观察者的列表/类似命名元组序列analyzers
: 保存由 cerebro 为该策略创建的分析器的列表/类似命名元组序列position
: 实际上是一个属性,用于给出data0
的当前持仓。
有用于检索所有仓位的方法(参见参考资料)
成员属性(用于统计/观察者/分析器):
_orderspending
: 将在调用next
之前通知给策略的订单列表_tradespending
: 将在调用next
之前通知给策略的交易列表_orders
: 已经通知的订单列表。订单可以以不同的状态和不同的执行位多次出现在列表中。此列表用于保留历史记录。_trades
: 已通知的订单列表。交易可以像订单一样多次出现在列表中。
注意
请记住,prenext
、nextstart
和 next
可能会针对同一时间点被多次调用(当使用日线时,每次 ticks 更新价格时)
参考:Strategy
类 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] 或 self.data0
(又名self.data
)将被使用size
(默认为None
)
要使用的数据单位(正数)来用于订单。
如果为None
,则将使用通过getsizer
获取的sizer
实例来确定大小。price
(默认为None
)
用于价格(实时经纪人可能对实际格式施加限制,如果不符合最小 tick 大小要求)
对于Market
和Close
订单,None
是有效的(市场决定价格)
对于Limit
、Stop
和StopLimit
订单,此值确定触发点(在Limit
的情况下,触发显然是订单应匹配的价格)plimit
(默认为None
)
仅适用于StopLimit
订单。这是触发隐含 Limit 订单的价格,一旦 Stop 被触发(price
已被使用)trailamount
(默认为None
)
如果订单类型是StopTrail
或StopTrailLimit
,这是一个绝对数值,用于确定距离价格的距离(对于卖单是下方,对于买单是上方)以保持跟踪止损trailpercent
(默认为None
)
如果订单类型是StopTrail
或StopTrailLimit
,这是一个百分比数值,用于确定距离价格的距离(对于卖单是下方,对于买单是上方)以保持跟踪止损(如果还指定了trailamount
,它将被使用)exectype
(默认值:None
)可能的值:
Order.Market
或None
. 一个市价订单将以下一个可用价格执行。 在回测中,它将是下一个 bar 的开盘价Order.Limit
. 一个只能以给定的price
或更好的价格执行的订单Order.Stop
. 一个在price
处触发并像Order.Market
订单一样执行的订单Order.StopLimit
. 一个在price
处触发并以隐式Limit订单形式执行的订单,价格由pricelimit
给出Order.Close
. 一个只能在会话结束时(通常在收盘竞价时)执行的订单Order.StopTrail
. 一个在price
减去trailamount
(或trailpercent
)处触发并在价格远离停止时更新的订单Order.StopTrailLimit
. 一个在price
减去trailamount
(或trailpercent
)处触发并在价格远离停止时更新的订单
valid
(默认值:None
)可能的值:
None
: 这将生成一个不会过期的订单(又称Good till cancel),并保持在市场上直到匹配或取消。 实际上,经纪人往往会强加一个时间限制,但这通常是如此遥远的时间,以至于可以视为不会过期。datetime.datetime
或datetime.date
实例:日期将用于生成一个直到给定日期时间(又称good till date)的有效订单Order.DAY
或0
或timedelta()
: 一个有效期至会话结束(又称day订单)的订单将被生成numeric value
: 这被假设为与matplotlib
编码中的日期时间对应的值(backtrader
使用的编码方式),并将用于生成一个有效订单,直到该时间(good till date)
tradeid
(默认值:0
)
这是backtrader
应用的内部值,用于跟踪同一资产上的重叠交易。 当通知订单状态变化时,此tradeid
将发送回strategy。oco
(默认值:None
)
另一个order
实例。 这个订单将成为 OCO(Order Cancel Others)组的一部分。 一个订单的执行会立即取消同一组中的所有其他订单parent
(默认值:None
)
控制一组订单的关系,例如一个由高限价卖出和低止损卖出所包围的买入订单。高/低侧订单保持不活跃,直到父订单被执行(它们变为活动状态)或取消/过期(子订单也取消)bracket 订单具有相同的大小transmit
(默认值:True
)
指示订单是否必须发送,即不仅在经纪人处放置,而且发出。 例如,这用于控制 bracket 订单,其中一个禁用父订单和第 1 组子订单的传输,并激活最后一组子订单的传输,这会触发所有 bracket 订单的完全放置。**kwargs
:其他经纪人实现可能支持额外的参数。backtrader
将kwargs传递给创建的订单对象
示例:如果直接由backtrader
支持的 4 种订单执行类型不够,例如Interactive Brokers的情况下,可以将以下内容作为kwargs传递:
orderType='LIT', lmtPrice=10.0, auxPrice=9.8`
- 这将覆盖
backtrader
创建的设置,并生成一个touched价格为 9.8,limit价格为 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)
创建一个支架订单组(低端 - 买单 - 高端)。默认行为如下:
- 发出buy带有执行
Limit
的订单 - 发出一个low side支架sell带有执行
Stop
的订单 - 发出一个high side支架sell带有执行
Limit
的订单。
有关不同参数的详细信息,请参见下文
data
(默认值:None
)
要为哪些数据创建订单。如果为None
,则将使用系统中的第一个数据,self.datas[0]或 self.data0
(又名self.data
)size
(默认值:None
)
要使用的大小(正)以用于订单的数据单位。
如果为None
,则将使用通过getsizer
检索到的sizer
实例确定大小。
注意
同样的大小适用于支架的所有 3 个订单price
(默认值:None
)
使用价格(实时经纪人可能会对实际格式施加限制,如果不符合最小跳动大小要求)None
适用于Market
和Close
订单(市场确定价格)
对于Limit
、Stop
和StopLimit
订单,此值确定触发点(在Limit
情况下,触发显然是订单应匹配的价格)plimit
(默认值:None
)
仅适用于StopLimit
订单。这是设置隐含Limit订单的价格,一旦Stop已被触发(已使用price
)trailamount
(默认值:None
)
如果订单类型为 StopTrail 或 StopTrailLimit,则此值是一个绝对金额,用于确定保持跟踪止损的价格距离(对于卖出订单为下方,对于买入订单为上方)trailpercent
(默认值:None
)
如果订单类型为 StopTrail 或 StopTrailLimit,则此处为一个百分比值,确定保持跟踪止损的距离(对于卖出订单下方,对于买入订单上方)(如果还指定了trailamount
,则将使用它)exectype
(默认值:bt.Order.Limit
)
可能的取值:(查看方法buy
的文档)valid
(默认值:None
)
可能的取值:(查看方法buy
的文档)tradeid
(默认值:0
)
可能的取值:(查看方法buy
的文档)oargs
(默认值:{}
)
将特定的关键字参数(在dict
中)传递给主侧订单。默认的**kwargs
中的参数将在此基础上应用。**kwargs
:其他经纪人实现可能支持额外的参数。backtrader
将把kwargs传递给创建的订单对象
可能的取值:(查看方法buy
的文档)
注意
这个kwargs
将应用于一个括号的 3 个订单。有关低侧和高侧订单的特定关键字参数,请参见下文stopprice
(默认值:None
)
低侧停止订单的具体价格stopexec
(默认值:bt.Order.Stop
)
低侧订单的具体执行类型stopargs
(默认值:{}
)
将特定的关键字参数(在dict
中)传递给低侧订单。默认的**kwargs
中的参数将在此基础上应用。limitprice
(默认值:None
)
高侧停止订单的具体价格stopexec
(默认值:bt.Order.Limit
)
高侧订单的具体执行类型limitargs
(默认值:{}
)
将特定的关键字参数(在dict
中)传递给高侧订单。默认的**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)
创建一个括号订单组(低侧 - 买入订单 - 高侧)。默认行为如下:
- 发出一个卖出订单,执行
限价
- 发出一个高侧括号买入订单,执行
停止
- 发出一个低侧括号买入订单,执行
限价
。
查看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)
下达订单以将头寸重新平衡为当前投资组合value
的target
百分比的最终价值
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
来确定头寸是多头
/空头
- 如果
target
>value
- 如果
pos.size >= 0
则买入(增加多头头寸) - 如果
pos.size < 0
则卖出(增加空头头寸)
- 如果
target
<value
- 如果
pos.size >= 0
则卖出(减少多头头寸) - 如果
pos.size < 0
则买入(减少空头头寸)
它返回以下之一:
- 生成的订单
或
- 如果没有下达订单,则为
None
(target == position.size
)
getsizer()
返回正在使用的 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
为 None,则将使用默认经纪人
也可用的属性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)
注意
可以在 __init__
或 start
期间调用
安排一个计时器来调用一个或多个策略的指定回调函数或 notify_timer
。
- 参数when(-) – 可以是
datetime.time
实例(参见下面的tzdata
)bt.timer.SESSION_START
用于引用会话开始bt.timer.SESSION_END
用于引用会话结束offset
必须是一个datetime.timedelta
实例
- 用于偏移值
when
。与SESSION_START
和SESSION_END
结合使用具有有意义的用途,以指示会话开始后15 分钟
调用计时器的情况。
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
实例或一个数据源实例。None
:when
按照面值解释(即使它不是 UTC 时间也会被处理为 UTC 时间)pytz
实例:when
将被解释为由时区实例指定的本地时间。data feed
实例:when
将被解释为数据源实例参数tz
指定的本地时间。
注意
如果when
是SESSION_START
或SESSION_END
,并且tzdata
是None
,则系统中的第一个数据源(即self.data0
)将被用作查找会话时间的参考。cheat
(默认为False
)如果为True
,则在经纪人有机会评估订单之前将调用计时器。这打开了在会话开始之前根据开盘价发出订单的可能性*args
:任何额外的参数将被传递给notify_timer
**kwargs
:任何额外的 kwargs 将被传递给notify_timer
BackTrader 中文文档(五)(2)https://developer.aliyun.com/article/1489255