跳转到内容

接收逐笔数据

逐笔数据按 tickType 进入不同回调。写代码时要同时实现需要的回调,不要只实现一个函数就期待所有逐笔类型都能收到。

官方参考:Tick-by-Tick Data

def tickByTickAllLast(
self,
reqId,
tickType,
time,
price,
size,
tickAttribLast,
exchange,
specialConditions,
):
print("成交逐笔", reqId, tickType, time, price, size, exchange, specialConditions)

字段说明:

字段类型含义中文说明
reqId请求编号对应 reqTickByTickData() 传入的编号。
tickType成交类型编号区分 Last 与 AllLast 返回的成交类型。
timeUnix 时间戳成交发生时间,通常需要转成交易所时区或系统展示时区。
price数值成交价格。
sizeDecimal成交数量,股票通常代表股数,其他品种要结合合约乘数理解。
tickAttribLast属性对象包含成交属性,例如是否越过限制价、是否未报告、是否过去限制等。
exchange字符串成交交易所或来源。
specialConditions字符串特殊成交条件,不能简单忽略。

LastAllLast 都进入这个回调。想区分来源时,不要只看函数名,要看请求时使用的 reqIdtickType

def tickByTickBidAsk(
self,
reqId,
time,
bidPrice,
askPrice,
bidSize,
askSize,
tickAttribBidAsk,
):
print("买卖报价逐笔", reqId, time, bidPrice, askPrice, bidSize, askSize)

字段说明:

字段中文说明
reqId对应请求编号。
time报价时间,通常是 Unix 时间戳。
bidPrice买一价格。
askPrice卖一价格。
bidSize买一数量。
askSize卖一数量。
tickAttribBidAsk买卖报价属性,例如 bid/ask 是否来自过去限制。

如果请求时 ignoreSize=True,只有报价数量变化而价格不变的更新会被过滤掉。做盘口压力、报价量变化统计时,应设为 False

def tickByTickMidPoint(self, reqId, time, midPoint):
print("中点价逐笔", reqId, time, midPoint)

midPoint 是买卖报价中点,不是成交价。不要把它当作真实成交价格写入成交表。

逐笔数据不适合只保存“最后一个价格”。更稳妥的做法是追加到队列或数据库:

tick_rows = []
def tickByTickMidPoint(self, reqId, time, midPoint):
tick_rows.append({
"reqId": reqId,
"time": time,
"midPoint": midPoint,
})

成交类数据建议额外保存 exchangespecialConditionstickAttribLast。买卖报价类数据建议同时保存 bid/ask 价格、数量和 tickAttribBidAsk,这样排查异常报价时有足够上下文。

缺少 AAPL API 实时行情权限时,不会进入逐笔回调:

LAST_ROWS=0
BIDASK_ROWS=0
MIDPOINT_ROWS=0

如果账户权限正常,最先应该看到这些行数大于 0。若仍然为 0,同时 error() 收到 1018910089,就是市场数据订阅问题。

10189 也可能表示该产品或该逐笔类型没有可用数据。例如外汇 EUR.USD 请求 Last / AllLast 时可能返回 No historical market data for EUR/CASH@FXSUBPIP。排查时要同时看合约类型、逐笔类型和错误消息,不要只看错误码。