iTick 加密货币实时行情接入:BTC/USD 与 ETH/USD(REST + WebSocket)

iTick 加密货币实时行情接入:BTC/USD 与 ETH/USD(REST + WebSocket)

2026年3月14日7 分钟阅读10,780 次阅读
#iTick#加密行情#BTC#ETH#WebSocket

一、你真正要接入的是“可信的价格”,不是“能收到的数据”

BTC/ETH 实时行情接入看似简单:拉一个 REST 快照,开一个 WebSocket 订阅,打印一下价格就结束。但只要你准备让它长期运行(比如作为策略信号源、告警触发、或内容站点的数据面板),问题会立刻出现:断线、乱序、重复、偶发异常值、以及“同一时刻不同源给出不同价格”。

所以本文不追求最短 demo,而是给一套生产化的接入思路:先定内部口径,再搭 REST + WS 的双链路,最后用去重/补洞/对账把价格变成可信输入。标题里的 BTC/USD 与 ETH/USD 只是两个样例标的,你把它替换成任意加密交易对也成立。

二、一张图理解系统:REST 做基准,WS 做增量

把接入想成两条流水线:

  • REST:用于启动对齐(快照)、断线补洞(补齐窗口)、事后对账(验证 WS 是否漏数据)。
  • WebSocket:用于实时增量(持续推送),在低延迟场景下承担“主输出”。

核心原则是:WS 负责快,REST 负责对;两者都必须能落到同一个内部数据模型,否则你永远无法解释“为什么实盘触发了、回放却没有”。

三、内部数据模型(建议你直接照抄这份字段清单)

加密行情最容易踩的坑是“字段看似都有,语义却不一致”。建议从一开始就把下游可见的 tick 写成固定结构:

  • symbol:统一成你自己的命名,例如 CRYPTO:BTCUSD / CRYPTO:ETHUSD,不要让交易所/供应商命名泄漏到业务层。
  • ts:事件时间(event time),统一 UTC 毫秒。必要时同时保留 recvTs(接收时间)用于测延迟。
  • price:你用于策略/看板的价格,建议优先 mid 或 last,但必须写清楚是哪一种。
  • bid/ask:如果上游提供,强烈建议保留,用于点差、滑点与异常检测。
  • source:固定 "itick",为未来多源扩展预留空间。

你可以很克制:不需要一次把所有字段都收进来,但必须“稳定”。稳定比丰富更重要。

四、用 iTick REST 拉快照(启动对齐 + 对账基准)

启动时的第一个动作不是订阅,而是把状态对齐:你要知道当前价大概在哪、时间戳从哪里开始、以及系统是否处于“新的一天/新的一段交易时段”。

示例(Python,参数与返回字段以 iTick 文档为准):

python
import requests

BASE = "https://api.itick.org"
TOKEN = "your_api_token"

headers = {"accept": "application/json", "token": TOKEN}
params = {"region": "US", "code": "BTCUSD"}

r = requests.get(f"{BASE}/crypto/tick", params=params, headers=headers, timeout=15)
r.raise_for_status()
data = r.json()
print(data)

工程要点:

  • timeout 必须有;重试要指数退避;429/5xx 分开处理。
  • 快照只作为“基准”,不要用它驱动高频逻辑,否则你会被限流与延迟卡住。
  • 把快照结果记录下来(包括 raw 响应),这对排查数据问题非常关键。

五、WebSocket 订阅(实时增量)与长期运行三件套

实时流能跑不难,能跑一周不掉线才算开始。你需要的不是一段 on_message,而是三件套:

  • 心跳:用 ping/pong 或应用层心跳,明确“多久没消息算断线”。
  • 自动重连:断线后按退避重连,避免重连风暴;重连成功后要重新订阅。
  • 有状态去重:既要去掉重复消息,也要处理乱序消息,至少保证下游看到的是“单调推进”的序列。

订阅示例(伪代码风格):

python
import json
from websocket import WebSocketApp

WS = "wss://api.itick.org/crypto"
TOKEN = "your_api_token"

last_ts = {"CRYPTO:BTCUSD": 0, "CRYPTO:ETHUSD": 0}

def on_open(ws):
    ws.send(json.dumps({"type": "auth", "token": TOKEN}))
    ws.send(json.dumps({"type": "subscribe", "symbols": ["CRYPTO:BTCUSD", "CRYPTO:ETHUSD"]}))

def on_message(ws, message):
    msg = json.loads(message)
    if msg.get("type") != "tick":
        return
    tick = msg.get("data") or {}
    symbol = tick.get("symbol")
    ts = int(tick.get("ts", 0))
    if symbol and ts and ts > last_ts.get(symbol, 0):
        last_ts[symbol] = ts
        # 写入:统一模型 -> 入库/缓存 -> 触发规则

app = WebSocketApp(WS, on_open=on_open, on_message=on_message)
app.run_forever(ping_interval=15, ping_timeout=10)

这里的 last_ts 是最小化示意。生产环境建议用“最后确认写入的序号/时间戳 + 可回放的日志”,否则一旦重启你就无法复现系统状态。

六、数据质量:加密行情“偶发异常值”比你想象得常见

加密市场数据质量问题通常不是持续错误,而是偶发尖刺:某个瞬间价格跳到极端值、点差扩大到异常、或某一段时间更新频率突然下降。你不需要上来就做复杂模型,先用三条规则就能过滤掉大部分事故:

  • 单点离群:价格相对过去 N 秒/分钟的变化超过阈值(阈值与波动绑定)。
  • 频率异常:单位时间内消息量突然下降(可能是连接半死不活)。
  • 点差异常:bid/ask 点差超过正常水平时,禁止触发交易类动作,只做展示或降频。

这些规则的目的不是“预测”,而是“保护下游系统不被脏数据击穿”。

七、断线补洞:把“缺口”显式化,别假装不存在

WebSocket 断线是常态。正确做法是:把缺口变成一等公民。

  • 断线发生:记录断线时间、最后一个已确认写入的 ts。
  • 重连成功:先用 REST 拉取缺口区间(或用历史接口补齐 bar),再恢复 WS 增量。
  • 对账:对比补洞结果与 WS 的序列,确认没有“悄悄漏掉”。

你会发现,一旦补洞机制建立,很多诡异问题(回放对不上、策略触发不一致)都会消失。

八、落地场景:行情接入一旦可靠,后面所有文章都能变得更“硬”

当 BTC/ETH 行情链路稳定之后,你可以非常自然地扩展:

  • 风控告警:波动突变、点差扩大、价格越界、数据延迟报警。
  • 内容看板:在文章页展示关键价格与当日涨跌,做到“观点与数据同屏”。
  • 研究回放:把 WS 实时流落库,配合 REST 补洞,形成可复现的数据集。

这也是为什么我建议你把“接入”写成系统,而不是写成一段示例:系统一旦打牢,之后每一篇策略/研究文章都不会再为基础链路重复造轮子。

九、风险提示与边界

本文的目的在于提供研究与工程方法论,不构成任何投资建议。不同资产、不同市场与不同阶段的主导变量会变化,读者应结合自身风险承受能力与合规要求使用数据与结论。

所有 API 接入示例都以 iTick 的接口规范为参考,实际返回字段与参数以官方文档为准。生产环境务必加入超时、重试、监控与告警,并对关键数据做校验与对账。

十、延伸阅读

如果你希望把本文的方法继续扩展到“策略回测→实盘部署”,建议再补齐三块能力:数据存储与回放(保证复现)、参数与版本管理(保证可迭代)、以及风控与告警(保证可长期运行)。当这三块补齐后,你的研究与工程会进入一个稳定的正循环。

对于内容型博客而言,同样建议把“变量、口径、验证、复盘”固化为模板:每周更新一次关键变量,每月回顾一次框架有效性。这样你写的每一篇文章都在为同一套系统积累资产,而不是一次性的观点输出。