问题描述
如图,513050,qmt全推行情返回的tick显示成交额数据是966171400.0,盘后拿历史数据拿到的正确数据是966171356,实时推送的数据精度明显被**了
解决方案
问题原因分析
在 QMT 平台中,实时 Tick 行情与盘后历史数据在 amount(成交额)字段上出现精度差异,主要由以下几个原因导致:
-
底层数据类型与浮点数精度限制:
实时行情为了追求极低的延迟和高并发传输,底层在处理或序列化amount字段时,可能采用了单精度浮点数(float32)。单精度浮点数的有效十进制数字大约为 7位。当成交额达到上亿级别(例如966,171,356,共9位数字)时,超出的部分会发生精度截断或四舍五入,从而变成类似966171400.0的数值。 -
实时推送与盘后清洗的机制差异:
- 实时全推行情:直接对接交易所的实时快照,经过网关快速分发,数据结构偏向轻量化。
- 盘后历史数据:收盘后,数据中心会对全天的行情进行清洗、校对,并以更高精度的数据类型(如
double或int64)落盘存储。因此,通过get_local_data或get_market_data_ex获取的历史数据是绝对精确的。
解决方案与处理建议
针对这种精度丢失现象,建议在编写量化策略时采取以下应对措施:
1. 评估策略对精度的实际需求
对于绝大多数基于成交额的量化策略(如计算资金净流入、放量突破、量价背离等),上亿成交额中几十元的精度误差(误差率不到千万分之一)对策略信号的触发没有任何实质性影响。在实时交易中,可以直接忽略这一微小的尾数差异。
2. 估算单笔/区间成交额
如果您需要计算两个 Tick 之间的区间成交额,直接相减可能会放大浮点数误差。可以通过成交量差值 × 最新价来进行估算:
def on_quote(datas):
for code, data in datas.items():
# 假设记录了上一个tick的 volume
current_volume = data['volume'].iloc[-1]
last_volume = get_last_volume(code) # 自定义函数获取上一个tick的volume
current_price = data['close'].iloc[-1]
# 估算当前Tick的真实成交额
tick_amount_est = (current_volume - last_volume) * current_price
print(f"{code} 当前Tick估算成交额: {tick_amount_est}")
3. 升级至 Level2 行情
如果您的策略是高频的微观结构策略,对盘口和逐笔成交的金额要求绝对精确,建议开通并订阅 Level2 行情。Level2 提供的逐笔成交明细(Tick-by-Tick)在数据结构上通常保留了完整的精度,能够满足高频交易的需求。
4. 盘后复盘务必使用历史接口
在进行盘后回测、财务对账或统计分析时,不要依赖盘中收集的实时 Tick 数据进行累加。请使用 QMT 提供的历史数据接口获取清洗后的高精度数据:
def handlebar(ContextInfo):
if not ContextInfo.is_last_bar():
return
# 获取盘后高精度日线/Tick数据
data = ContextInfo.get_market_data_ex(
['amount', 'volume', 'close'],
['513050.SH'],
period='1d',
subscribe=False
)
print("盘后精确成交额:", data['513050.SH']['amount'].iloc[-1])
总结:实时 Tick 行情 amount 字段的尾数归零是底层浮点数精度限制所致。在实盘策略中可忽略此误差或用量价推算,盘后统计则应统一使用历史数据接口。