上一篇文章详细介绍数据相关类,本文开始 介绍和Cerebro一样重要的Strategy。如果Cerebro是大脑,那Strategy就是心脏,所有血液(数据)流经心脏(Strategy)处理。
老规矩,先上Strategies的家族图谱。
Strategy家族图谱

同样的,牢牢记住这个图,这是咱们的家谱。
Note1:图中类名后面加标号直接和未加标号同名类定义完全相同,比如LineRoot1和Lineroot是相同的。主要是为了图形清爽,不然太多交叉,看不清楚。
Note2:由于Strategy类通常要自定义,所以增加了一个自定义类继承自Strategy。
一个简单的均线Strategy
为了更好地进行代码解读,我们提供了一个简单的定制MyCustomStrategy类,继承Strategy,完成均线策略。
class MyCustomStrategy(bt.Strategy):
params = (
('maperiod', 5),
)
def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
# To keep track of pending orders and buy price/commission
self.order = None
self.buyprice = None
self.buycomm = None
# Add a MovingAverageSimple indicator
self.sma = bt.indicators.SimpleMovingAverage(
self.datas[0], period=self.params.maperiod)
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# Buy/Sell order submitted/accepted to/by broker - Nothing to do
return
# Check if an order has been completed
# Attention: broker could reject order if not enough cash
if order.status in [order.Completed]:
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close:%.3f' % self.data.close[0])
self.log('turnover, %.8f' % self.data.turnover[0])
# Check if an order is pending ... if yes, we cannot send a 2nd one
if self.order:
return
#Check if we are in the market
if not self.position:
if self.dataclose[0] > self.sma[0]:
# 大于均线就买
self.log('BUY CREATE, %.2f' % self.dataclose[0])
# Keep track of the created order to avoid a 2nd order
self.order = self.buy()
else:
if self.dataclose[0] < self.sma[0]:
# 小于均线卖卖卖!
self.log('SELL CREATE, %.2f' % self.dataclose[0])
# Keep track of the created order to avoid a 2nd order
self.order = self.sell()
此段代码具体解释,请参见系列文章1.
下面以人的一生来描述Strategy的发展过程。
孕育阶段
在Cerebro代码详解一文中,我们说明了如何使用strategy:
- 首先通过Cerebro中添加Strategy类(本文以添加定制类MyCustomStrategy为例),这个只是添加类,还没有实例化,和Strategy实现没啥关系。
- 然后Cerebro在runstrategies函数中实例化和初始化,代码如下:
for stratcls, sargs, skwargs in iterstrat:
sargs = self.datas + list(sargs)
try:
strat = stratcls(*sargs, **skwargs)
except bt.errors.StrategySkipError:
continue # do not add strategy to the mix
下面我们看看Strategy的实例化和初始化。
Strategy的实例化
从家谱图中我们可以看出,MyCustomStrategy的父类中有元类,所以实例化会受MetaBase元类的控制。首先到MetaBase的__call__走一圈:
-
首先是doprenew,没人重写,啥也没做。
-
然后donew,顺着家谱找,MetaStrategy重写了donew,但是其中第一句话,就先调用父类的donew,父类是MetaLineIterator,它的donew又调用到自己父类的donew,继续MetaLineSeries–>MetaLineRoot->MetaParams->MetaBase.太复杂了,俄罗斯套娃啊。熟悉的味道,又到MetaParams,这个之前介绍过,就是调用MetaBase的donew实例化MyCustomStrategy,并且完成参数到属性的映射。
-
MyCustomStrategy实例化完成之后,就到MetaLineRoot的donew,这个系列文章4也讲过,主要是查找自己的owner是谁?MyCustomStrategy是初始化的发起者,所以它没有owner。
-
继续到MetaLineSeries的donew,这个系列文章4也讲过(为啥都讲过?这也是面向对象的好处啊,代码大量复用)。 首先初始化一个AutoInfoClass保存plotinfo,并根据参数设置属性,画图使用,暂时忽略,后续专题再讲。然后就是最重要的也实例化了和初始化了lines以及LineBuffer(这一块在文章4中有详细描述),这里注意下,LineBuffer的owner就是MyCustomStrategy。这样MyCustomStrategy和数据源一样也拥有lines了,请参见家谱图。
-
下一步就是MetaLineIterator,这个就是strategy特有的,看代码:
def donew(cls, *args, **kwargs): _obj, args, kwargs = \ super(MetaLineIterator, cls).donew(*args, **kwargs) # Prepare to hold children that need to be calculated and # influence minperiod - Moved here to support

本文详细解析了Backtrader库中Strategy类的工作原理,从实例化、初始化、数据处理到策略操作,阐述了Strategy如何与Cerebro协同完成交易逻辑。Strategy作为策略核心,通过重写`__init__`和`next`方法实现自定义交易策略,如均线策略。在数据未达到最小周期时,会调用`prenext`,在数据有效后调用`next`进行实际交易操作。此外,还介绍了SignalStrategy,一种简化策略实现的类,通过信号触发买卖操作。
-Strategy类源代码解读&spm=1001.2101.3001.5002&articleId=121961354&d=1&t=3&u=5916d8a7dabc4c22a2aa203cf1cdbc4e)
1345

被折叠的 条评论
为什么被折叠?



