BackTrader 中文文档(十一)(2)https://developer.aliyun.com/article/1505309
实际 Sizer 应用
在不考虑复杂的大小算法的情况下,可以使用两个不同的 Sizer 将策略从单向变为双向。只需在 cerebro 执行中更改 Sizer,策略就会改变行为。一个非常简单的 close
穿越 SMA
算法:
class CloseSMA(bt.Strategy): params = (('period', 15),) def __init__(self): sma = bt.indicators.SMA(self.data, period=self.p.period) self.crossover = bt.indicators.CrossOver(self.data, sma) def next(self): if self.crossover > 0: self.buy() elif self.crossover < 0: self.sell()
注意策略不考虑当前的 持仓(通过查看 self.position
)来决定是否实际执行 买入 或 卖出。只考虑 CrossOver
的 信号。 Sizers 将负责一切。
这个尺寸器将在已经开仓的情况下仅在卖出时返回 非零 大小:
class LongOnly(bt.Sizer): params = (('stake', 1),) def _getsizing(self, comminfo, cash, data, isbuy): if isbuy: return self.p.stake # Sell situation position = self.broker.getposition(data) if not position.size: return 0 # do not sell if nothing is open return self.p.stake
将所有内容放在一起(并假设 backtrader 已经被导入并且一个 data 已经被添加到系统中):
... cerebro.addstrategy(CloseSMA) cerebro.addsizer(LongOnly) ... cerebro.run() ...
图表(从源代码中包含的示例中获取)。
简单地将 Sizer 更改为上面显示的 FixedReverser
即可获得 长-短 版本:
... cerebro.addstrategy(CloseSMA) cerebro.addsizer(FixedReverser) ... cerebro.run() ...
输出图表。
注意区别:
- 交易数量已经翻了一番
- 现金水平永远不会回到值,因为策略总是处于市场中
两种方法都是负面的,但这只是一个例子。
bt.Sizer 参考
类 backtrader.Sizer()
这是Sizers的基类。任何sizer都应该是这个的子类,并覆盖_getsizing
方法
成员属性:
strategy
:将由工作在其中的调整器的策略设置
提供了策略的整个 api 访问权限,例如如果在_getsizing
中需要实际数据位置:
position = self.strategy.getposition(data)`
broker
:将由工作在其中的 Sizer 的策略设置
提供了一些复杂调整器可能需要的信息,如投资组合价值,…
_getsizing(comminfo, cash, data, isbuy)
这个方法必须被 Sizer 的子类覆盖,以提供大小调整功能
参数:
* `comminfo`: The CommissionInfo instance that contains information about the commission for the data and allows calculation of position value, operation cost, commision for the operation * `cash`: current available cash in the *broker* * `data`: target of the operation * `isbuy`: will be `True` for *buy* operations and `False` for *sell* operations
该方法必须返回要执行的实际大小(一个整数)。如果返回0
,则不会执行任何操作。
返回值的绝对值将被使用
调整器参考
FixedSize
类 backtrader.sizers.FixedSize()
这个调整器只是为任何操作返回一个固定的大小。大小可以通过系统希望使用的分期数量来控制,方法是通过指定tranches
参数来缩放到交易中。
参数:
* `stake` (default: `1`) * `tranches` (default: `1`)
FixedReverser
类 backtrader.sizers.FixedReverser()
这个调整器返回需要的固定大小以反转开仓位置或开仓大小。
- 开仓位置:返回参数
stake
。 - 反转仓位:返回 2 *
stake
。
参数:
* `stake` (default: `1`)
PercentSizer
类 backtrader.sizers.PercentSizer()
这个调整器返回可用现金的百分比。
参数:
* `percents` (default: `20`)
AllInSizer
类 backtrader.sizers.AllInSizer()
这个调整器返回经纪人的所有可用现金。
参数:
* `percents` (default: `100`)
PercentSizerInt
类 backtrader.sizers.PercentSizerInt()
这个调整器以截断为整数的形式返回可用现金的百分比。
参数:
* `percents` (default: `20`)
AllInSizerInt
类 backtrader.sizers.AllInSizerInt()
这个调整器将经纪人的所有可用现金返回,并将大小截断为整数。
参数:
* `percents` (default: `100`)
实时交易
实时数据源和实时交易
从版本 1.5.0 开始,backtrader
支持实时数据和实时交易。
- 交互经纪商
- 可视化图表
- Oanda
交互式经纪人
与交互式经纪人的集成支持两种:
- 实时数据提供
- 实时交易
注意
尽管尝试测试尽可能多的错误条件和情况,但代码可能(像任何其他软件一样)包含错误。
在进入生产之前,彻底测试任何策略都使用模拟交易帐户或 TWS 演示。
注意
使用IbPy
模块进行与交互式经纪人的交互必须事先安装。在写作时,Pypi 中没有包,但可以使用以下命令使用pip
进行安装:
pip install git+https://github.com/blampe/IbPy.git
如果您的系统中没有git
可用(Windows 安装?),则以下内容也应该有效:
pip install https://github.com/blampe/IbPy/archive/master.zip
示例代码
源代码包含完整的示例:
- samples/ibtest/ibtest.py
示例不能涵盖每种可能的用例,但它试图提供广泛的见解,并应该突出显示在使用回测模块或实时数据模块时没有真正的区别
有一件事可以确定:
- 示例在进行任何交易活动之前等待
data.LIVE
数据状态通知。
这可能是在任何实时策略中考虑的事情
商店模型 vs 直接模型
与交互式经纪人的交互支持通过 2 种模式:
- 商店模型(首选)
- 与数据源类和经纪人类的直接交互
商店模型在创建经纪人和数据源时提供了清晰的分离模式。两个代码片段应该更好地作为示例。
首先是Store模型:
import backtrader as bt ibstore = bt.stores.IBStore(host='127.0.0.1', port=7496, clientId=35) data = ibstore.getdata(dataname='EUR.USD-CASH-IDEALPRO')
这里是参数:
host
、port
和clientId
被传递到它们所属的地方IBStore
,该地方使用这些参数打开连接。
然后使用getdata
创建一个与backtrader中所有数据源共用的数据源。
dataname
请求EUR/USD外汇对。
现在可以直接使用了:
import backtrader as bt data = bt.feeds.IBData(dataname='EUR.USD-CASH-IDEALPRO', host='127.0.0.1', port=7496, clientId=35)
这里:
- 用于商店的参数被传递给数据。
- 这些将用于在后台创建
IBStore
实例
缺点:
- 清晰度大大降低,因为不清楚什么属于数据,什么属于商店。
IBStore - 商店
商店是实时数据源/交易支持的关键,提供了一个在IbPy
模块和数据源和经纪人代理的需求之间的适应层。
商店是一个涵盖以下功能的概念:
- 作为一个实体的中心商店:在这种情况下,实体是 IB。
这可能需要或不需要参数 - 提供通过该方法获取经纪人实例的访问权限:
IBStore.getbroker(*args, **kwargs)
- 提供获取数据源实例的访问权限
IBStore.getdata(*args, **kwargs)
- 在这种情况下,许多
**kwargs
与数据源相同,如dataname
、fromdate
、todate
、sessionstart
、sessionend
、timeframe
、compression
数据可能提供其他参数。请查看下面的参考资料。
IBStore
提供:
- 连接目标(
host
和port
参数) - 标识(
clientId
参数) - 重新连接控制(
reconnect
和timeout
参数) - 时间偏移检查(
timeoffset
参数,请参见下文) - 通知和调试
notifyall
(默认:False
):在这种情况下,IB 发送的任何错误消息(许多只是信息性的)都将被转发给Cerebro/Strategy_debug
(默认:False
):在这种情况下,从 TWS 收到的每条消息都将打印到标准输出
IBData 数据源
数据选项
无论是直接还是通过 getdata
,IBData
数据源支持以下数据选项:
- 历史下载请求
如果持续时间超过 IB 对于给定时间框架/压缩组合施加的限制,这些将分成多个请求 - 3 种实时数据
tickPrice
事件(通过 IBreqMktData
)
- 用于CASH产品(至少 TWS API 9.70 的实验表明不支持其他类型)
通过查看BID
价格接收tick价格事件,根据非官方互联网文献,这似乎是跟踪CASH
市场价格的方法。
时间戳是在系统中本地生成的。如果用户希望,可以使用与 IB 服务器时间的偏移量(从 IBreqCurrentTime
计算)
tickString
事件(又名RTVolume
(通过 IBreqMktData
))
- 大约每 250 毫秒从 IB 接收一个OHLC/Volume快照(如果没有发生交易,则间隔可能更长)
RealTimeBars
事件(通过 IBreqRealTimeBars
)
- 每 5 秒接收历史数据条(由 IB 固定持续时间)
如果所选的时间框架/组合低于秒/5级别,此功能将自动禁用。
!!! 注意
`RealTimeBars` do not work with the TWS Demo`
- 默认行为是在大多数情况下使用:
tickString
,除非用户明确希望使用RealTimeBars
Backfilling
除非用户要求只进行历史下载,否则数据源将自动进行回填:
- 在开始时:使用最大可能的持续时间。例如:对于天/1(时间框架/压缩)组合,IB 的最大默认持续时间是1 年,这是将进行回填的时间量
- 在数据断开连接后:在这种情况下,用于回填操作的数据量将通过查看断开连接前接收的最新数据来减少。
注意
请注意,最终考虑的时间框架/压缩组合可能不是在数据源创建期间指定的,而是在系统中插入期间指定的。请参见以下示例:
data = ibstore.getdata(dataname='EUR.USD-CASH-IDEALPRO', timeframe=bt.TimeFrame.Seconds, compression=5) cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=2)
如现在应该清楚的是,最终考虑的时间框架/压缩组合是分钟/2
数据合同检查
在启动阶段,数据源将尝试下载指定合同的详细信息(查看如何指定的参考资料)。如果找不到这样的合同或找到多个匹配项,则数据将拒绝继续并将其通知系统。一些例子。
简单但明确的合同规范:
data = ibstore.getdata(dataname='TWTR') # Twitter
只会找到一个实例(2016-06),因为对于默认类型STK
、交易所SMART
和货币(默认为空)的单一合同交易将被找到。
使用AAPL
的类似方法会失败:
data = ibstore.getdata(dataname='AAPL') # Error -> multiple contracts
因为SMART
可以在几个真实交易所找到合同,并且AAPL
在其中一些交易所以不同的货币交易。以下是可以的:
data = ibstore.getdata(dataname='AAPL-STK-SMART-USD') # 1 contract found
数据通知
数据源将通过以下一种或多种方式报告当前状态(查看Cerebro和Strategy参考资料)
Cerebro.notify_data
(如果重写)- 使用
Cerebro.adddatacb
添加回调 Strategy.notify_data
(如果重写)
在strategy内部的一个例子:
class IBStrategy(bt.Strategy): def notify_data(self, data, status, *args, **kwargs): if status == data.LIVE: # the data has switched to live data # do something pass
系统发生更改后,将发送以下通知:
CONNECTED
成功初始连接时发送DISCONNECTED
在这种情况下,不再能够检索数据,并且数据将指示系统无法执行任何操作。可能的条件:
- 指定的合同有误
- 在历史下载期间中断
- 尝试重新连接到 TWS 的次数已超过限制
CONNBROKEN
与 TWS 或数据中心的连接已断开。数据源将尝试(通过存储)重新连接和回溯填充,必要时,并恢复操作NOTSUBSCRIBED
合同和连接都正常,但由于权限不足,无法检索数据。
数据将向系统指示无法检索数据DELAYED
表示正在进行历史/回溯操作,并且由策略处理的数据不是实时数据LIVE
表示从此处开始由strategy处理的数据是实时数据
策略的开发者应该考虑在发生断开连接或接收延迟数据等情况时要采取哪些行动。
数据时间框架和压缩
backtrader生态系统中的数据源,在创建时支持timeframe
和compression
参数。这些参数也可以通过data._timeframe
和data._compression
属性访问
timeframe/compression组合的重要性在将数据通过resampledata
或replaydata
传递给cerebro
实例时具有特定目的,以便内部重新采样器/重播器对象了解预期目标是什么。当重新采样/重播时,._timeframe
和._compression
将在数据中被覆盖。
但在另一方面,对于实时数据源,这些信息可能起重要作用。请参阅以下示例:
data = ibstore.getdata(dataname='EUR.USD-CASH-IDEALPRO', timeframe=bt.TimeFrame.Ticks, compression=1, # 1 is the default rtbar=True, # use RealTimeBars ) cerebro.adddata(data)
用户正在请求tick数据,这很重要,因为:
- 不会进行回溯填充(IB 支持的最小单位是Seconds/1)
- 即使请求和支持
dataname
的RealTimeBars
,也不会使用,因为RealTimeBar
的最小分辨率是Seconds/5
无论如何,除非使用Ticks/1的分辨率,否则数据必须进行重新采样/重播。上述情况下与实时条和工作:
data = ibstore.getdata(dataname='TWTR-STK-SMART', rtbar=True) cerebro.resampledata(data, timeframe=bt.TimeFrame.Seconds, compression=20)
在这种情况下,并且如上所述,在resampledata
期间将覆盖数据的._timeframe
和._compression
属性。这是会发生的事情:
- 将会发生回溯填充,请求分辨率为Seconds/20
RealTimeBars
将用于实时数据,因为分辨率等于/大于Seconds/5且数据支持(不是CASH产品)- TWS 发送给系统的事件最多每 5 秒发生一次。这可能不重要,因为系统每 20 秒只向策略发送一个条。
没有RealTimeBars
的情况下相同:
data = ibstore.getdata(dataname='TWTR-STK-SMART') cerebro.resampledata(data, timeframe=bt.TimeFrame.Seconds, compression=20)
在这种情况下:
- 将会发生回溯填充,请求分辨率为Seconds/20
tickString
将用于实时数据,因为(不是CASH产品)- TWS 发送给系统的事件最多每 250 毫秒发生一次。这可能不重要,因为系统每 20 秒只向策略发送一个条。
最后,对于CASH产品和最多 20 秒:
data = ibstore.getdata(dataname='EUR.USD-CASH-IDEALPRO') cerebro.resampledata(data, timeframe=bt.TimeFrame.Seconds, compression=20)
在这种情况下:
- 将会发生回溯填充,请求分辨率为Seconds/20
tickPrice
将用于实时数据,因为这是现金产品
即使添加了rtbar=True
- TWS 发送给系统的事件最多每 250 毫秒发生一次。这可能不重要,因为系统每 20 秒只向策略发送一个条。
时间管理
数据源将自动从TWS报告的ContractDetails
对象中确定时区。
注意
这要求安装pytz
。如果未安装,则用户应为数据源的tz
参数提供与所需输出时区兼容的tzinfo
实例
注意
如果安装了pytz
并且用户认为自动时区确定不起作用,则tz
参数可以包含一个时区名称的字符串。backtrader
将尝试使用给定名称实例化一个pytz.timezone
报告的datetime
将是与产品相关的时区的时间。一些示例:
- 产品: 欧洲证券交易所的 EuroStoxxx 50(股票代码:ESTX50-YYYYMM-DTB)
时区将是CET
(中欧时间),又名Europe/Berlin
- 产品: ES-Mini(股票代码:ES-YYYYMM-GLOBEX)
时区将是EST5EDT
,又名EST
,又名US/Eastern
- 产品: EUR.JPY 外汇对(股票代码EUR.JPY-CASH-IDEALPRO)
时区将是EST5EDT
,又名EST
,又名US/Eastern
实际上这是一个交互式经纪商的设置,因为外汇交易几乎连续 24 小时进行,因此对于它们不会有真正的时区。
这种行为确保交易保持一致,无论交易者的实际位置如何,因为计算机很可能具有实际位置的时区,而不是交易场所的时区。
请阅读手册的时间管理部分。
注意
TWS Demo 在没有数据下载权限的资产的时区报告方面并不准确(欧洲斯托克 50 期货就是这种情况的一个例子)
BackTrader 中文文档(十一)(4)https://developer.aliyun.com/article/1505311