初步了解backtrader回测平台/框架 – backtrader中文教程
线迭代器
为了参与操作,平台使用线迭代器的概念。它们在 Python 的迭代器之后被松散地建模,但实际上与它们无关。
策略和指标是线迭代器。
线迭代器概念试图描述以下内容:
- 线迭代器踢从线迭代器告诉他们迭代
- Line Iterator 然后迭代它自己声明的命名行设置值
与常规 Python 迭代器一样,迭代的关键是:
next
方法_每次迭代都会调用它。线迭代器具有并用作逻辑/计算基础的datas
数组将已经被平台移动到下一个索引(除非数据重放)当满足行迭代器的最小周期时调用。下面对此进行更多介绍。
但是因为它们不是常规迭代器,所以存在两个额外的方法:
prenext
在满足 line iterator`的最小周期之前调用。nextstart
当满足 line iterator`的最小周期时恰好调用一次。默认行为是将呼叫转发到
next
,但如果需要,当然可以覆盖。
指标的额外方法
为了加快操作,Indicators 支持批量操作模式,也就是 runonce。它不是严格需要的(一种next
方法就足够了),但它大大减少了时间。
runonce 方法规则使索引为 0 的 get/set 点无效,并依赖于对保存数据的底层数组的直接访问,并为每个状态传递正确的索引。
定义的方法遵循下一个系列的命名:
once(self, start, end)
在满足最短期限时调用。内部数组必须在 start 和 end 之间处理,从内部数组的开头开始为零preonce(self, start, end)
在达到最短期限之前调用。oncestart(self, start, end)
满足最短期限时恰好调用一次。默认行为是将呼叫转发到
once
,但如果需要,当然可以覆盖。
最短期限
一张图片值一千字,在这种情况下也可能是一个例子。SimpleMovingAverage 能够解释它:
class SimpleMovingAverage(Indicator): lines = ('sma',) params = dict(period=20) def __init__(self): ... # 与解释无关 def prenext(self): print('prenext:: current period:', len(self)) def nextstart(self): print('nextstart:: current period:', len(self)) # 模拟默认行为 ... 调用下一个 self.next() def next(self): print('next:: current period:', len(self))
实例化可能如下所示:
sma = btind.SimpleMovingAverage(self.data, period=25)
简要说明:
- 假设传递给移动平均线的数据是标准数据馈送,其默认周期是
1
:数据馈送产生没有初始延迟的柱。 - 那么“period=25”实例化移动平均线的方法调用如下:
prenext
24次nextstart
1次(依次调用next
)next
n 次,直到数据馈送用完
让我们来看看杀手级指标:一个 SimpleMovingAverage超过另一个 SimpleMovingAverage。实例化可能如下所示:
sma1 = btind.SimpleMovingAverage(self.data, period=25) sma2 = btind.SimpleMovingAverage(sma1, period=20)
现在发生了什么:
- 同上
sma1
sma2
正在接收一个最短周期为 25的数据馈送,这是我们的,因此sma1
- 这些
sma2
方法的调用如下所示:prenext
前25+18次共43次- 25 次,以
sma1
产生其第一个合理的价值 - 18次累积额外
sma1
价值 - 总共 19 个值(25 次调用后 1 个,然后再有 18 个)
nextstart
然后 1 次(依次调用next
)next
额外的 n 次,直到数据馈送用完
next
当系统已处理 44 根柱线时,平台正在调用。
最小周期已根据传入数据自动调整。
策略和指标遵循此行为:
- 只有当达到自动计算的最小周期时才会
next
被调用(除非初始挂钩调用nextstart
) preonce
相同的规则适用于runonceoncestart
批处理操作模式once
- 尽管不推荐,但可以操纵最小周期行为。如果希望
setminperiod(minperiod)
在策略或指标中使用该方法
启动并运行
启动和运行至少涉及 3 个Lines对象:
- 数据馈送
- A Strategy(实际上是从 Strategy 派生的类)
- A Cerebro大脑(西班牙语中的大脑)
数据馈送
显然,这些对象提供将通过应用计算(直接和/或使用指标)进行回测的数据
该平台提供了几个数据源:
- 几种 CSV 格式和一个通用 CSV 阅读器
- 雅虎在线提取器
- 支持接收Pandas DataFrames和blaze对象
- 带有交互式经纪人、可视化图表和Oanda的实时数据馈送
该平台不对数据馈送的内容(例如时间范围和压缩)做出任何假设。这些值连同名称可用于提供信息和高级操作,例如数据馈送重采样(例如将 5 分钟的数据馈送转换为每日数据馈送)
设置 Yahoo Finance Data Feed 的示例:
import backtrader as bt import backtrader.feeds as btfeeds ... datapath = 'path/to/your/yahoo/data.csv' data = btfeeds.YahooFinanceCSVData( dataname=datapath, reversed=True)
显示 Yahoo的可选reversed
参数,因为直接从 Yahoo 下载的 CSV 文件以最新日期开始,而不是从最旧日期开始。
如果您的数据跨越较大的时间范围,实际加载的数据可以限制如下:
data = btfeeds.YahooFinanceCSVData( dataname=datapath, reversed=True fromdate=datetime.datetime(2014, 1, 1), todate=datetime.datetime(2014, 12, 31))
还可以添加压缩和名称:
data = btfeeds.YahooFinanceCSVData( dataname=datapath, reversed=True fromdate=datetime.datetime(2014, 1, 1), todate=datetime.datetime(2014, 12, 31) timeframe=bt.TimeFrame.Days, compression=1, name='Yahoo' )
策略(派生)类
Tips: 在继续之前并使用更简化的方法,如果不希望对策略进行子类化,请检查文档的 信号部分。
使用该平台的任何人的目标都是回测数据,这是在策略(派生类)中完成的。
有两种方法至少需要定制:
__init__
next
在初始化数据和其他计算指标的过程中,为以后应用逻辑做好准备。
稍后调用下一个方法以对数据的每个条形应用逻辑。
Tips: 如果传递了不同时间范围的数据馈送(因此不同的柱数)next
,则将为主数据调用该方法(传递给cerebro的第一个,见下文),它必须是具有较小时间范围的数据
Tips: 如果使用数据重播功能,则在next
重播该条的开发时,该方法将针对同一条被多次调用。
一个基本的 Strategy 派生类:
class MyStrategy(bt.Strategy): def __init__(self): self.sma = btind.SimpleMovingAverage(self.data, period=20) def next(self): if self.sma > self.data.close: self.buy() elif self.sma < self.data.close: self.sell()
策略有其他可以被覆盖的方法(或挂钩点):
class MyStrategy(bt.Strategy): def __init__(self): self.sma = btind.SimpleMovingAverage(self.data, period=20) def next(self): if self.sma > self.data.close: submitted_order = self.buy() elif self.sma < self.data.close: submitted_order = self.sell() def start(self): print('Backtesting is about to start') def stop(self): print('Backtesting is finished') def notify_order(self, order): print('An order new/changed/executed/canceled has been received')
start、
stop
的方法正如预期的那样,并遵循打印函数中的文本。notify_order
当策略需要通知时,将调用该方法。用例:
- 请求买入或卖出(如下所示)买/卖将返回提交给经纪人的订单。保留对这个提交的订单的引用取决于调用者。
例如,它可用于确保在订单仍处于待处理状态时不会提交新订单。
- 如果订单被接受/执行/取消/更改,经纪人将通过 notify 方法将状态更改(例如执行大小)通知回策略
notify_order
快速入门指南在该方法中有一个完整且实用的订单管理示例。
其他 Strategy 类可以做更多事情:
buy
//sell
_close
使用标的经纪商和分级器向经纪商发送买入/卖出订单同样可以通过手动创建订单并将其传递给经纪人来完成。但该平台旨在让使用它的人更容易。
close
将获得当前市场头寸并立即平仓。getposition
(或属性“位置”)返回当前市场头寸setsizer
/getsizer
(或属性“sizer”)这些允许设置/获取底层股权 Sizer。相同的逻辑可以与 Sizer 进行检查,这些 Sizer 为相同的情况提供不同的赌注(固定大小,与资本成正比,指数)有很多文学作品,但 Van K. Tharp 有关于这个主题的优秀书籍。
策略是一个Lines对象和这些支持参数,这些参数是使用标准 Python kwargs 参数收集的:
class MyStrategy(bt.Strategy): params = (('period', 20),) def __init__(self): self.sma = btind.SimpleMovingAverage(self.data, period=self.params.period) ... ...
请注意如何SimpleMovingAverage
不再使用固定值 20 进行实例化,而是使用已为策略定义的参数“周期”进行实例化。
一个大脑
一旦数据馈送可用并定义了策略,Cerebro 实例就可以将所有内容组合在一起并执行操作。实例化一个策略:
cerebro = bt.Cerebro()
如果不希望有什么特别的,默认值正在处理。
- 创建默认代理
- 运营不收取佣金
- 数据馈送将被预加载
- 默认执行模式为runonce(批量操作),速度更快所有指示灯必须支持
runonce
全速模式。平台中包含的那些。自定义指标不需要实现 runonce 功能。
Cerebro
将模拟它,这意味着那些非运行一次兼容的指标将运行得更慢。但大部分系统仍将以批处理模式运行。
由于数据馈送和策略(之前创建)已经可用,因此将它们放在一起并启动并运行的标准方法是:
cerebro.adddata(data) cerebro.addstrategy(MyStrategy, period=25) cerebro.run()
请注意以下事项:
- 添加了数据馈送“实例”
- MyStrategy“类”与将传递给它的参数(kwargs)一起添加。MyStrategy 的实例化将由 cerebro 在后台完成,“addstrategy”中的任何 kwargs 都将传递给它
用户可以根据需要添加尽可能多的策略和数据馈送。策略如何相互通信以实现协调(如果需要)不受平台强制/限制。
当然,Cerebro 提供了额外的可能性:
- 决定预加载和操作模式:
cerebro = bt.Cerebro(runonce=True, preload=True)
- 这里有一个约束:
runonce
需要预加载(如果没有,则无法运行批处理操作)当然预加载数据馈送不会强制执行runonce
setbroker
/getbroker
(和经纪人财产)如果需要,可以设置自定义代理。也可以访问实际的代理实例- 绘图。在常规情况下,如下所示:
cerebro.run() cerebro.plot()
- plot 需要一些参数来进行自定义
numfigs=1
如果地块太密集,它可能会被分成几个地块plotter=None
可以传递客户绘图仪实例,并且 cerebro 不会实例化默认的绘图仪实例**kwargs
– 标准关键字参数这将传递给绘图仪。
请参阅绘图部分以获取更多信息。
- 优化策略。如上所述,Cerebro 获得一个 Strategy 派生类(不是实例)和将在实例化时传递给它的关键字参数,这将在调用“run”时发生。
这是为了启用优化。同一个 Strategy 类将根据需要使用新参数多次实例化。如果一个实例被传递给了 cerebro……这是不可能的。
要求优化如下:
cerebro.optstrategy(MyStrategy, period=xrange(10, 20))
该方法optstrategy
具有相同的签名,addstrategy
但会进行额外的内务管理以确保优化按预期运行。一个策略可能期望一个范围作为策略的正常参数,并且 addstrategy
不会对传递的参数做任何假设。
另一方面,optstrategy
将理解可迭代是一组值,必须按顺序传递给 Strategy 类的每个实例化。
请注意,传递的不是单个值,而是一系列值。在这个简单的例子中,这个策略将尝试 10 个值 10 -> 19(20 是上限)。
如果使用额外参数开发更复杂的策略,它们都可以传递给optstrategy。不需要优化的参数可以直接传递,最终用户不必创建一个只有一个值的虚拟迭代。例子:
cerebro.optstrategy(MyStrategy, period=xrange(10, 20), factor=3.5)
该optstrategy
方法看到因子并在后台为具有单个元素的因子创建(需要的)虚拟迭代