nautilus_trader Polymarket 适配器 RTDS Crypto TWAP 测试向量解析:从 signed-E18 精确解码到数据客户端路由

发布时间:2026/9/10 20:52:23
nautilus_trader Polymarket 适配器 RTDS Crypto TWAP 测试向量解析:从 signed-E18 精确解码到数据客户端路由 nautilus_trader Polymarket 适配器 RTDS Crypto TWAP 测试向量解析从 signed-E18 精确解码到数据客户端路由【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader导读本文围绕 Nautilus Trader 的 Polymarket 适配器测试数据集中的rtds_crypto_twap_sixty_update.json测试向量展开剖析该向量如何从 Polymarket 官方 SDK 回归测试中被构造出来并深入讲解其背后 RTDSReal-Time Data Streamcrypto TWAP 行情在适配器中的线上解码、字段校验、重放防护与数据客户端路由逻辑。读完本文你将理解 Chainlink 计算的 60 秒 TWAP 样本如何以 signed-E18 整数在线上传输Nautilus 为何只信任full_accuracy_value而非显示字段value以及这一测试向量在单元测试与集成测试中的双重角色。一、测试向量在 Polymarket 适配器中的位置该测试向量是 Nautilus Trader Polymarket 适配器测试数据集的一部分。适配器源码位于 crates/adapters/polymarket/src其中 rtds.rs 实现了私有的 RTDS 行情订阅与解码测试数据则存放在 crates/adapters/polymarket/test_data 目录下。与该向量配套的还有一份来源说明文档 rtds_crypto_twap_sixty_update.source.md。这类.source.md侧车文件sidecar在测试数据目录中普遍存在用于记录每条 fixture 的来源、构造方式与适用范围例如 gamma_market_crypto_twap.source.md 记录了 Gamma 接口响应的捕获时间与哈希。这种做法保证了测试数据的可追溯性任何依赖该 fixture 的测试都能回溯到它的真实出处。二、向量的来源与构造原则来源说明文档明确了两条核心原则第一该向量是构造的协议向量而非实时抓包。文档原文写道rtds_crypto_twap_sixty_update.jsonis a constructed protocol vector, not a live capture.该 JSON 是构造的协议向量不是实时捕获。这意味着它的作用是验证解码逻辑是否符合线上协议约定而不是证明某个真实时刻的行情内容。第二向量中的关键字段取自 Polymarket 官方 SDK 的回归测试向量。文档指出其中的时间戳timestamps、交易对symbol、显示值display value以及精确的 signed-E18 值来自 Polymarket 官方 TypeScript SDK 与 Python SDK 的回归测试用例分别位于其订阅层测试的rtds.test.ts与test_streams_rtds_events.py中且引用了不可变的提交immutable commits以保证来源稳定60 秒主题crypto_prices_twap_sixty与window_s字段则采用了这两套测试中的 60 秒用例。这一设计体现了适配器测试的工程惯例以交易所官方 SDK 的已验证回归数据作为基准向量保证 Nautilus 的解码结果与官方客户端行为一致。同时文档也对向量边界做出明确声明——它只用于验证数据客户端路由与精确线上解码不是实时 RTDS 投递行为或边界行为的证据。三、线上报文格式全解测试向量 rtds_crypto_twap_sixty_update.json 的完整内容如下{ connection_id: connection-1234567890, topic: crypto_prices_twap_sixty, type: update, timestamp: 1772752582004, payload: { symbol: btc/usd, timestamp: 1772752581815, value: 65000.12345678901, full_accuracy_value: 65000123456789012345678, window_s: 60 } }报文由信封envelope与载荷payload两层构成字段逐一说明层级字段值含义envelopeconnection_idconnection-1234567890WebSocket 连接标识测试构造值envelopetopiccrypto_prices_twap_sixty60 秒 TWAP 主题envelopetypeupdate报文类型RTDS TWAP 仅有update帧envelopetimestamp1772752582004发布方publisher毫秒时间戳payloadsymbolbtc/usd小写斜杠分隔的品种符号payloadtimestamp1772752581815Chainlink 观测毫秒时间戳payloadvalue65000.12345678901仅用于显示的数值非权威payloadfull_accuracy_value65000123456789012345678signed-E18 精确值字符串权威payloadwindow_s60TWAP 回看窗口秒数在 rtds.rs 的源码中RtdsTopic枚举定义了四种主题其中 TWAP 主题有两个Self::CryptoPricesTwapThirty crypto_prices_twap_thirty, Self::CryptoPricesTwapSixty crypto_prices_twap_sixty,对应的载荷反序列化结构CryptoTwapPayloadRaw同文件约第 300 行定义了严格类型#[derive(Debug, Deserialize)] struct CryptoTwapPayloadRaw { symbol: String, timestamp: u64, #[serde(rename value, deserialize_with deserialize_crypto_twap_value)] display_value: Decimal, // 仅校验线上符合性从不发布 full_accuracy_value: String, window_s: u32, }注意display_value字段上的注释display-only field validated for wire conformance, never published仅供线上符合性校验从不发布这一设计在自定义数据类型 data_types.rs 中也有明确表述The adapter derivesvalueonly from the exact signed E18 provider field. The numeric display field in the RTDS payload is never authoritative.适配器只从精确的 signed-E18 供应商字段推导valueRTDS 载荷中的数字显示字段绝不具有权威性。四、signed-E18 精确值解码为何显示字段不可信这是整个向量最核心的技术点。full_accuracy_value的值65000123456789012345678是一个signed E18 整数它表示以 10 的 18 次方为缩放因子的定点数即真实值为65000123456789012345678 / 10^18 65000.123456789012345678。Nautilus 用 rtds.rs 中的decimal_from_signed_e18函数完成解码fn decimal_from_signed_e18(field: str, value: str) - anyhow::ResultDecimal { let digits value.strip_prefix(-).unwrap_or(value); if digits.is_empty() || !digits.bytes().all(|byte| byte.is_ascii_digit()) { anyhow::bail!(invalid signed E18 integer for {field}: {value}); } let mantissa value .parse::i128() .with_context(|| format!(signed E18 integer out of range for {field}: {value}))?; Decimal::try_from_i128_with_scale(mantissa, 18) .with_context(|| format!(signed E18 value out of Decimal range for {field}: {value})) }该函数执行三层校验字符合法性必须是纯 ASCII 数字允许前导负号、i128 范围超出范围报 out of range、Decimal 精度范围rust_decimal 的Decimal支持 28~29 位有效数字若超出则报 out of Decimal range。测试用例test_handle_crypto_twap_update_rejects_out_of_decimal_range_value用79228162514264337593543950336超过 Decimal 上限验证了第三层拦截。之所以必须以字符串形式传输精确值是因为线上显示字段value是普通的 JSON 浮点数65000.12345678901浮点表示会引入尾数误差无法表达65000.123456789012345678这种 18 位小数精度。若直接用浮点字段计算TWAP 价格的精确性就会丢失。这一点由单元测试test_handle_crypto_twap_update_uses_exact_field_not_display_value验证即使把value篡改为1最终发布的 TWAP 值仍是精确字段解析出的65000.123456789012345678。解码得到精确值后适配器将其封装为自定义数据类型PolymarketRtdsCryptoTwap定义于 data_types.rs通过 Nautilus 的CustomData机制进入数据引擎pub struct PolymarketRtdsCryptoTwap { pub symbol: String, // 小写斜杠分隔符号如 btc/usd pub window_seconds: u32, // 30 或 60 pub value: Decimal, // 由 signed E18 解码的精确值 pub observation_timestamp_ms: u64, // Chainlink 观测毫秒时间戳 pub message_timestamp_ms: u64, // RTDS 发布方毫秒时间戳 pub ts_event: UnixNanos, // 事件发生时间纳秒 pub ts_init: UnixNanos, // 实例初始化时间纳秒 }值得注意的是 TWAP 数据类型的 JSON 序列化也会保留精确小数。data_types.rs中的测试test_crypto_twap_json_round_trip_preserves_exact_decimal验证了64997.810000000000000001与64997.810000000000000002两个相邻值序列化后字符串不同证明 TWAP 值在 Nautilus 内部与外部传输全程保持精确。五、窗口匹配与重放防护admit_twap_observation的守护逻辑解码只是第一步适配器在发布前还执行了严格的时序与一致性校验。入口函数 rtds.rs 中的handle_crypto_twap_update依次完成主题订阅检查若当前没有crypto_prices_twap_sixty或 thirty主题的订阅直接忽略该帧window_s与主题匹配校验载荷中的window_s必须与主题对应的窗口一致否则报错RTDS TWAP topic ... requires window_s60, received ...。测试test_handle_crypto_twap_update_rejects_topic_window_mismatch_without_advancing_guard验证了把window_s改为 30 会触发可见失败signed-E18 解码使用上一节所述的decimal_from_signed_e18时间戳溢出校验payload.timestamp与envelope.timestamp都会通过unix_nanos_from_millis转换为纳秒并检查溢出观察准入与重放防护调用admit_twap_observation这是防重放的关键。admit_twap_observation按(topic, symbol)维护last_twap_fingerprint最后一条 TWAP 观测的时间戳值指纹规则如下更旧时间戳的观测直接丢弃timestamp_ms previous.timestamp_ms时返回Ok(None)相同时间戳且值相同视为重放如断线重连后的重复投递静默忽略相同时间戳但值不同视为协议冲突抛出可见错误conflicting RTDS TWAP observation topic... symbol... timestamp_ms... prior... received...且不推进指纹——冲突后仍以先前观测为权威只有更新的时间戳才能恢复发布指纹按 symbol 隔离不同品种的时序互不影响test_twap_replay_fingerprints_are_isolated_by_symbol验证。这一整套逻辑在 data_types.rs 的类型文档中也有完整描述The adapter suppresses older observations and exact same-timestamp redeliveries. A changed value at the same observation timestamp is reported as a protocol error and is not emitted.适配器抑制更旧观测与相同时间戳的重复投递相同观测时间戳下值发生变化会作为协议错误报告且不发布。之所以如此严格是因为 RTDS 对 TWAP 类型不提供快照、历史或断线重连后的回放——订阅从下一条update帧开始。这意味着任何重复或乱序的帧如果不被过滤都会污染策略看到的价格序列。六、单元测试向量驱动解码正确性该向量在 rtds.rs 的单元测试模块中以常量形式被引入约第 1725 行// Constructed from the official Polymarket SDK regression vector; see its source sidecar. const RTDS_CRYPTO_TWAP_SIXTY_UPDATE_FIXTURE: str include_str!(../test_data/rtds_crypto_twap_sixty_update.json);围绕它构建的测试覆盖了完整的解码与校验矩阵可归纳为以下几组验证主题代表测试精确值发布与三个时钟test_handle_crypto_twap_update_emits_exact_provider_value_and_three_clocks断言value 65000.123456789012345678、observation_timestamp_ms 1772752581815、message_timestamp_ms 1772752582004显示字段非权威test_handle_crypto_twap_update_uses_exact_field_not_display_value30 秒主题适配test_handle_crypto_twap_update_accepts_thirty_second_topic_only_for_thirty_window负值 signed-E18test_handle_crypto_twap_update_preserves_negative_signed_e18_value-1234567890000000000→-1.234567890000000000相邻 E18 值区分test_handle_crypto_twap_update_preserves_adjacent_e18_values等时间戳重放丢弃test_handle_crypto_twap_update_drops_equal_timestamp_redelivery冲突可见性test_twap_conflict_does_not_advance_replay_guard缺字段/错类型/错窗口test_handle_crypto_twap_update_rejects_missing_exact_value_without_fallback、..._rejects_missing_window、..._rejects_wrong_type_on_active_topic等时间戳溢出test_handle_crypto_twap_update_rejects_timestamp_overflow_without_advancing_guard订阅映射test_track_subscribe_maps_twap_window_to_exact_topic30/60 秒各自映射到精确主题拒绝 45 秒等非法窗口断线重连时序test_server_disconnect_preserves_twap_replay_fingerprint、test_reconnect_quiesces_old_twap_tail_before_new_loop_delivery例如冲突测试断言了精确的错误消息conflicting RTDS TWAP observation topiccrypto_prices_twap_sixty symbolbtc/usd timestamp_ms1772752581815 prior65000.123456789012345678 received65000.123456789012345679其中prior与received展示了 18 位小数精度下两个相邻 E18 值末尾相差 1被完整保留并区分。七、集成测试数据客户端路由的端到端验证除了单元测试该向量还出现在 tests/integration/data_client.rs 的集成测试中承担数据客户端路由验证职责。集成测试启动一个模拟的 RTDS WebSocket 服务器handle_rtds_socket当它检测到客户端订阅了crypto_prices_twap_sixty主题时会把该向量作为update帧推送给客户端if is_twap_subscribe { let update load_json(rtds_crypto_twap_sixty_update.json).to_string(); if socket.send(Message::Text(update.into())).await.is_err() { break; } }这验证了从 WebSocket 线上报文到 Nautilus 数据客户端事件通道的完整调用链报文到达 → 信封解析 → 载荷解码 → 自定义数据类型构造 → 以DataEvent::Data(Custom(...))形式路由到订阅方。来源说明文档所说的验证 NT 的公共数据客户端路由和精确线上解码verifies NTs public contenteditable="false">【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考