BackTrader 中文文档(十一)(3)https://developer.aliyun.com/article/1505310
实时数据源和重采样/重播
关于何时为实时数据源交付条的设计决策是:
- 尽可能实时地交付它们
这可能看起来很明显,对于Ticks
的时间框架来说是这样,但如果重采样/重播起作用,延迟可能会发生。用例:
- 重采样配置为Seconds/5,具有:
cerebro.resampledata(data, timeframe=bt.TimeFrame.Seconds, compression=5)`
- 一个时间为
23:05:27.325000
的 tick 被交付 - 在市场上交易速度很慢,下一个 tick 将在
23:05:59.025000
时到达
也许并不明显,但backtrader并不知道交易速度非常慢,下一个 tick 大约会在32
秒后到来。如果没有适当的措施,一个时间为23:05:30.000000
的重采样条可能会被延迟约29 秒
。
这就是为什么实时数据源每隔x
秒(float值)唤醒一次重采样器/重播器并让它知道没有新数据输入。这是在创建实时数据源时通过参数qcheck
(默认值:0.5
秒)来控制的。
这意味着重采样器每隔qcheck
秒就有机会交付一个条,如果本地时钟显示,重采样周期已经结束。这样一来,上述情景(23:05:30.000000
)的重采样条最多会在报告时间后qcheck
秒交付。
因为默认值是0.5
,所以最晚时间是:23:05:30.500000
。几乎比以前早了 29 秒。
缺点:
- 有些 tick 可能会对已经交付的重采样/重播的条造成延迟
如果在交付后,TWS 从服务器收到一个时间戳为23:05:29.995\
000的延迟消息,这对于已经向系统报告的时间
23:05.30.000000`来说就太晚了
这通常发生在以下情况下:
timeoffset
在IBStore\
中被禁用(设置为False
),IB报告的时间与本地时钟的时间差很大。
避免大部分延迟样本的最佳方法是:
- 增加
qcheck
值,以考虑延迟消息:
data = ibstore.getdata('TWTR', qcheck=2.0, ...)`
这应该增加额外的空间,即使延迟了重采样/重播条的交付
注意
当然,对于Seconds/5的重采样来说,2.0 秒的延迟意义不同于Minutes/10的重采样
如果由于某种原因,最终用户希望禁用timeoffset
并且不通过qcheck
进行管理,则仍然可以接受延迟样本:
- 在
getdata
/IBData
的参数中设置_latethrough
为True
:
data = ibstore.getdata('TWTR', _latethrough=True, ...)`
- 在重采样/重播时设置
takelate
为True
:
cerebro.resampledata(data, takelate=True)`
IBBroker - 实时交易
注意
在backtrader中的经纪人模拟中实现了tradeid
功能。这允许正确地跟踪在同一资产上并行执行的交易,并将佣金正确地分配给适当的tradeid
此概念在此实时经纪人中不受支持,因为佣金是由经纪人报告的,而在某些情况下,不可能将其分离为不同的tradeid
值。
tradeid
仍然可以指定,但不再有意义。
使用经纪人
要使用IB Broker,必须替换由cerebro创建的标准经纪人模拟实例。
使用Store模型(首选):
import backtrader as bt cerebro = bt.Cerebro() ibstore = bt.stores.IBStore(host='127.0.0.1', port=7496, clientId=35) cerebro.broker = ibstore.getbroker() # or cerebro.setbroker(...)
使用直接方法:
import backtrader as bt cerebro = bt.Cerebro() cerebro.broker = bt.brokers.IBBroker(host='127.0.0.1', port=7496, clientId=35)
经纪人参数
不管是直接还是通过getbroker
,IBBroker
经纪人都不支持任何参数。这是因为经纪人只是一个真实经纪人的代理。真实经纪人给予的,不应被剥夺。
一些限制
现金和价值报告
当内部的backtrader经纪人模拟在调用策略的next
方法之前对value
(净清算价值)和cash
进行计算时,无法保证与实时经纪人相同。
- 如果请求了值,则可能会延迟
next
的执行,直到回答到达 - 经纪人可能尚未计算出这些值
backtrader告诉 TWS 在它们更改时提供更新的值(backtrader订阅accounUpdate
消息),但它不知道消息何时到达。
IBBroker
的getcash
和getvalue
方法报告的值始终是从 IB 接收到的最新值。
注意
进一步的限制是,即使有更多货币的值可用,这些值也以帐户的基本货币报告。这是一个设计选择。
位置
backtrader使用 TWS 报告的资产的Position
(价格和大小)。在order execution和order status消息后,内部计算可以被使用,但是如果其中一些消息被错过(套接字有时会丢失数据包),则计算将无法进行。
当然,如果连接到 TWS 时将执行交易的资产已经有一个开放的头寸,由于初始偏移,策略所做的Trades
的计算将不会像通常一样工作
与其进行交易
就标准用法而言,没有变化。只需使用策略中可用的方法(有关完整说明,请参阅Strategy
参考资料)
buy
sell
close
cancel
返回的订单对象
- 与 backtrader 的
Order
对象兼容(在同一层次结构中的子类)
订单执行类型
IB 支持各种执行类型,其中一些由 IB 模拟,一些由交易所本身支持。最初支持哪些订单执行类型的决定有一个动机:
- 与backtrader中可用的经纪人模拟兼容性
这是因为经过回测的内容将会投入生产。
因此,订单执行类型仅限于broker simulation中可用的类型:
Order.Market
Order.Close
Order.Limit
Order.Stop
(当Stop触发时,Market订单跟随)Order.StopLimit
(当Stop触发时,Limit订单跟随)
注意
停止触发是根据不同的策略由 IB 执行的。backtrader不修改默认设置,即为0
:
0 - the default value. The "double bid/ask" method will be used for orders for OTC stocks and US options. All other orders will use the "last" method.
如果用户希望修改此项,可以根据 IB 文档提供的额外**kwargs
向buy
和sell
提供。例如,在策略的next
方法中:
def next(self): # some logic before self.buy(data, m_triggerMethod=2)
这已更改策略为2
(“last”方法,其中停止订单基于最后价格触发)
请参阅 IB API 文档以获取有关停止触发的进一步澄清
订单有效期
在回测期间可用的相同有效性概念(使用valid
来buy
和sell
)也可用,并具有相同的含义。因此,对于以下IB 订单的valid
参数翻译如下:
None -> GTC
(Good Til Cancelled)
因为没有指定有效期,所以理解为订单必须有效直到取消datetime/date
翻译为GTD
(Good Til Date)
传递datetime.datetime/datetime.date
实例表示订单必须有效直到给定时间点。timedelta(x)
翻译为GTD
(这里timedelta(x) != timedelta()
)
这被解释为指示订单从now
+timedelta(x)
开始有效float
翻译为GTD
如果该值来自backtrader使用的原始float日期时间存储,则订单必须有效直到由该float指示的日期时间timedelta() or 0
翻译为DAY
已有一个值(而不是None
),但是为空,被解释为当前day(session)有效的订单
通知
标准的Order
状态将通过方法notify_order
(如果已重写)通知给strategy
Submitted
- 订单已发送到 TWSAccepted
- 订单已下达Rejected
- 订单放置失败或在其生命周期内被系统取消Partial
- 已经部分执行Completed
- 订单已完全执行Canceled
(或Cancelled
)这在 IB 下有几个意思:
- 手动用户取消
- 服务器/交易所取消了订单
- 订单有效期已过期
将应用启发式方法,如果已从 TWS 接收到带有orderState
指示为PendingCancel
或Canceled
的openOrder
消息,则订单将被标记为已过期
已过期
- 请参阅上文的解释
参考
IBStore
类 backtrader.stores.IBStore()
封装一个 ibpy ibConnection 实例的单例类。
参数也可以在使用此存储的类中指定,如IBData
和IBBroker
参数:
host
(默认:127.0.0.1
):IB TWS 或 IB Gateway 实际运行的位置。尽管这通常是本地主机,但不应该是port
(默认值:7496
):连接的端口。演示系统使用7497
clientId
(默认值:None
):要用于连接到 TWS 的客户端 ID。None
:生成 1 到 65535 之间的随机 ID。一个整数
:将作为要使用的值传递。notifyall
(默认值:False
)
如果为False
,则只会将error
消息发送到Cerebro
和Strategy
的notify_store
方法。
如果为True
,则会通知从 TWS 接收到的每条消息_debug
(默认值:False
)
打印从 TWS 接收到的所有消息到标准输出reconnect
(默认值:3
)
在第 1 次连接尝试失败后,尝试重新连接的次数。
将其设置为-1
值以永远保持重新连接timeout
(默认值:3.0
)
重新连接尝试之间的秒数timeoffset
(默认值:True
)
如果为 True,则将从reqCurrentTime
(IB 服务器时间)获得的时间用于计算到本地时间的偏移量,并且此偏移量将用于价格通知(例如用于 CASH 市场的 tickPrice 事件)以修改本地计算的时间戳。
时间偏移将传播到backtrader
生态系统的其他部分,例如重新采样,以使用计算出的偏移量对齐重新采样时间戳。timerefresh
(默认值:60.0
)
秒数:时间偏移量必须刷新的频率indcash
(默认值:True
)
将 IND 代码视为现金进行价格检索
IBBroker
类backtrader.brokers.IBBroker(**kwargs)
用于 Interactive Brokers 的经纪实现。
此类将 Interactive Brokers 的订单/持仓映射到backtrader
的内部 API。
注意
- 实际上不支持
tradeid
,因为利润和损失直接来自 IB。因为(如预期的那样)以 FIFO 方式计算,所以对于tradeid
,利润和损失并不准确。 - 仓位
如果在操作开始时有资产的持仓或通过其他方式给出的订单改变了持仓,那么在cerebro
中计算的交易将不反映现实。
为了避免这种情况,该经纪商将不得不进行自己的持仓管理,这也将允许使用多个 ID 进行交易(利润和损失也将在本地计算),但可能被认为是与实时经纪商合作的目的相悖。
IBData
类backtrader.feeds.IBData(**kwargs)
Interactive Brokers 数据源。
支持参数dataname
中的以下合同规格:
- TICKER # 股票类型和 SMART 交易所
- TICKER-STK # 股票和 SMART 交易所
- TICKER-STK-EXCHANGE # 股票
- TICKER-STK-EXCHANGE-CURRENCY # 股票
- TICKER-CFD # 差价合约和 SMART 交易所
- TICKER-CFD-EXCHANGE # 差价合约
- TICKER-CDF-EXCHANGE-CURRENCY # 股票
- TICKER-IND-EXCHANGE # 指数
- TICKER-IND-EXCHANGE-CURRENCY # 指数
- TICKER-YYYYMM-EXCHANGE # 期货
- TICKER-YYYYMM-EXCHANGE-CURRENCY # 期货
- TICKER-YYYYMM-EXCHANGE-CURRENCY-MULT # 期货
- TICKER-FUT-EXCHANGE-CURRENCY-YYYYMM-MULT # 期货
- TICKER-YYYYMM-EXCHANGE-CURRENCY-STRIKE-RIGHT # 期权
- TICKER-YYYYMM-EXCHANGE-CURRENCY-STRIKE-RIGHT-MULT # 期权
- TICKER-FOP-EXCHANGE-CURRENCY-YYYYMM-STRIKE-RIGHT # 期权组合
- TICKER-FOP-EXCHANGE-CURRENCY-YYYYMM-STRIKE-RIGHT-MULT # 期权组合
- CUR1.CUR2-CASH-IDEALPRO # 外汇
- TICKER-YYYYMMDD-EXCHANGE-CURRENCY-STRIKE-RIGHT # 期权
- TICKER-YYYYMMDD-EXCHANGE-CURRENCY-STRIKE-RIGHT-MULT # 期权
- TICKER-OPT-EXCHANGE-CURRENCY-YYYYMMDD-STRIKE-RIGHT # 期权
- TICKER-OPT-EXCHANGE-CURRENCY-YYYYMMDD-STRIKE-RIGHT-MULT # 期权
Params:
sectype
(默认:STK
)
如果在dataname
规范中未提供证券类型,则应用的默认值exchange
(默认:SMART
)
如果在dataname
规范中未提供交易所,则应用的默认值currency
(默认:''
)
如果在dataname
规范中未提供货币,则应用的默认值historical
(默认:False
)
如果设置为True
,数据源将在第一次下载数据后停止。
将使用标准数据源参数fromdate
和todate
作为参考。
如果请求的持续时间大于由 IB 给定的允许的数据时间段/压缩,则数据源将发出多个请求。what
(默认:None
)如果为None
,则历史数据请求将使用不同资产类型的默认值:
- 对于 CASH 资产,为‘BID’
- 对于任何其他交易
- 如果希望使用另一个值,请查看 IB API 文档
rtbar
(默认:False
)
如果为True
,则将使用由 Interactive Brokers 提供的5 秒实时数据条
作为最小刻度。根据文档,它们对应于实时值(一旦被 IB 整理和筛选)
如果为False
,则将使用基于接收到的刻度的RTVolume
价格。对于CASH
资产(例如 EUR.JPY),将始终使用RTVolume
,并从中获取bid
价格(根据互联网上零散的文献,这是 IB 的行业事实标准)
即使设置为True
,如果数据被重新采样/保留到低于秒/5 的时间段/压缩,也不会使用实时数据,因为 IB 不会在该级别以下提供它们qcheck
(默认:0.5
)
如果未收到数据,等待的时间(秒)以便适当地对数据包进行重新采样/重播并将通知传递给链上backfill_start
(默认:True
)
在开始时执行回填。将在单个请求中获取尽可能多的历史数据。backfill
(默认:True
)
在断开连接/重新连接周期后执行回填。间隙持续时间将用于下载尽可能少的数据backfill_from
(默认:None
)
可以传递附加数据源来进行初始回填。一旦数据源用尽,并且如果需要,将从 IB 进行回填。理想情况下,这意味着从已存储的源(如磁盘上的文件)进行回填,但不限于此。latethrough
(默认:False
)
如果数据源被重采样/重播,一些 ticks 可能来得太晚,已经交付的重采样/重播 bar 了。如果设置为True
,那些 ticks 将无论如何通过。
检查重采样文档以了解如何考虑这些 ticks。
这种情况可能特别发生在IBStore
实例中timeoffset
设置为False
,且 TWS 服务器时间与本地计算机时间不同步时tradename
(默认:None
)对于某些特定情况很有用,比如CFD
,其中价格由一种资产提供,交易发生在另一种资产上。
- SPY-STK-SMART-USD -> 标普 500 ETF(将被指定为
dataname
) - SPY-CFD-SMART-USD -> 对应的 CFD 提供的不是价格跟踪,而是交易资产(指定为
tradename
)
参数中的默认值是允许类似 \
TICKER这样的东西,其中参数
sectype(默认:
STK)和
exchange(默认:
SMART`)被应用。
一些资产如 AAPL
需要完整的规范,包括 currency
(默认:‘’),而其他资产如 TWTR
可以直接传递。
AAPL-STK-SMART-USD
将是 dataname 的完整规范
或者:IBData
作为IBData(dataname='AAPL', currency='USD')
,它使用默认值(STK
和SMART
),并覆盖货币为USD
Oanda
与 Oanda 的集成支持:
- 实时数据馈送
- 实时交易
要求
oandapy
使用以下命令安装:pip install git+https://github.com/oanda/oandapy.git
pytz
(可选且不推荐)
鉴于外汇市场的全球性和 24 小时运作的特点,选择使用UTC
时间。如果愿意,您仍然可以使用您期望的输出时区。
示例代码
源代码包含完整示例:
samples/oandatest/oandatest.py
Oanda - 存储
存储是实时数据提要/交易支持的关键,提供了Oanda API 与数据提要和经纪人代理的需求之间的适配层。
- 提供访问使用方法获取经纪人实例:
OandaStore.getbroker(*args, **kwargs)
- 提供访问数据提要实例的方法
OandaStore.getedata(\*args, **kwargs)
- 在这种情况下,许多
**kwargs
与数据提要(例如dataname
、fromdate
、todate
、sessionstart
、sessionend
、timeframe
、compression
)是共同的
数据可能提供其他参数。请查看下面的参考资料。
强制性参数
为了成功连接到Oanda,以下参数是强制性的:
token
(默认值:None
):API 访问令牌account
(默认值:None
):账户 ID
这些由Oanda提供
是否连接到测试服务器或真实服务器,请使用:
practice
(默认值:False
):使用测试环境
必须定期检查账户以获取现金和价值。刷新周期可以通过以下方式控制:
account_tmout
(默认值:10.0
):帐户价值/现金刷新周期
Oanda 提要
实例化数据:
- 根据 Oanda 的指南传递符号
- 根据 Oanda 的指南,EUR/USDD必须指定为
EUR_USD
。实例化如下:
data = oandastore.getdata(dataname='EUR_USD', ...)`
时间管理
除非将tz
参数(pytz 兼容对象)传递给数据提要,否则所有时间输出均为UTC
格式,如上所述。
回填
backtrader对Oanda没有特殊要求。对于小时间框架,在测试服务器上由Oanda返回的回填长度为500
条
OandaBroker - 实时交易
使用经纪人
要使用OandaBroker,必须替换由cerebro创建的标准经纪人模拟实例。
使用Store模型(首选):
import backtrader as bt cerebro = bt.Cerebro() oandastore = bt.stores.OandaStore() cerebro.broker = oandastore.getbroker() # or cerebro.setbroker(...)
经纪人 - 初始持仓
经纪人支持一个参数:
use_positions
(默认值:True
):连接到经纪人提供商时,使用现有持仓来启动经纪人。
在实例化时设置为False
,以忽略任何现有持仓
操作
关于标准用法没有变化。只需使用策略中可用的方法(详见Strategy
参考资料以获取完整解释)
buy
sell
close
cancel
订单执行类型
Oanda几乎支持backtrader所需的所有订单执行类型,但不包括Close。
因此,订单执行类型受到限制:
Order.Market
Order.Limit
Order.Stop
Order.StopLimit
(使用 Stop 和 upperBound / lowerBound 价格)Order.StopTrail
- Bracket 订单受到支持,使用
takeprofit
和stoploss
订单成员并在内部创建模拟订单。
订单有效性
在回测期间(使用 valid
为 buy
和 sell
)可用的相同的有效性概念可用,并且具有相同的含义。因此,对于以下值,Oanda Orders 的 valid
参数将如下翻译:
None
转换为 Good Til Cancelled
因为未指定有效性,所以理解为订单必须有效直至取消datetime/date
转换为 Good Til Datetimedelta(x)
转换为 Good Til Date(这里timedelta(x) != timedelta()
)
这被解释为信号,要求订单从now
+timedelta(x)
开始有效。timedelta() 或 0
转换为 Session
已传递一个值(而不是None
)但为 Null,并被解释为当前 day(会话)有效的订单
通知
标准的 Order
状态将通过 notify_order
方法(如果已重写)通知到策略。
Submitted
- 订单已发送到 TWSAccepted
- 订单已下达Rejected
- 用于实际拒绝和在订单创建期间未知其他状态时使用Partial
- 部分执行已经发生Completed
- 订单已完全执行Canceled
(或Cancelled
)Expired
- 当订单因到期而取消时
参考
OandaStore
class backtrader.stores.OandaStore()
单例类,用于控制与 Oanda 的连接。
参数:
token
(默认值:None
):API 访问令牌account
(默认值:None
):账户 IDpractice
(默认值:False
):使用测试环境account_tmout
(默认值:10.0
):账户价值/现金刷新的刷新周期
OandaBroker
class backtrader.brokers.OandaBroker(**kwargs)
Oanda 的经纪人实现。
此类将来自 Oanda 的订单/持仓映射到 backtrader
的内部 API。
参数:
use_positions
(默认值:True
):连接到经纪人提供者时,使用现有仓位启动经纪人。
在实例化期间设置为False
以忽略任何现有仓位
OandaData
class backtrader.feeds.OandaData(**kwargs)
Oanda 数据源。
参数:
qcheck
(默认值:0.5
)
如果未收到数据,则在苏醒的秒数内将给出重新采样/重播数据包的机会,并将通知传递给链上historical
(默认值:False
)
如果设置为True
,数据源将在第一次下载数据后停止。
将使用标准数据源参数fromdate
和todate
作为参考。
如果请求的持续时间大于 IB 允许的时间跨度/压缩所选择的数据的持续时间,数据源将进行多次请求。backfill_start
(默认值:True
)
在开始时执行回填。将通过单个请求获取最大可能的历史数据。backfill
(默认:True
)
在断开/重新连接周期后执行回填。间隙持续时间将用于下载可能的最小数据量backfill_from
(默认:None
)
可以传递额外的数据源来进行初始的回填层。一旦数据源用尽并且如果请求,将从 IB 进行回填。理想情况下,这是为了从已存储的源(如磁盘上的文件)进行回填,但不限于此。bidask
(默认:True
)
如果为True
,则历史/回填请求将从服务器请求bid/ask价格
如果为False
,则将请求midpointuseask
(默认:False
)
如果为True
,则将使用bidask价格的ask部分,而不是默认的bid使用方式includeFirst
(默认:True
)
通过直接设置参数到 Oanda API 调用来影响历史/回填请求的第一个柱条的交付reconnect
(默认:True
)
当网络连接断开时重新连接reconnections
(默认:-1
)
重新连接尝试的次数:-1
表示永远reconntimeout
(默认:5.0
)
在重新连接尝试之间等待的时间(秒)
此数据源仅支持timeframe
和compression
的以下映射,这些映射符合 OANDA API 开发人员指南中的定义:
(TimeFrame.Seconds, 5): 'S5', (TimeFrame.Seconds, 10): 'S10', (TimeFrame.Seconds, 15): 'S15', (TimeFrame.Seconds, 30): 'S30', (TimeFrame.Minutes, 1): 'M1', (TimeFrame.Minutes, 2): 'M3', (TimeFrame.Minutes, 3): 'M3', (TimeFrame.Minutes, 4): 'M4', (TimeFrame.Minutes, 5): 'M5', (TimeFrame.Minutes, 10): 'M10', (TimeFrame.Minutes, 15): 'M15', (TimeFrame.Minutes, 30): 'M30', (TimeFrame.Minutes, 60): 'H1', (TimeFrame.Minutes, 120): 'H2', (TimeFrame.Minutes, 180): 'H3', (TimeFrame.Minutes, 240): 'H4', (TimeFrame.Minutes, 360): 'H6', (TimeFrame.Minutes, 480): 'H8', (TimeFrame.Days, 1): 'D', (TimeFrame.Weeks, 1): 'W', (TimeFrame.Months, 1): 'M',
任何其他组合都将被拒绝