backtrader 文档学习-爱代码爱编程
Backtrader 文档学习-Strategy(上)
策略通过方法的形式体现生命周期。
是BackTrader的核心模块,需要好好研读。
1.Strategy
- (1)怀胎
在init中创建indicator和需要的属性值 - (2)出生
start方法,策略启动,start默认是空方法 - (3)儿童
prenext方法,indicator 在init初始化的时候设置了成熟期的时间,称为最小周期。上面在 __init__创建了一个周期=15的SimpleMovingAverage。 - (4)成人
next方法,一旦系统生成15个bar,SMA缓存了足够的用于启动的数据,策略就可以真正执行。
nextstart方法执行一次,是从prenext切换到next的标志,nextstart默认执行是调用next方法。 - (5)生育
策略中并没有真正的生育,但是从某种意义上来说是存在的,因为如果优化用不同的参数的话,系统会实例化多次。算是生育吧 - (6)死亡
stop方法,系统通知策略重启,恢复所有设置,默认是空方法。
策略就像现实世界中的交易员一样,会在事件发生时得到通知。实际上在每一个next循环在回测过程中 :
- 通过notify_order(order)获得订单状态变化的通知
- 通过notify_trade(trade)通知所有开仓/更新/平仓交易
- 通过notify_cashvalue(cash,value)通知在broker中当前现金和投资组合
- 通过notify_fund(cash,value,fundvalue,shares)跟踪broker中当前现金和投资组合,以及基金价值和份额
- 通过notify_store(msg,*args,**kwargs)实现特定事件 ,请参见Cerebro的关于store的说明。event将被传递给策略,即使已经被传递给cerebro实例(通过重写notify_store方法或通过回调)
策略像交易者有机会在市场期间通过next方法试图实现获利
- buy方法 是做多或减少/平仓空头的头寸
- sell方法 是做空或减少/平仓多头的头寸
- close方法 是平仓存在的仓位
- cancel方法 是取消尚未执行的订单
2. How to Buy/Sell/Close
order常用的方法是Buy和Sell方法。当被调用时,它们返回一个订单(或子类)实例作参考。该订单具有唯一的参考标识符,可用于对比。
order的参数:
- data(默认:无) 必须为其创建订单的数据。如果没有,则将使用系统中的第一个数据,即self.datas[0]或self.data0(也称为self.data)
- size(默认值:无) 用于订单的数据单位的大小(正值)。 如果没有,将使用通过getsizer检索的sizer来确定大小。
- price(默认值:无) 如要设置的价格(实时broker会对其进行限制,如果格式不符合最小报价单位要求)
None对market订单和close订单是有效(市价决定价格)
对于limit限价单、stop止损单和stoplimit单,该值price决定是否触发,(在限价单limit的情况下,触发点显然是订单应该匹配price) - exectype(默认值:None) 执行订单的类型:
- Order.Market or None,市价单将以next可用价格执行。回测中,next使用第二天的开盘价执行订单。
- Order.Limit,只能以给定价格或更低(好)价格执行的订单
- Order.Stop,止损价格被触发,和订单一样执行。
- Order.StopLimit,以价格触发的订单,隐含限价订单执行,价格由pricelimit执行,理解应该是止损单的止损价格。
- numeric value: 如果是一个与matplotlib编码中的日期时间相对应的值(backtrader使用的日期时间),就是该数字能转换成正确的日期,可以生成一个在该时间(截止日期)之前有效的订单。
如果backtrader直接支持的4种订单执行类型还不够用,例如在交互时broker,可以将作为kwargs传递:
orderType='LIT', lmtPrice=10.0, auxPrice=9.8
将重写backtrader创建的设置,并生成一个触及限价单,触及价格为9.8,限价为10.0。
3.Information Bits
策略的长度总是等于主数据(datas[0])的长度,可以用len(self) 。
如果正在replay数据或正载入数据,并且新tick正在到达相同的时间点,调用next而不改变长度 。(没有理解 ?)
4.Member Attributes
- env:加载策略的cerebro 实体
- datas:加载到cerebro的数据,默认data/data0是data[0],dataX是data[X]
- dnames:通过名称访问数据加载的替代方法。
在数据加载时:
data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date,name='days') # 加载数据
# Add the Data Feed to Cerebro
cerebro.adddata(data)
cerebro.resampledata(data, timeframe=bt.TimeFrame.Weeks, name='weeks')
在策略的indicator中:
class MyStrategy(bt.Strategy):
def __init__(self):
self.dataclose = self.datas[0].close
smadays = bt.indicators.SMA(self.dnames.days, period=30) # or self.dnames['days']
smaweeks = bt.indicators.SMA(self.dnames.weeks, period=10) # or self.dnames['weeks']
- broker:策略所关联的broker
- stats:由cerebro为相关策略创建的Observers ,保存为列表/命名的类似元组的序列
- analyzers:由cerebro为相关策略创建的analyzers,保存为列表/命名的类似元组的序列
- position:data0的仓位
5.Member Attributes (适用于statistics/observers/analyzers):
- _orderspending: 在调用next方法将通知给策略的订单列表
- _tradespending: 在调用next方法将通知给策略的交易列表
- _orders:已经完成通知的订单列表。一个订单可以在列表中出现多次,具有不同的状态和不同的执行位,目的是记录历史。
- _trades: 已经完成通知的订单列表。像订单一样,一笔交易可以列表上出现多次。
6.Strategy参考
next()
当满足所有data/indicators的最小周期后,执行将对所有剩余数据点调用。
如period是10 ,最小周期达到后,开始执行next方法。
nextstart()
方法执行一次,在最小周期的data/indicators满足时,默认执行next方法。
如period是10 ,在到达9执行最小周期达到后,执行一次nextstart,之后执行next方法。
prenext()
方法将在所有数据/指标的最小周期满足策略开始执行之前调用执行。
如period是10 ,在1到9执行最小周期之间,执行prenext。
start()
在回测即将开始之前调用,执行一次。
stop()
在回测即将结束之前调用,执行一次。
notify_order(order)
每当订单发生变化时,都会接收订单变化的通知
notify_trade(trade)
每当交易发生变化时,都会接收交易变化的通知
notify_cashvalue()
notify_cashvalue(cash, value)
接收当前使用的资金余额,broker的资金状态还是现金价值 ???
Receives the current fund value, value status of the strategy’s broker
notify_fund()
notify_fund(cash, value, fundvalue, shares)
策略的资金和价值发生变化时被调用。用于跟踪和记录策略的现金、价值、基金价值和持仓股票的数量。
notify_fund方法的参数:
- cash: 当前策略的现金余额。
- value: 当前策略的总价值(包括持有的股票价值)。
- fundvalue: 策略基金的价值。这是另一个属性,与value不同,它可能代表策略的总资产,包括现金和股票,但不包括费用和税费等其他扣除。???
- shares: 当前策略持有的股票数量。
notify_store()
notify_store(msg, *args, **kwargs)
接收broker的通知信息。
buy()重要!
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)
strategy重要的方法,buy方法的参数:
-
data: 可选参数,表示当前的数据对象。如果提供,它将在执行交易时使用该数据对象。
-
size: 可选参数,正数,表示要购买的合约数量或金额。如果没有指定,将使用默认值或策略中定义的size属性,getsizer 返回设置值。
-
price: 可选参数,表示买入的价格限制。如果实际格式不符合最小报价单位的要求,实时broker可以对其进行限制。
-
plimit: 可选参数,仅适用于停止限制订单。一旦止损被触发,设置隐含限价单的价格(已使用该价格)。
-
trailamount :可选参数,如果订单类型是StopTrail或StopTrailLimit,使用绝对金额,它决定了保持跟踪止损的价格距离(低于卖出订单,高于买入订单)
-
trailpercent :可选参数,如果订单类型是StopTrail或StopTrailLimit,使用百分比金额,它决定了保持跟踪止损的价格距离(低于卖出订单,高于买入订单),如果同时还指定了trailamount,优先使用trailpercent 。
-
exectype: 可选参数,表示执行类型。
- Order.Market or None. Market或者不指定值,市价单将以下一个可用价格执行。在回测中它将是下一bar的开盘价
- Order.Limit. 只能以给定价格或更好的价格执行的订单。(对于买单,更低的价格;对于卖单,更高的价格?)
- Order.Stop. 在价格一旦被触发,像Order.Market一样被执行的止损订单
- Order.StopLimit.以价格触发执行的隐含限价单订单,价格由限价单plimit决定
- Order.Close. 只能以设定的平仓价格执行的订单
- Order.StopTrail. 如果价格波动超过止损点,订单会更新,在价格减去trailamount 值(或减去trailpercent值) 时触发的订单
- Order.StopTrailLimit. 如果价格波动超过止损点,订单会更新,在价格减去trailamount (或trailpercent)时触发的订单
Order.StopTrail和Order.StopTrailLimit ,从字面上看不出具体差异区别。
-
valid: 可选参数,表示交易的有效期。它可以是时间格式的字符串或一个 datetime.timedelta对象。默认情况下,它将使用策略中定义的valid属性。
- None: 只要市场存在,数据持续,订单永不过期(除非上帝取消它),在现实中broker会施加一个临时 的时间限制,但通常是遥不可及的时间
- datetime.datetime or datetime.date instance: 日期类型参数,订单到指定的时间停止。
- Order.DAY or 0 or timedelta(): Order.DAY,timedelta()类型, 生成一个在会话结束前有效的日期(也称为日订单)
- numeric value: 数字类型,假定为与matplotlib编码中的日期时间相对应的值,(backtrader中使用的日期时间),将用于生成在该时间之前有效的订单(有效截止日期) 。数字类型实际上是可以转换为matplotlib的日期类型。
-
tradeid: 可选参数,表示交易的唯一标识符。默认情况下,它将自动生成一个唯一的交易ID。backtrader应用的内部值,用于跟踪同一资产的重叠交易。当通知订单状态的变化时,该tradeid被发送回策略。
-
oco: 可选参数,表示是否使用OCO(One-Cancels-All)订单。如果提供,该订单将成为OCO(订单取消其他)组的一部分。其中一个订单的执行会立即取消同一组中的所有其他订单。
-
parent: 可选参数,表示父交易对象。如果提供,将将当前交易附加到父交易上。
控制一组订单的关系,例如由高限价卖出和低止损卖出组成的买入。高/低价格的订单保持无效直到父订单被执行(它们变为有效)或被取消/到期(子订单也被取消)为止。(bracket orders have the same size)回测订单具有相同的大小? -
transmit: 可选参数,表示是否传输交易请求。默认情况下为True,表示将传输交易请求到执行引擎。
指示是否必须传输订单,即:不仅在broker中发出。这意味着,例如,控制bracket 订单,其中一个为父代和第一组子代禁用传输,并为最后的子代激活传输,将触发所有bracket 订单的完全设置。 -
**kwargs: 其他broker实现可能支持额外的参数。backtrader将把kwargs传递给创建的订单对象 例如:如果backtrader直接支持的4种订单执行类型还不够,例如在交互式经纪人的情况下,可以将以下类型作为kwargs传递:
orderType='LIT', lmtPrice=10.0, auxPrice=9.8
将覆盖backtrader创建的设置,并生成一个触及限价单,触及价格为9.8,限价为10.0。
(个人理解:应该是 在init初始化中定义的参数。)
- Returns,返回提交的buy订单(数量?列表?)
sell()重要!
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)
创建卖出(卖空)订单并将其发送给broker 。
参数与buy一样,不再赘述。
close()
close(data=None, size=None, **kwargs)
结算多头/空头,平仓。
returns:提交的订单
cancel(order)
取消broker中的订单
buy_bracket()买组合单
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)和一个买入止损单(buy stop),或者同时发送一个买入限价单和一个卖出止损单(sell stop,作为保护性止损)。订单组合通常用于捕捉市场波动并设置相应的风险管理措施。
创建一个组合订单(低价端-订单-高价端)。默认操作如下:
- 发出有执行限制的买单
- 发出带执行止损的低价组合卖单
- 发出有执行限制的高价组合卖单
方法参数:
-
data: 可选参数,表示当前的数据对象。如果提供,它将在执行交易时使用该数据对象。
-
size: 可选参数,正数,表示要购买的合约数量或金额。如果没有指定,将使用默认值或策略中定义的size属性,getsizer 返回设置值。
-
price: 可选参数,表示买入的价格限制。如果实际格式不符合最小报价单位的要求,实时broker可以对其进行限制。
None 是有效的,对市价订单和平仓订单有效(市价决定价格)
对于限价单、止损单和限价止损单,该值决定触发点价格。(在限价单的情况下,触发价显然是订单应该匹配的价格) -
plimit: 可选参数,仅适用于停止限制订单。一旦止损被触发,设置隐含限价单的价格(已使用该价格)。
-
trailamount :可选参数,如果订单类型是StopTrail或StopTrailLimit,使用绝对金额,它决定了保持跟踪止损的价格距离(低于卖出订单,高于买入订单)
-
trailpercent :可选参数,如果订单类型是StopTrail或StopTrailLimit,使用百分比金额,它决定了保持跟踪止损的价格距离(低于卖出订单,高于买入订单),如果同时还指定了trailamount,优先使用trailpercent 。
-
exectype (default: bt.Order.Limit)
可能值:参考buy的说明 -
valid (default: None) 参考buy的说明
-
tradeid (default: 0) 参考buy的说明
-
oargs (default: {}) 特定的关键字参数(在字典dict中)传递到主顺序。默认**kwargs中的参数将应用(优先??)于此之上。
**kwargs: 其他broker实现可能支持额外的参数。backtrader将把kwargs传递给创建的订单对象。参考buy的说明。 -
stopprice (default: None) 设置低价止损价订单
-
stopexec (default: bt.Order.Stop) 设置低价订单的类型,默认是止损单
-
stopargs (default: {}) 传递给低价订单的特定关键字参数(在字典dict中)。默认**kwargs中的参数将应用于此之上。
-
limitprice (default: None) 设置高价止损单
-
stopexec (default: bt.Order.Limit) 设置高价限价订单 ,和上一个stopexec应该一样,只不过参数值不同。
-
limitargs (default: {}) 传递给高价订单的特定关键字参数(在字典dict中)。默认**kwargs中的参数将应用于此之上。
-
High/Low Side orders can be suppressed by using:
高价/低价订单抑制设置:- limitexec=None 抑制高价
- stopexec=None 抑制低价
-
Returns 返回值
返回list对象,包括3个订单[订单,止损单,限价单]
If high/low orders have been suppressed the return value will still contain 3 orders, but those suppressed will have a value of None
如果高价/低价订单已被抑制(取消?),返回值仍将包含3个订单,但被取消的订单的值将为None 。
sell_bracket()卖组合单
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)
创建一个卖组合单(低价-订单-高价)。默认行为如下:
- 发出限价的卖单
- 发出止损高价买单
- 发出限价低价买单
可以和buy_bracket()对比理解。
其他参数看 bracket_buy 说明。
-
高价/低价 可通过以下方法抑制:
- stopexec=None 抑制高价
- limitexec=None 抑制低价
-
Returns 返回值
返回list对象,包括3个订单[订单,止损单,限价单]
如果高价/低价订单已被取消,返回值仍将包含3个订单,但被取消的订单的值将为None 。
order_target_size()
order_target_size(data=None, target=0, **kwargs)
基于目标持仓数量来发出订单。这个方法的目的是调整当前持仓以达到指定的目标持仓数量。
target: 必需参数,指定目标持仓数量。可以是正数(多头持仓),负数(空头持仓),默认值0(平仓)。
当前仓位值被视为实现目标的起点:
- 如果没有目标仓位值,则在当前位置平仓
- 如果目标仓位值>当前仓位,则买入
- 如果目标仓位值<当前仓位,则卖出
返回值:
可能是生成的订单 或者 None 没有任何订单被触发
order_target_percent()
order_target_percent(data=None, target=0.0, **kwargs)
重新平衡头寸,使最终价值达到当前投资组合价值的目标百分比 。
根据目标持仓百分比来发出订单。用于根据资产配置或风险管理要求调整持仓比例。
target 必需参数,指定目标持仓百分比。这个值应该在0到1之间(不包括0和1),表示目标持仓占账户总资产的比例。
使用order_target_value来执行订单。
举例说明:
- target=0.05 投资组合值 100
- value= 0.05 * 100 = 5
- 赋值order_target_value =5
The current value is taken into account as the start point to achieve target
当前值被视为实现目标的起点 。
position.size用于确定头寸是多头/空头
- target > value
- 买入 if pos.size >= 0 (增加多头)
- 卖出 if pos.size < 0 (增加空头)
- target < value
- 卖出 if pos.size >= 0 (减少多头)
- 买入 if pos.size < 0 (减少空头)
返回值:
生成的订单,或者如果(target == position.size),无订单,则None 。
getsizer()
自动计算返回持仓数量,也可以用sizer对象
setsizer()
设置持仓数量
getsizing()
getsizing(data=None, isbuy=True)
用于确定应该买入或卖出的资产数量。
isbuy: 必需参数,布尔值,指示是否计算买入订单的大小。如果为True,则计算买入订单的大小;如果为False,则计算卖出订单的大小。
getposition()
getposition(data=None, broker=None)
用于获取当前broker持仓信息
如果两个参数都是None,使用主data和默认broker 。
['__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'adjbase', 'clone', 'datetime', 'fix', 'price', 'price_orig', 'pseudoupdate', 'set', 'size', 'upclosed', 'update', 'updt', 'upopened']
Position对象可用属性,对象包含了当前持仓的详细信息。信息包括:
- position.size:持仓数量
- position.price:持仓成本单价
可以直接打印输出position :
--- Position Begin
- Size: 10
- Price: 126.75585714285712
- Price orig: 126.74206349206348
- Closed: 0
- Opened: 1
- Adjbase: 126.04
--- Position End
getpositionbyname()
(1)getpositionbyname(name=None, broker=None)
返回指定broker的某个资产持仓情况
如果两个参数都是None,使用主data和默认broker 。
Position对象可用属性,同上。
(2)getpositionsbyname(broker=None)
返回某个broker下所有资产持仓情况(不区分资产?)
Position对象可用属性,同上。
网上找了个例子,先理解一下。
# 获取特定资产的持仓信息
position = self.getpositionbyname('AAPL')
# 检查持仓盈亏状况
if position.pnl > 0:
print("AAPL is in profit!")
elif position.pnl < 0:
print("AAPL is in loss!")
else:
print("AAPL is flat.")
getdatanames()
返回策略中存在的数据源名称
getdatabyname(name)
在当前使用cerebro中按名称返回给定数据
add_timer()
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)
调度一个计时器来调用指定的回测或一个或多个策略的notify_timer。
它允许在特定时间触发事件,例如在特定日期、时间或间隔内执行某些操作。
注意:
只能在 init or start 中设置执行
参数说明:
-
when :必选参数
- 可以是 datetime.time实例(参见后面的tzdata)
- t.timer.SESSION_START 引用会话开
- timer.SESSION_END引用会话结束
- offset 必须是datetime.timedelta实例的偏移量
如指定偏移该值,它与SESSION_START和SESSION_END结合使用才有意义,可以指示诸如会话开始15分钟(offset)后调用计时器执行操作。
-
repeat: 可选参数
指示在第一次调用后,是否将在同一会话中以预定的重复增量安排多次调用。 一旦定时器在会话结束时,它将被重置为原始值。
指定事件的重复间隔,可以是datetime.timedelta对象或其他时间单位(例如天、小时等)。默认值为datetime.timedelta(0),即不重复。 -
weekdays: 可选参数
一个包含星期几的整数列表(1代表星期一,2代表星期二,以此类推),用于指定仅在某些特定的星期几触发事件。默认值为空,即每天都有可能触发。 -
monthcarry: 可选参数,布尔值
指定是否在每月某个日期不可用(周末,节假日),并延续到下一个可用日期。默认值为True,即延续下一个交易日。 -
allow: 可选参数
是否调用函数,接收datetime.date数据类型,如果日期允许用于计时器,则返回True,否则返回False。
用于过滤是否允许触发事件。如果该函数或方法返回True,则允许触发;如果返回False,则不允许触发。默认值为None,即无过滤条件。 -
tzdata: 可选参数
指定时区数据。是时区对象、时区字符串或包含时区数据的字典。默认值为None,即使用当前系统时区。
pytz实例:when将被解释为由timezone实例指定的本地时间。(pytz是时区数据类型 ?) -
cheat: 可选参数,布尔值
如果为true,将在broker调用计时器前有机会评估订单。提供了根据开盘价发出订单的机会,例如就在会话开始之前。指定是否在调用期间使用定时器事件。 -
*args: 其他可选参数列表
用于传递给定时器事件notify_timer -
**kwargs: 其他可选关键字参数列表
用于传递给定时器事件的notify_timer
返回值
创建成功的timer
notify_timer()
notify_timer(timer, when, *args, **kwargs)
当指定的时间到达时,该方法将调用与定时器相关联的回调函数,并传递相应的参数。
以下是notify_timer方法的一些参数说明:
- timer: 必选参数,指定要触发的定时器对象。
- when: 必选参数,指定触发事件的时间。它可以是datetime.datetime对象或字符串表示的日期和时间。
- *args: 可选参数,其他可选参数列表,用于传递给回调函数。
- **kwargs: 可选参数,其他可选关键字参数列表,用于传递给回调函数。
接收计时器通知,其中timer是add_timer返回的计时器,而when是调用时间。
args和kwargs是传递给add_timer的任何附加参数。
实际when调用时间可能晚一些,但系统可能无法调用之前的计时器。
这个值是定时器值,而不是系统时间。
使用场景:可以在回调函数中执行交易操作、发送通知或更新策略状态等。
注意:notify_timer方法仅在Backtrader的回测或实时交易期间有效。在策略初始化或初始化之后的阶段调用该方法将不会产生任何效果。确保在适当的时间和上下文中使用该方法,以实现您想要的定时器功能。
终于完成了,strategy的方法、属性很多,是做好回测设计中最重要的一个步骤,需要后面做程序验证是否理解到位。