【TWS API 翻译系列】11、TWS和IB中的streaming市场数据
作者:yunjinqi   类别:    日期:2022-01-03 22:15:30    阅读:1311 次   消耗积分:0 分    

流媒体市场数据

可以从TWS获取不同类型的市场数据:

实时市场数据

为了从 API 接收实时的顶级、深度或历史市场数据,有必要在TWS中为请求的工具提供实时市场数据订阅。实时数据要求的完整列表:

(1)指定品种的交易许可

(2)注资账户(外汇和债券除外),以及

(3)指定用户名的市场数据订阅

要订阅实时市场数据:

登录您的账户管理,导航到管理账户 - >交易配置 - >市场数据,然后根据您需要的产品选择您希望订阅的相关软件包和/或订阅。

确定给定证券需要哪些市场数据订阅的一种方法是将合约输入TWS观察列表,然后右键单击合约以选择"启动市场数据订阅管理器"。这将启动一个浏览器窗口,进入涵盖指定工具的订阅的市场数据订阅页面。

或者,还有一个"市场数据助手"实用程序用于确定市场数据订阅:

am_market_data_subscription.png

选择相关软件包后,单击"继续"按钮,并在以下屏幕中确认您做出了正确的选择。

**重要:**市场数据订阅按整月费率计费,不会按比例计费。

am_subscription_confirm.png

共享市场数据订阅

市场数据订阅是在TWS用户名级别完成的,而不是在每个账户上完成的。这意味着每个实时TWS用户都需要购买实时市场数据订阅。此规则的唯一例外是模拟交易用户。要共享市场数据订阅,只需访问您的帐户管理并导航到管理账户 - >设置 - >模拟交易,您将看到下面的屏幕。市场数据共享最多需要24小时才能生效。

am_md_sharing.png

**重要提示:**由于您的模拟交易市场数据权限绑定到您的实时交易,因此您只能在以下情况下获取有关您的模拟交易用户的实时市场数据;

  • 如上所述,您已相应地共享了市场数据订阅。

  • 您没有同时在另一台计算机上使用您的实时用户名登录。

市场数据线

每当用户从TWS内部或通过TWS API请求工具的实时(顶级)市场数据时,用户都在使用市场数据线。因此,市场数据线表示用户具有的活动市场数据请求。

例:为了进一步澄清这个概念,让我们假设用户的最大Ticker限制为条市场数据线,并且已经在TWS本身内观察了五只股票的实时数据。当用户将其TWS API客户端应用程序连接到TWS时,他随后请求其他五种工具的实时市场数据。稍后,当所有 10 个请求仍处于活动状态时,用户尝试订阅第 11 个产品的实时实时市场数据。由于用户已经在使用十条市场数据线(TWS 中有五条,客户端应用程序中还有五条),因此 TWS 将响应一条错误消息,告知客户端应用程序它已达到最大并发请求数。为了请求第十一个产品的市场数据,用户必须取消至少一个当前有效的订阅(在TWS内或从其客户计划中)。

默认情况下,每个用户都有100条市场数据线的最大Ticker限制,因此可以同时获得多达100种工具的实时市场数据。但是,可以通过购买报价补充包或通过增加用户帐户的净值和/或佣金来进一步扩展此限制。有关如何增加市场数据行数或如何计算市场数据行的权利的更多详细信息,请参阅我们网站"研究,新闻和市场数据"页面中的"市场数据显示"部分。

**注意:**了解市场数据线的概念非常重要,因为它不仅对实时实时请求有影响,而且对请求市场深度和实时柱也有影响。

顶级市场数据(一级)

使用TWS API,您可以请求实时市场数据进行交易和分析。从API中,从函数IBApi.EClient.reqMktData返回的市场数据对应于TWS观察列表中显示的市场数据。此数据不是逐个刻度,而是由每秒间隔拍摄的聚合快照组成,这些快照因仪器类型而异:

  • 需要注意的是:实时市场数据和历史柱线目前无法从交易所OSE的 API 获得。只有 15 分钟的延迟流数据可用于此交换。

    产品频率
    股票、期货及其他250 毫秒
    美国期权100 毫秒
    外汇对5 毫秒

请求关注列表数据

与TWS观察列表中显示的数据相对应的流市场数据值可通过IBApi.EClient.reqMktData获得。此数据不是逐个逐个刻度,而是由每秒拍摄几次的聚合快照组成。默认情况下,从对IBApi.EClient.reqMktData的调用中返回一组"默认"逐笔报价类型,并且通过在市场数据请求中指定相应的泛型分时类型,可以使用其他分时类型。包括通用价格变动类型,许多(但不是全部)数据类型都可用,这些数据类型可以通过添加其他列显示在TWS观察列表中。每个市场数据请求都使用一个唯一的标识符(股票代码 ID),用于标识返回的数据:

self.reqMktData(1000, ContractSamples.USStockAtSmart(), "", False, False, [])self.reqMktData(1001, ContractSamples.StockComboContract(), "", False, False, [])

通用分时类型

最常见的分时类型在成功请求市场数据后自动交付。但是,通过显式请求还有其他分笔报价类型: 通用分时类型。当调用IBApi.EClient.reqMktData时,可以通过函数的genericTickList参数请求特定的泛型分时:

# Requesting RTVolume (Time & Sales) and shortable generic ticksself.reqMktData(1004, ContractSamples.USStockAtSmart(), "233,236", False, False, [])

有关可用逐笔报价类型的列表,请参阅可用的分笔报价类型

流数据快照

通过交易所市场数据订阅,例如美国股票的网络A(NYSE),网络B(ARCA)或网络C(NASDAQ),可以请求一次市场当前状态的快照,而不是随着市场价值的变化不断请求更新流。通过调用IBApi::EClient::reqMktData 函数为快照参数传入**true,**客户端应用程序将在 11 秒后发送IBApi.EWrapper.tickSnapshotEnd 事件之前接收一次当前可用的市场数据。快照请求只能针对默认价格变动类型发出;不能指定通用价格变动。请务必注意,快照请求只会在 11 秒的跨度内返回可用数据。在某些情况下,可能不会为所有价格变动类型返回值。

快照请求:

self.reqMktData(1002, ContractSamples.FutureComboContract(), "", True, False, [])

结束标记接收:
class TestWrapper(wrapper.EWrapper):
	###
    def tickSnapshotEnd(self, reqId: int):
        super().tickSnapshotEnd(reqId)
    	print("TickSnapshotEnd. TickerId:", reqId)

法规快照

reqMktData的第五个参数指定了对美国股票和期权的监管快照请求。监管快照需要 TWS/IBG v963和 API 973.02或更高版本以及特定的市场数据订阅。

对于股票,需要订阅单个交易所特定的市场数据才能接收流报价。例如,对于纽约证券交易所股票,这种订阅被称为"网络A",对于ARCA / AMEX股票,它被称为"网络B",对于纳斯达克股票,它是"网络C"。每个订阅都增加了点菜,并有单独的市场数据费用。

或者,还有一个"美国证券快照包"订阅,它不提供流数据,但允许实时计算美国市场NBBO价格的快照。通过将IBApi::EClient::reqMktData中的第5个参数设置为**True,**可以从API发出监管快照请求。返回值是基于所有可用交易所的数据计算的当前市场状态。

**重要提示:每个监管快照将向账户收取 0.01 美元的费用。这适用于真实*账户和*纸质账户。**如果监管快照的月费达到特定"网络"订阅的价格,则用户将自动订阅该网络订阅以获取连续流报价,并收取该月的相关费用。在月底,订阅将被终止。每个上市交易所将独立设定上限,不会在上市交易所之间合并。

# Each regulatory snapshot request incurs a 0.01 USD feeself.reqMktData(1003, ContractSamples.USStock(), "", False, True, [])

下表列出了监管快照报价的成本和最大分配:

列出的网络源价格根据要求快照请求专业版或非专业版最大 reqSnapshot 请求
纽约证券交易所(网络A/CTA)0.01 元专业版4500
纽约证券交易所(网络A/CTA)0.01 元非专业版150
美国运通(网络B/CTA)0.01 元专业版2300
美国运通(网络B/CTA)0.01 元非专业版150
纳斯达克(网络C/UTP)0.01 元专业版2300
纳斯达克(网络C/UTP)0.01 元非专业版150

请求法规快照受节奏限制:

  • 每秒不超过一个请求。

可用的分笔报价类型

接收关注列表数据

接收市场数据

使用订阅和发布模型在 API 中访问实时数据,该模型还与其他功能(如检索头寸或账户值)一起使用。在对IB数据库中的特定合约发出流式市场数据订阅请求后,TWS将返回连续的市场数据流,并根据数据类型(整数、十进制和字符串)分离到EWrapper中的不同函数。由于订阅和发布模型本质上是异步的,因此返回的数据将使用请求中指定的称为请求 ID (reqID) 的数字标签链接到初始请求。

订阅股票代码流后,您的 API 客户端将通过多种方式接收 TWS API 服务器提供的数据。在 API 客户端代码中,您需要实现这些方法来操作中继回客户端的数据。请注意市场数据回调(如IBApi.EWrapper.tickPriceIBApi.EWrapper.tickSize方法)如何包含请求 ID,响应可以通过该 ID 映射到其原始请求。默认情况下,始终返回某些"默认价格变动类型"。其中包括买入价、卖出价、买入价大小、卖出价大小等字段。实时数据还有其他类型的数据可用,这些数据是通过在市场数据请求中指定某些"通用价格变动类型"来请求的。有关更多信息,泛型价格变动类型

当 IBApi::EWrapper::tickPrice 和 IBApi::EWrapper::tickSize 报告为 -1 时,这表示当前没有可用的数据。最常见的情况是,当从已关闭的市场请求数据时,会发生这种情况。对于在请求时没有公开出价或报盘的不经常交易的工具,也可能发生这种情况。要接收冻结的报价(系统记录的最后一个可用出价/要价),请调用带有参数 2 的函数IBApi.EClient.reqMarketDataType。或者,要从股票代码接收"延迟冻结"数据而不持有市场数据订阅,请指定市场数据类型 4。冻结数据是默认分时类型独有的 -通用分时类型不可用 - 并且需要市场数据订阅。

对于出价、要价和最后的数据,在每IBApi::EWrapper::tickSize回调之后,总会有一个 IBApi::EWrapper::tickPrice。这很重要,因为对于组合合约,积极交易的合约的价格可以为零。在这种情况下,它将具有正的IBApi::EWrapper::tickSize值。 IBApi::EWrapper::tickSize在每次最后交易价格的大小发生变化时,也会调用大小。因此,当交易的价格和规模都发生变化时,将出现重复的 tickSize 事件。

class TestWrapper(wrapper.EWrapper):
	###
	def tickPrice(self, reqId: TickerId, tickType: TickType, price: float,
                   attrib: TickAttrib):
        super().tickPrice(reqId, tickType, price, attrib)
        print("TickPrice. TickerId:", reqId, "tickType:", tickType,
               "Price:", price, "CanAutoExecute:", attrib.canAutoExecute,
               "PastLimit:", attrib.pastLimit, end=' ')
        if tickType == TickTypeEnum.BID or tickType == TickTypeEnum.ASK:
             print("PreOpen:", attrib.preOpen)
        else:
             print()
     ###
     def tickSize(self, reqId: TickerId, tickType: TickType, size: Decimal):
         super().tickSize(reqId, tickType, size)
         print("TickSize. TickerId:", reqId, "TickType:", tickType, "Size: ", decimalMaxString(size))
            
     ###
     def tickSize(self, reqId: TickerId, tickType: TickType, size: Decimal):
         super().tickSize(reqId, tickType, size)
         print("TickSize. TickerId:", reqId, "TickType:", tickType, "Size: ", decimalMaxString(size))
     
     ###
     def tickGeneric(self, reqId: TickerId, tickType: TickType, value: float):
         super().tickGeneric(reqId, tickType, value)
         print("TickGeneric. TickerId:", reqId, "TickType:", tickType, "Value:", value)

交换组件映射

市场数据请求能够从多个交易所返回数据。从TWS/IBG v963和API v973.02开始,在对市场数据订阅所涵盖的工具发出市场数据请求后,将向 IBApi::EWrapper::tickReqParams发送一条消息,其中包含有关"minTick",BBO交换映射和可用快照权限的信息。

def tickReqParams(self, tickerId:int, minTick:float,
             bboExchange:str, snapshotPermissions:int):
    super().tickReqParams(tickerId, minTick, bboExchange, snapshotPermissions)
    print("TickReqParams. TickerId:", tickerId, "MinTick:", minTick,
          "BboExchange:", bboExchange, "SnapshotPermissions:", snapshotPermissions)

交换映射标识符bboExchange将是一个符号,例如 “a6”,它可用于通过调用函数IBApi::EClient::reqSmartComponents.来解码返回到 bidExch、askExch 和 lastExch 字段的单字母交换缩写。有关组件更换的详细信息

返回到 tickReqParams 的minTick表示返回到 API 的市场数据值的最小增量。它可能不同于 ContractDetails 类中的 minTick 值。例如,对于市场数据,组合的最小增量通常为 0.01,对于下单,最小增量为 0.05。

Re-Routing CFDs

IB不提供某些类型工具的市场数据,例如股票差价合约和外汇差价合约。如果股票差价合约或外汇差价合约被输入到TWS观察列表中,TWS将自动显示标的股票代码的市场数据,并在工具名称旁边显示"U"图标,以指示该数据是针对基础工具的。

根据API,当为股票差价合约或外汇差价合约请求1级或2级市场数据时,将对函数 IBApi::EWrapper::rerouteMktDataReq 或 IBApi::EWrapper::rerouteMktDepthReq进行回调,其中包含有关IB数据库中具有市场数据的基础工具的详细信息。

def rerouteMktDataReq(self, reqId: int, conId: int, exchange: str):
    super().rerouteMktDataReq(reqId, conId, exchange)
    print("Re-route market data request. ReqId:", reqId, "ConId:", conId, "Exchange:", exchange)
    def rerouteMktDepthReq(self, reqId: int, conId: int, exchange: str):
    super().rerouteMktDataReq(reqId, conId, exchange)
    print("Re-route market depth request. ReqId:", reqId, "ConId:", conId, "Exchange:", exchange)

取消流数据

一旦不再需要活跃的市场数据请求,可以通过IBApi::EClient::cancelMktData方法取消该请求。取消MktData的一个参数是在原始市场数据请求中指定的股票代码ID。取消订阅允许用户订阅不同的合同,并保持在1级市场数据线限额内。

self.cancelMktData(1000)self.cancelMktData(1001)

Component Exchanges

来自 API 的单个数据请求可以接收来自多个交易所的聚合报价。对于 API 版本9.72.18和 TWS 9.62及更高版本,使用逐笔报价类型 ‘bidExch’(分时类型 32)、‘askExch’(分时类型 33)、‘lastExch’(分时类型 84)来识别报价的来源。为了节省带宽,返回到这些价格变动类型的数据由一系列大写字母组成,而不是每个返回的交换名称字段的一长串交换名称。要查找与价格变动类型 32、33 或 84 中返回的单个字母代码相对应的完整交换名称,可以使用 API 函数IBApi::EClient::reqSmartComponents**注意:**此功能只能在交易所打开时使用。

不同的IB合约有不同的交易所地图,其中包含它们交易的交易所集。每个交换地图都有不同的代码,例如"a6"或"a9"。此交易所映射代码在具有市场数据订阅的用户发出市场数据请求后立即返回到IBApi::EWrapper::tickReqParams.要查找单个字母代码到完整交换名称的特定映射,将调用函数 reqSmartComponents,并将交换映射代码返回到 tickReqParams。

# Requests description of map of single letter exchange codes to full exchange namesself.reqSmartComponents(1018, "a6")

例如,IBKR美国合约的市场数据请求可能会将交易所映射标识符"a6"返回给IBApi.EWrapper.tickReqParams。调用函数IBApi.EClient.reqSmartSmart代码为"a9"的组件将显示提供IBKR美国合约市场数据的交易所列表及其单字母代码。“ARCA"的代码可以是"P”。在这种情况下,如果"P"返回到交易所价格变动类型,则表明报价是由ARCA提供的。

def smartComponents(self, reqId:int, smartComponentMap:SmartComponentMap):
    super().smartComponents(reqId, smartComponentMap)
    print("SmartComponents:")
    for smartComponent in smartComponentMap:
    	print("SmartComponent.", smartComponent)

市场数据类型

API 可以通过IBApi.EClient.reqMarketDataType切换市场数据类型,然后使用 reqMktData 发出市场数据请求,从而从交易者工作站请求实时、冻结、延迟和延迟冻结市场数据。对于特定的市场数据请求,成功切换到不同的(非实时)市场数据类型将通过回调IBApi::EWrapper::marketDataType来指示,该调用返回的市场数据请求的股票代码 ID 返回不同类型的数据。

市场数据类型用户名描述
Live1实时市场数据是实时流传回的数据。需要订阅市场数据才能接收实时市场数据。
Frozen2冻结市场数据是收盘时记录的最后数据。在TWS中,冻结数据以灰度数字显示。当您将市场数据类型设置为"冻结"时,您将要求TWS在当前没有可用报价时发送最后可用的报价。例如,如果市场当前处于平仓状态并请求实时数据,则通常将为买入价和卖出价返回-1值,以指示当前没有可用的买入价/卖出价数据。TWS通常会显示"冻结"的买入价/卖出价,代表系统记录的最后一个值。要在市场收盘前接收最后已知的买入价/卖出价,请在请求市场数据之前从API切换到市场数据类型2。API 冻结数据需要 TWS/IBG v.962 或更高版本,以及实时流数据所需的相同市场数据订阅。
Delayed3免费延迟数据延迟 15 - 20 分钟。在 TWS 中,延迟数据显示在棕色背景中。当您将市场数据类型设置为延迟时,您告诉TWS在用户没有必要的实时数据订阅时自动切换到延迟市场数据。如果实时数据可用,则TWS将忽略对延迟数据的请求。延迟的市场数据以延迟的逐笔报价类型返回 (Tick ID 66~76)。注意:需要 TWS 内部版本 962 或更高版本,建议使用 API 版本 9.72.18 或更高版本。
Delayed Frozen4请求延迟了没有市场数据订阅的用户的"冻结"数据。
# Switch to live (1) frozen (2) delayed (3) delayed frozen (4).self.reqMarketDataType(MarketDataTypeEnum.DELAYED)

在调用IBApi.EClient.reqMarketDataType获取冻结或延迟的数据后,后续IBApi::EClient::reqMktData 请求将触发IBApi.EWrapper.marketDataType作为结果事件之一,以指示返回数据的数据类型(2 或 3)。

 class TestWrapper(wrapper.EWrapper):
     def marketDataType(self, reqId: TickerId, marketDataType: int):
    	super().marketDataType(reqId, marketDataType)
    	print("MarketDataType. ReqId:", reqId, "Type:", marketDataType)

逐笔报价数据

与TWS时间和销售窗口中显示的数据相对应的逐笔报价数据从TWS v969和API v973.04开始提供。允许用户同时逐笔报价订阅的最大数量由用于计算最大市场深度订阅数量限制的相同公式确定。

  • 分时类型字段区分大小写 - 它必须是BidAsk,Last,AllLast,MidPoint。AllLast还有其他交易类型,如组合,衍生品和平均价格交易,这些交易不包括在Last中。

  • 期权的逐笔报价数据目前仅在历史上可用,而不是实时提供。

  • 指数逐笔报价数据仅针对CME上的指数提供。

  • 逐笔报价数据不适用于组合。

  • 在 15 秒内,同一工具的逐笔报价请求不得超过 1 次。

self.reqTickByTickData(19001, ContractSamples.EuropeanStock2(), "Last", 0, True)self.reqTickByTickData(19002, ContractSamples.EuropeanStock2(), "AllLast", 0, False)self.reqTickByTickData(19003, ContractSamples.EuropeanStock2(), "BidAsk", 0, True)self.reqTickByTickData(19004, ContractSamples.EurGbpFx(), "MidPoint", 0, False)

根据在 IBApi::EClient::reqTickByTickData中选择的数据类型,数据将返回到以下函数之一:IBApi::EWrapper::tickByTickAllLastIBApi::EWrapper::tickByTickBidAsk, or IBApi::EWrapper::tickByTickMidPoint. 此外,如果在 IBApi::EClient::reqTickByTickData中为参数编号输入非零值,则历史逐笔报价数据将首先返回给以下函数之一 IBApi::EWrapper::historicalTicksLastIBApi::EWrapper::historicalTicksBidAsk, or IBApi::EWrapper::historicalTicks.

def tickByTickBidAsk(self, reqId: int, time: int, bidPrice: float, askPrice: float,	                                      bidSize: Decimal, askSize: Decimal, tickAttribBidAsk: TickAttribBidAsk):
	super().tickByTickBidAsk(reqId, time, bidPrice, askPrice, bidSize,askSize, tickAttribBidAsk)
	print("BidAsk. ReqId:", reqId,
           "Time:", datetime.datetime.fromtimestamp(time).strftime("%Y%m%d %H:%M:%S"),
           "BidPrice:", bidPrice, "AskPrice:", askPrice, "BidSize:", decimalMaxString(bidSize),
            "AskSize:", decimalMaxString(askSize), "BidPastLow:", tickAttribBidAsk.bidPastLow,
          "AskPastHigh:", tickAttribBidAsk.askPastHigh)
def tickByTickAllLast(self, reqId: int, tickType: int, time: int, price: float,
                           size: Decimal, tickAtrribLast: TickAttribLast, exchange: str,
                           specialConditions: str):
    super().tickByTickAllLast(reqId, tickType, time, price, size, tickAtrribLast,
                                   exchange, specialConditions)
     if tickType == 1:
         print("Last.", end='')
     else:
         print("AllLast.", end='')
         print(" ReqId:", reqId,
               "Time:", datetime.datetime.fromtimestamp(time).strftime("%Y%m%d %H:%M:%S"),
               "Price:", price, "Size:", decimalMaxString(size), "Exch:" , exchange,
               "Spec Cond:", specialConditions, "PastLimit:", tickAtrribLast.pastLimit, 
               "Unreported:",tickAtrribLast.unreported)
  • 不可报告交易的交易数据,如组合和大宗交易,包含在实时数据馈送提供的"AllLast"数据类型中,但不记录在历史数据库中。

@iswrapperdef tickByTickMidPoint(self, reqId: int, time: int, midPoint: float):
	super().tickByTickMidPoint(reqId, time, midPoint)
	print("Midpoint. ReqId:", reqId,"Time:", 
          datetime.datetime.fromtimestamp(time).strftime("%Y%m%d %H:%M:%S"),
          "MidPoint:", midPoint)

逐笔逐笔报价订阅可以使用函数 IBApi::EClient::cancelTickByTickData 取消

self.cancelTickByTickData(19001)self.cancelTickByTickData(19002)self.cancelTickByTickData(19003)self.cancelTickByTickData(19004)

延迟流数据

10-15分钟的延迟流数据可用于许多类型的工具,而无需市场数据订阅。默认情况下,API 处于实时市场数据模式,因此函数IBApi::EClient::reqMktData将请求实时数据。要切换到延迟流数据,必须调用函数 IBApi::EClient::reqMarketDataType时参数为 3(对于延迟)或 4(对于延迟冻结),另请参阅市场数据类型。随后调用IBApi::EClient::reqMktData将导致对延迟数据的请求,这些数据将返回到延迟的分时类型可用的分时类型。如果实时数据可用,则将始终返回该数据,而不是延迟数据。

  • 延迟数据具有数量有限的可指定的通用价格变动类型:101、106、165、221、232、236、258。另请参阅可用的逐笔报价类型

  • 需要注意的是,历史数据仍然需要市场数据订阅历史市场数据

市场深度(二级)

市场深度数据,也经常成为 level II数据,通常指的是一个品种的订单薄。通过TWS API,可以使用IBApi.EClient.reqMarketDepth函数(注意:它在Java,C++和Python中被命名为reqMktDepth)来获取此信息。与顶级市场数据(I级)不同,市场深度数据是在没有抽样或过滤的情况下发送的,但是我们不能保证当您调用IBApi.EClient.reqMarketDepth时,特定证券的每个报价都会显示出来。特别是,不包括奇数手订单。从API v974TWS v974开始,可以智能路由IBApi.EClient.reqMarketDepth请求以接收来自所有可用交易所的聚合数据,类似于TWS BookTrader显示。

请求

IBApi.EClient.reqMarketDepth方法接收一个请求标识符(或股票代码 ID),用于标识传入的数据、我们要为其提取此信息的IBApi.Contract以及所需的行数或深度级别。如果市场深度小于请求的行数,TWS 将仅返回可用的条目。

self.reqMktDepth(2001, ContractSamples.EurGbpFx(), 5, False, [])

做市商或交易所

市场深度将通过IBApi.EWrapper.updateMktDepthIBApi.EWrapper.updateMktDepthL2回调返回。这两个功能的不同之处在于,当有做市商或交易所标识符要返回时,市场深度数据将通过IBApi.EWrapper.updateMktDepthL2中继回来。否则,它将返回到IBApi.EWrapper.updateMktDepth。例如,ARCA只有ARCA本身作为做市商。因此,当从ARCA请求市场深度数据时,数据将通过IBApi.EWrapper.updateMktDepth中继回来。另一方面,通过ISLAND(纳斯达克的ECN)提供做市商信息,因此做市商MPID将通过IBApi.EWrapper.updateMktDepthL2中继回来。做市商 MPID 在回调函数的 “marketMaker” 字符串参数中报告。如果 isSmartDepth 布尔值(可用于 API v974+)为 True,则 marketMaker 字段将指示报价源自的交易所。否则,它表示做市商的MPID。

为了检查哪些交易所提供订单薄,可以调用函数 IBApi::EClient::reqMktDepthExchanges如果用户具有适当的市场数据订阅,它将返回市场深度可用的交易所列表。

self.reqMktDepthExchanges()

API"交易所"字段,市场深度请求将返回做市商信息并导致对 IBApi::EWrapper::updateMktDepthL2 的回调,将在IBApi::EWrapper::mktDepthExchanges字段的结果中用"isL2"字段中的"True"值指示:

def mktDepthExchanges(self, depthMktDataDescriptions:ListOfDepthExchanges):
    super().mktDepthExchanges(depthMktDataDescriptions)
    print("MktDepthExchanges:")
    for desc in depthMktDataDescriptions:
        print("DepthMktDataDescription.", desc)

接收

最初,所有请求/可用的行都将传递到客户端应用程序。然而,随着市场的走势,这些行将不可避免地发生变化。为了保持客户订单簿的一致性,TWS将发送更新,不仅通知要更新哪一行,还通知要在行中执行的操作:插入(0),更新(1)或删除(2)。

class TestWrapper(wrapper.EWrapper):#...
     def updateMktDepth(self, reqId: TickerId, position: int, operation: int,
                        side: int, price: float, size: Decimal):
         super().updateMktDepth(reqId, position, operation, side, price, size)
         print("UpdateMarketDepth. ReqId:", reqId, "Position:", position, "Operation:",
               operation, "Side:", side, "Price:", price, "Size:", decimalMaxString(size))#...
     def updateMktDepthL2(self, reqId: TickerId, position: int, marketMaker: str,
                          operation: int, side: int, price: float, size: Decimal, isSmartDepth: bool):
         super().updateMktDepthL2(reqId, position, marketMaker, operation, side,
                                  price, size, isSmartDepth)
         print("UpdateMarketDepthL2. ReqId:", reqId, "Position:", position, "MarketMaker:", marketMaker, "Operation:",
               operation, "Side:", side, "Price:", price, "Size:", decimalMaxString(size), "isSmartDepth:", isSmartDepth)

取消

要取消活动的市场深度请求,只需调用IBApi.EClient.cancelMktDepth传入请求的标识符即可。

self.cancelMktDepth(2001, False)self.cancelMktDepth(2002, True)

局限性

鉴于发送的数据量可能很高,市场深度请求的数量要有限得多。与历史数据请求一样,活动深度请求的数量与市场数据行的数量相关,最少 3 条,最多 60 条:

行数最大请求数
0 - 3993
400 - 4994
500 - 5995
600 - 6996
等。。。

请注意,每个账户限制只有10个报价补充包,其余的市场数据线是使用账户资金和佣金分配的。另请注意,每个报价补充包提供100个市场数据行。

5 秒实时K线

实时和历史数据功能通过IBApi.EClient.reqRealTimeBars请求进行组合。reqRealTimeBars 将创建一个活动订阅,该订阅将每五秒实时返回一个具有该时间段内 OHLC 值的柱。reqRealTimeBars 只能在条形大小为 5 秒的情况下使用。

**重要提示:实时柱订阅结合了顶部和历史市场数据的局限性。确保您观察或者请求bar的市场数据线频率不超过(30秒一次或更高)。例如,在 10 分钟内可以发出不超过 60个 *new***实时柱请求,并且所有类型的活动有效订阅总数不能超过用户允许的最大市场数据行数。

请求

self.reqRealTimeBars(3001, ContractSamples.EurGbpFx(), 5, "MIDPOINT", True, [])

  • 要接收交易量,VWAP或交易计数数据,必须将whatToShow指定为TRADES。

  • 可能需要在 IB 服务器重置后或交易时段之间重新制作实时K线订阅。

  • 如果发生bust事件,则会向连接到 TWS 版本 978+ 的所有 API 客户端版本报告 bust 事件错误 (code=10225)。

接收

一旦被调用,五秒的历史数据条将开始通过IBApi.EWrapper.realtimeBar回调提供:

class TestWrapper(wrapper.EWrapper):#...
     def realtimeBar(self, reqId: TickerId, time:int, open_: float, high: float, low: float, close: float,
                         volume: Decimal, wap: Decimal, count: int):
         super().realtimeBar(reqId, time, open_, high, low, close, volume, wap, count)
         print("RealTimeBar. TickerId:", reqId, RealTimeBar(time, -1, open_, high, low, close, volume, wap, count))
  • 美国股票的交易量乘数为100

取消

要取消活动请求,只需调用IBApi.EClient.cancelRealTimeBars

self.cancelRealTimeBars(3001)

TWS API相关的教程

【TWS API使用教程1】—如何在自己创建的client和TWS之间创建一个连接,并请求当前的时间
【TWS API使用教程2】—如何使用 TWS API在ubuntu和windows上分别设置contract、获取contract详细信息、设置order、下单、获取持仓信息、获取账户信息
【TWS API使用教程3】—如何使用TWS API从盈透证券中设置contract及获取contract的信息?
【TWS API使用教程4】—如何使用TWS API在盈透证券中设置order?
【TWS API使用教程5】—如何使用TWS API在盈透证券中下单(place order)、获取订单信息、获取持仓、获取账户汇总信息?
【TWS API使用教程6】—如何使用TWS API在盈透证券中获取数据?
【TWS API 使用教程7】如何使用TWS API 从盈透证券中筛选满足一定条件的contract?
【TWS API 使用教程8】一个基于TWS API的简单的程序化策略


版权所有,转载本站文章请注明出处:云子量化, http://www.woniunote.com/article/77
上一篇:【TWS API 翻译系列】10、IB和TWS API中一些常见的关于订单的算法
下一篇:【TWS API 翻译系列】12、TWS API和IB中的订单管理