BackTrader 中文文档(二)(2)https://developer.aliyun.com/article/1489215
策略是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 进行实例化,而是使用已为策略定义的参数“period”进行实例化。
一个 Cerebro
一旦数据源可用并且策略已定义,Cerebro 实例就是将所有内容汇集在一起并执行操作的工具。实例化一个很容易:
cerebro = bt.Cerebro()
如果没有特殊要求,则默认情况下会进行处理。
- 创建默认经纪人
- 操作无佣金
- 数据源将被预加载
- 默认执行模式将是 runonce(批量操作),这是更快的模式
所有指标必须支持runonce
模式以实现全速运行。平台中包含的指标可以。
自定义指标不需要实现 runonce 功能。Cerebro
将模拟它,这意味着那些不兼容 runonce 的指标将运行得更慢。但大部分系统仍将以批处理模式运行。
由于数据源已经可用,策略也已经创建(之前创建),将它们组合在一起并使其运行的标准方法是:
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
(以及broker属性)
如果需要,可以设置自定义经纪人。实际经纪人实例也可以被访问- 绘图。在常规情况下,就像这样简单:
cerebro.run() cerebro.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
方法看到因子并在后台为具有单个元素的因子创建(所需的)虚拟可迭代对象(例如 3.5 中的示例)。
注意
交互式 Python shell 和某些类型的在Windows下的冻结可执行文件对 Python 的multiprocessing
模块存在问题。
请阅读有关multiprocessing
的 Python 文档。
大脑
Cerebro
这个类是backtrader
的基石,因为它作为以下方面的中心点:
- 收集所有输入(数据源)、行动者(策略)、旁观者(观察员)、评论者(分析器)和文档编制者(写作者),确保节目随时进行。
- 执行回测/或实时数据提供/交易
- 返回结果
- 提供对绘图设施的访问
收集输入
- 首先创建一个
cerebro
:
cerebro = bt.Cerebro(**kwargs)`
- 支持一些
**kwargs
来控制执行,参见参考文献(这些参数后来也可以应用于run
方法) - 添加数据源
最常见的模式是cerebro.adddata(data)
,其中data
已经实例化为数据源。例如:
data = bt.BacktraderCSVData(dataname='mypath.days', timeframe=bt.TimeFrame.Days) cerebro.adddata(data)`
- 重新采样和回放数据是可能的,遵循相同的模式:
data = bt.BacktraderCSVData(dataname='mypath.min', timeframe=bt.TimeFrame.Minutes) cerebro.resampledata(data, timeframe=bt.TimeFrame.Days)`
- 或:
data = bt.BacktraderCSVData(dataname='mypath.min', timeframe=bt.TimeFrame.Minutes) cerebro.replaydatadata(data, timeframe=bt.TimeFrame.Days)`
- 系统可以接受任意数量的数据源,包括混合常规数据与重新采样和/或重放数据。当然,其中一些组合肯定毫无意义,因此在能够组合数据时会应用一些限制:时间对齐。请参阅数据-多时间框架、数据重新采样-重新采样和数据-重播部分。
- 添加
Strategies
与已经是类实例的数据源
不同,cerebro
直接接受Strategy
类和传递给它的参数。背后的原理是:在优化场景中,该类将被实例化多次并传递不同的参数
即使没有运行优化,该模式仍然适用:
cerebro.addstrategy(MyStrategy, myparam1=value1, myparam2=value2)`
- 当优化参数时,必须添加为可迭代对象。详细说明请参见优化部分。基本模式:
cerebro.optstrategy(MyStrategy, myparam1=range(10, 20))`
- 运行
MyStrategy
10 次,其中myparam1
的值从 10 到 19(请记住,Python 中的范围是半开放的,20
不会被包含) - 其他元素还有一些其他元素可以添加以增强回测体验。查看相应的部分以了解详情。方法包括:
addwriter
addanalyzer
addobserver
(或addobservermulti
)
- 更改经纪人
Cerebro 将在backtrader
中使用默认经纪人,但可以被覆盖:
broker = MyBroker() cerebro.broker = broker # property using getbroker/setbroker methods`
- 接收通知如果数据源和/或经纪人发送通知(或创建它们的存储提供程序),它们将通过
Cerebro.notify_store
方法接收。有三(3)种处理这些通知的方法
- 通过
addnotifycallback(callback)
调用向cerebro
实例添加回调。回调函数必须支持此签名:
callback(msg, *args, **kwargs)`
- 实际的
msg
、*args
和**kwargs
接收的内容是实现定义的(完全取决于数据/经纪人/存储),但一般可以期望它们是可打印的,以便接收和实验。
- 在添加到
cerebro
实例的Strategy
子类中覆盖notify_store
方法。
- 签名:
notify_store(self, msg, *args, **kwargs)
- 子类
Cerebro
并覆盖notify_store
(与Strategy
中的签名相同)
- 这应该是最不受欢迎的方法
执行回测
有一个单一的方法可以做到这一点,但它支持几个选项(也可以在实例化时指定),以决定如何运行:
result = cerebro.run(**kwargs)
请参阅下面的参考文献,了解可用的参数。
标准观察者
cerebro
(除非另有说明)会自动实例化三个标准观察者
- 一个Broker观察者,用于跟踪
cash
和value
(投资组合) - 一个Trades观察者,应显示每次交易的有效性如何
- 一个Buy/Sell观察者,应记录操作何时执行
如果希望更干净的绘图,只需使用stdstats=False
禁用它们
返回结果
cerebro
在回测期间返回所创建的策略实例。这允许分析它们的操作,因为可以访问策略中的所有元素:
result = cerebro.run(**kwargs)
由run
返回的result
的格式取决于是否使用了优化(使用optstrategy
添加了一个策略):
- 所有使用
addstrategy
添加的策略result
将是在回测期间运行的实例的list
- 使用
optstrategy
添加了 1 个或多个策略result
将是list
的list
。每个内部列表将包含每次优化运行后的策略
注意
优化的默认行为已更改为仅返回系统中存在的分析器,以减轻跨计算机核心的消息传递负担。
如果希望返回完整的策略集,请将参数optreturn
设置为False
提供对绘图功能的访问
如果安装了matplotlib
,则可以绘制策略图。通常的模式是:
cerebro.plot()
请参阅下文的参考文献和绘图部分
回测逻辑
事物流程的简要概述:
- 传递任何存储通知
- 要求数据源提供下一组 ticks/bars
**版本更改:**版本 1.9.0.99 中已更改:新行为
数据源通过查看下一个将提供的datetime来同步。在新周期中尚未交易的数据源仍提供旧数据点,而具有新数据的数据源则提供此数据(以及指标的计算)
旧行为(在Cerebro中使用oldsync=True
时保留)
第 1 个插入系统的数据是datamaster
,系统将等待它提供一个 tick
其他数据源或多或少是datamaster
的从属,且:
* If the next tick to deliver is newer (datetime-wise) than the one delivered by the `datamaster` it will not be delivered * May return without delivering a new tick for a number of reasons`
- 逻辑被设计为轻松同步多个数据源和具有不同时间框架的数据源
- 通知策略有关已排队的经纪人订单、交易和现金/价值的通知
- 告诉经纪人接受排队的订单,并使用新数据执行待处理的订单
- 调用策略的
next
方法以使策略评估新数据(并可能发出在经纪人中排队的订单)
根据阶段,策略/指标的最小周期要求可能在满足之前是prenext
还是nextstart
。
在内部,策略还会触发observers
、indicators
、analyzers
和其他活动元素 - 告诉任何
writers
将数据写入其目标
注意:
注意
在上述第 1
步中,当 数据源 传递新的柱集时,这些柱是 关闭 的。 这意味着数据已经发生了。
因此,在第 4
步中策略发出的 订单 无法使用第 1
步的数据 执行。
这意味着订单将使用 x + 1
的概念执行。 其中 x
是订单执行的柱时刻,而 x + 1
是下一个,它是可能的订单执行的最早时刻
参考
类 backtrader.Cerebro()
参数:
preload
(默认:True
)
是否预加载传递给 cerebro 的不同 data feeds
用于策略
runonce
(默认:True
)
在向量化模式下运行 Indicators
以加速整个系统。 策略和观察器将始终基于事件运行。
live
(默认:False
)
如果没有数据通过数据的 islive
方法报告自身为 live,但最终用户仍希望以 live
模式运行,可以将此参数设置为 true
这将同时停用 preload
和 runonce
。 对内存节省方案没有影响。
在向量化模式下运行 Indicators
以加速整个系统。 策略和观察器将始终基于事件运行。
maxcpus
(默认:无->所有可用核心)
同时使用多少核心进行优化stdstats
(默认:True
)
如果为 True,默认观察者将被添加:经纪人(现金和价值)、交易和买卖
oldbuysell
(默认:False
)
如果 stdstats
为 True
并且观察者自动添加,则此开关控制 BuySell
观察者的主要行为
False
:使用现代行为,在低/高价格的下方/上方分别绘制买入/卖出信号,以避免图表混乱True
:使用已弃用的行为,在给定时刻的订单执行的平均价格绘制买入/卖出信号。 这当然会在 OHLC 柱或 Cloe 柱上方绘制,难以识别图的内容。oldtrades
(默认:False
)
如果 stdstats
为 True
并且观察者自动添加,则此开关控制 Trades
观察者的主要行为
False
:使用现代行为,其中所有数据的交易都用不同的标记绘制True
:使用旧的交易观察器,它使用相同的标记绘制交易,仅在它们是正数还是负数时有所区别。exactbars
(默认:False
)
默认情况下,每个值都会存储在内存中的一行中。
可能的值:
* `True` or `1`: all “lines” objects reduce memory usage to the automatically calculated minimum period. If a Simple Moving Average has a period of 30, the underlying data will have always a running buffer of 30 bars to allow the calculation of the Simple Moving Average * This setting will deactivate `preload` and `runonce` * Using this setting also deactivates **plotting** * `-1`: datafreeds and indicators/operations at strategy level will keep all data in memory. For example: a `RSI` internally uses the indicator `UpDay` to make calculations. This subindicator will not keep all data in memory * This allows to keep `plotting` and `preloading` active. * `runonce` will be deactivated * `-2`: data feeds and indicators kept as attributes of the strategy will keep all points in memory. For example: a `RSI` internally uses the indicator `UpDay` to make calculations. This subindicator will not keep all data in memory If in the `__init__` something like `a = self.data.close - self.data.high` is defined, then `a` will not keep all data in memory * This allows to keep `plotting` and `preloading` active. * `runonce` will be deactivated
objcache
(默认:False
)
实验选项,用于实现线条对象的缓存并减少它们的数量。从 UltimateOscillator 示例:
bp = self.data.close - TrueLow(self.data) tr = TrueRange(self.data) # -> creates another TrueLow(self.data)
如果这是True
,则TrueRange
内的第 2 个TrueLow(self.data)
将与bp
计算中的签名匹配。它将被重用。
边缘情况可能会发生,其中这会使线条对象超出其最小周期并且导致故障,因此已禁用。
writer
(默认:False
)
如果设置为True
,将创建一个默认的 WriterFile,它将打印到 stdout。它将被添加到策略中(除了用户代码添加的任何其他写入器)
tradehistory
(默认:False
)
如果设置为True
,它将激活每个策略的每次交易的更新事件记录。这也可以通过策略方法set_tradehistory
逐个策略地完成。
optdatas
(默认:True
)
如果为True
且正在优化(并且系统可以preload
并使用runonce
,数据预加载将仅在主进程中执行一次,以节省时间和资源。
测试显示,从在83
秒的样本执行中移动到66
秒的执行速度提高了约20%
。
optreturn
(默认:True
)
如果为True
,则优化结果将不是完整的Strategy
对象(以及所有datas、indicators、observers…),而是具有以下属性的对象(与Strategy
中相同):
* `params` (or `p`) the strategy had for the execution * `analyzers` the strategy has executed
在大多数情况下,只有分析器和与之相关的参数是评估策略性能所需的内容。如果需要对生成的值(例如指标)进行详细分析,则关闭此选项。
测试显示执行时间提高了13% - 15%
。与optdatas
结合使用,总增益增加到了优化运行的32%
的总体加速。
oldsync
(默认:False
)
从版本 1.9.0.99 开始,多个数据的同步(相同或不同的时间框架)已更改为允许长度不同的数据。
如果希望保留旧的行为,并将 data0 设置为系统的主要数据,则将此参数设置为 true。
tz
(默认:None
)
为策略添加全局时区。参数tz
可以是
* `None`: in this case the datetime displayed by strategies will be in UTC, which has been always the standard behavior * `pytz` instance. It will be used as such to convert UTC times to the chosen timezone * `string`. Instantiating a `pytz` instance will be attempted. * `integer`. Use, for the strategy, the same timezone as the corresponding `data` in the `self.datas` iterable (`0` would use the timezone from `data0`)
cheat_on_open
(默认:False
)
在调用策略的next_open
方法之前将会调用它。这发生在next
之前,也发生在经纪人有机会评估订单之前。指标尚未重新计算。这允许发出一个订单,该订单考虑了前一天的指标,但使用open
价格进行股份计算。
对于cheat_on_open
订单执行,还需要调用cerebro.broker.set_coo(True)
或使用BackBroker(coo=True)
实例化一个经纪人(其中coo代表 cheat-on-open),或者将broker_coo
参数设置为True
。除非在下面禁用,否则 Cerebro 将自动执行此操作。
broker_coo
(默认:True
)
这将自动调用经纪人的set_coo
方法,并使用True
来激活cheat_on_open
执行。仅当cheat_on_open
也为True
时才执行。
quicknotify
(默认值:False
)
经纪人通知将在下一个价格传递之前立即传递。 对于回测,这没有任何影响,但对于实时经纪人,通知可能会在交付柱形图之前很久就发生了。 当设置为 True
时,通知将尽快传递(请参阅实时数据源中的 qcheck
)
设置为 False
以实现兼容性。 可能会更改为 True
addstorecb(callback)
添加一个回调来获取将由 notify_store 方法处理的消息
回调函数的签名必须支持以下内容:
callback(msg, *args, **kwargs)
实际接收到的 msg
、*args
和 **kwargs
取决于实现(完全依赖于 数据/经纪人/存储),但通常应该期望它们是可打印的,以便接收和实验。
notify_store(msg, *args, **kwargs)
在 cerebro 中接收存储通知
此方法可以在 Cerebro
的子类中重写
如果 name
不为 None,则将其放入 data._name
中,该参数用于装饰/绘图目的。
adddatacb(callback)
adddata(data, name=None)
向获取将由 notify_data 方法处理的消息添加一个回调
- callback(data, status, *args, **kwargs)
实际接收到的 *args
和 **kwargs
取决于实现(完全依赖于 数据/经纪人/存储),但通常应该期望它们是可打印的,以便接收和实验。
实际接收到的 msg
、*args
和 **kwargs
取决于实现(完全依赖于 数据/经纪人/存储),但通常应该期望它们是可打印的,以便接收和实验。
在 cerebro 中接收数据通知
此方法可以在 Cerebro
的子类中重写
回调函数的签名必须支持以下内容:
notify_data(data, status, *args, **kwargs)
向组合中添加一个 Data Feed
实例。
添加一个 callback
来获取将由 notify_store 方法处理的消息
resampledata(dataname, name=None, **kwargs)
向系统添加一个将由系统重新采样的 Data Feed
如果 name
不为 None,则将其放入 data._name
中,该参数用于装饰/绘图目的。
任何其他支持重新采样过滤器的 kwargs,如 timeframe
、compression
、todate
,都将被透明地传递
replaydata(dataname, name=None, **kwargs)
向系统添加一个将由系统重播的 Data Feed
如果 name
不为 None,则将其放入 data._name
中,该参数用于装饰/绘图目的。
任何其他支持回放过滤器的 kwargs,如 timeframe
、compression
、todate
,都将被透明地传递
chaindata(*args, **kwargs)
将几个数据源串联成一个
如果 name
被传递为命名参数且不为 None,则将其放入 data._name
中,该参数用于装饰/绘图目的。
如果为 None
,则将使用第 1 个数据的名称
rolloverdata(*args, **kwargs)
将几个数据源链接到一个数据源中
如果将 name
作为命名参数传递,并且不为 None,则将放入 data._name
中,用于装饰/绘图目的。
如果为 None
,则将使用第 1 个数据的名称
任何其他的 kwargs 将传递给 RollOver 类
addstrategy(strategy, *args, **kwargs)
将 Strategy
类添加到混合中,以进行单次运行。实例化将在运行
时发生。
args 和 kwargs 将像在实例化期间一样传递给策略。
返回用于引用其他对象(如调整器)的添加索引
optstrategy(strategy, *args, **kwargs)
将 Strategy
类添加到混合中以进行优化。实例化将在运行
时发生。
args 和 kwargs 必须是可迭代的,其中包含要检查的值。
示例:如果一个策略接受一个参数 period
,为了优化目的,optstrategy
的调用如下所示:
- cerebro.optstrategy(MyStrategy, period=(15, 25))
这将为值 15 和 25 执行优化。而
- cerebro.optstrategy(MyStrategy, period=range(15, 25))
将使用 period
值 15 -> 25(因为 Python 中的范围是半开放的,所以不包括 25)执行 MyStrategy
如果传递了一个参数,但不应该进行优化,则调用如下:
- cerebro.optstrategy(MyStrategy, period=(15,))
请注意,period
仍然传递为可迭代对象 … 只有 1 个元素
backtrader
将尝试识别诸如以下情况:
- cerebro.optstrategy(MyStrategy, period=15)
并在可能的情况下创建内部伪可迭代对象
optcallback(cb)
将 callback 添加到将在每个策略运行时调用的回调列表中进行优化
签名:cb(strategy)
addindicator(indcls, *args, **kwargs)
将 Indicator
类添加到混合中。实例化将在传递的策略的运行
时完成
addobserver(obscls, *args, **kwargs)
将 Observer
类添加到混合中。实例化将在运行
时完成
addobservermulti(obscls, *args, **kwargs)
将 Observer
类添加到混合中。实例化将在运行
时完成
它将每个“数据”系统中添加一次。一个用例是观察单个数据的买入/卖出观察者。
反例是 CashValue,它观察系统范围的值
addanalyzer(ancls, *args, **kwargs)
将 Analyzer
类添加到混合中。实例化将在运行
时完成
addwriter(wrtcls, *args, **kwargs)
将 Writer
类添加到混合中。实例化将在运行
时在 cerebro 中完成
run(**kwargs)
执行回测的核心方法。传递给它的任何 kwargs
都会影响实例化时 Cerebro
的标准参数的值。
如果 cerebro
没有数据,则该方法将立即退出。
它具有不同的返回值:
- 对于无优化:包含使用
addstrategy
添加的策略类实例的列表 - 用于优化:包含使用
addstrategy
添加的 Strategy 类实例的列表的列表
runstop()
如果从策略内部或其他任何地方调用,包括其他线程,执行将尽快停止。
setbroker(broker)
为此策略设置特定的broker
实例,替换从 cerebro 继承的实例。
getbroker()
返回经纪人实例。
这也可以作为名为broker
的property
使用
绘图(plotter=None,numfigs=1,iplot=True,start=None,end=None,width=16,height=9,dpi=300,tight=True,use=None,**kwargs)
在 cerebro 内部绘制策略
如果plotter
为 None,则会创建一个默认的Plot
实例,并在实例化期间将kwargs
传递给它。
numfigs
将绘图分成指定数量的图表,如果需要,可以减少图表密度
iplot
:如果为True
并在notebook
中运行,则图表将内联显示
use
:将其设置为所需 matplotlib 后端的名称。它将优先于iplot
start
:策略或datetime.date
、datetime.datetime
实例的日期时间线数组的索引,指示绘图的开始
end
:策略的日期时间线数组的索引或datetime.date
、datetime.datetime
实例,指示绘图的结束
width
:保存图形的英寸
height
:保存图形的英寸
dpi
:保存图形的每英寸点数的质量
tight
:仅保存实际内容而不是图形的框架
添加 sizer(sizercls,*args,**kwargs)
添加一个Sizer
类(和 args),它是添加到 cerebro 的任何策略的默认 sizer
addsizer_byidx(idx,sizercls,*args,**kwargs)
按 idx 添加一个Sizer
类。此 idx 是与addstrategy
返回的兼容引用。只有由idx
引用的策略将接收此大小
add_signal(sigtype,sigcls,*sigargs,**sigkwargs)
向系统添加一个信号,稍后将其添加到SignalStrategy
中。
signal_concurrent(onoff)
如果向系统添加信号并且将concurrent
值设置为 True,则将允许并发订单
signal_accumulate(onoff)
如果向系统添加信号并且将accumulate
值设置为 True,则在已经进入市场时进入市场,将允许增加头寸
signal_strategy(stratcls,*args,**kwargs)
添加一个可以接受信号的 SignalStrategy 子类
addcalendar(cal)
向系统添加全局交易日历。个别数据源可能具有覆盖全局日历的单独日历
cal
可以是TradingCalendar
的实例、字符串或pandas_market_calendars
的实例。字符串将被实例化为PandasMarketCalendar
(需要系统中安装pandas_market_calendar
模块。
如果传递的是 TradingCalendarBase 的子类(而不是实例),它将被实例化
BackTrader 中文文档(二)(4)https://developer.aliyun.com/article/1489219