期货数据接口开发:实时报价与五档盘口WebSocket接入

用户头像Fxdund
2026-09-18 发布

最近中东局势升温,原油直接跳涨——布伦特突破108美元,WTI站上103,国内SC原油更是一天涨了11%冲破900元大关。这种波动率下,做期货数据监控的人最关心的不是最新价一个数字,而是买卖盘口的厚度变化:大单托底还是压盘,多空力量在哪个价位堆积。

做量化或者行情工具开发的人都知道,期货数据接口跟股票接口看起来差不多,但实际接入时有几个关键差异。这篇从技术角度记录一下用Python接入期货行情API的完整过程,重点讲实时报价和五档盘口数据怎么拿、怎么解析、怎么用。

期货行情API与股票接口的核心差异

接之前先搞清楚几个差异,不然容易照搬股票的写法踩坑。

路径是 /future/ 单数形式。 跟股票 /stock/ 一样,别写成 /futures/。这个我第一次接的时候就404了,查了半天才发现。

市场代码用 USHKCN 美国商品期货(GC黄金、CL原油、ZS大豆)用 US,国内期货用 CN。这个跟指数接口用 GB 不一样,别搞混了。

期货多了盘口depth数据。 股票接口虽然也支持depth,但期货的盘口分析更常见——因为期货是撮合交易,买卖盘口直接反映了流动性和多空力量。做短线策略的话,光看最新价根本不够。

K线周期多了2小时和4小时。 股票和指数的kType到1小时就是5,然后直接跳到日K(8)。期货多了 kType=6(2小时)和 kType=7(4小时),这是因为期货交易时段长,有些策略用2小时K线做中线判断。

REST API:历史K线与实时报价快照

先从基础的REST接口开始。拉一个商品期货的报价快照,调用方式跟其他产品类似:

import requests

API_BASE = "//api.itick.org"
TOKEN = "your_token_here"
headers = {
    "accept": "application/json",
    "token": TOKEN
}


def get_future_quote(region, code):
    """
    获取期货实时报价快照
    region: US(美盘) CN(国内) HK(港股相关)
    code: 期货合约代码,如 GC(黄金) CL(原油) ZS(大豆)
    """
    resp = requests.get(
        f"{API_BASE}/future/quote",
        headers=headers,
        params={"region": region, "code": code}
    )
    resp.raise_for_status()
    return resp.json()["data"]


# 看一下美盘黄金和原油的快照
for region, code, name in [("US", "GC", "黄金"), ("US", "CL", "原油")]:
    q = get_future_quote(region, code)
    print(f"{name}({code}): 最新={q['ld']} 涨跌幅={q['chp']}% "
          f"高={q['h']} 低={q['l']} 量={q['v']}")

报价字段跟其他产品基本一致:ld最新价、chp涨跌幅、o/h/l开高低、v成交量、p前收。做行情看板的时候,这些字段够用了。

K线接口也类似,但注意kType多了两个周期:

def get_future_kline(region, code, k_type=2, limit=50):
    """
    k_type: 2=5分钟 5=1小时 6=2小时 7=4小时 8=日K
    (期货比股票多了6=2小时和7=4小时两个周期)
    """
    resp = requests.get(
        f"{API_BASE}/future/kline",
        headers=headers,
        params={
            "region": region,
            "code": code,
            "kType": k_type,
            "limit": limit
        }
    )
    resp.raise_for_status()
    return resp.json()["data"]


# 拉原油5分钟K线,看今天波动有多大
cl_kline = get_future_kline("US", "CL", k_type=2, limit=50)
# 计算今天的振幅
today_range = max(bar["h"] for bar in cl_kline) - min(bar["l"] for bar in cl_kline)
print(f"近50根5分钟K线区间振幅: {today_range:.2f}")

原油这种品种波动大,用5分钟K线比日K更能捕捉盘中异动。kType=2就是5分钟,拉最近50根大概覆盖4个多小时的交易。做日内策略回测的时候,这个粒度刚好。

WebSocket实时推送:五档盘口数据接入

REST只能拿到静态快照,盘中盘口变化很快,必须用WebSocket。期货WebSocket的地址是 wss://api.itick.org/future,鉴权流程跟其他产品一样——先等 resAc:"auth" 再订阅。

关键区别在订阅类型。除了常规的 quote,期货还可以订阅 depth(盘口):

import json
import threading
import time
import websocket

WS_URL = "wss://api.itick.org/future"
TOKEN = "your_token_here"
authenticated = False


def start_heartbeat(ws):
    def ping():
        while True:
            time.sleep(30)
            ws.send(json.dumps({
                "ac": "ping",
                "params": str(int(time.time() * 1000))
            }))
    threading.Thread(target=ping, daemon=True).start()


def subscribe(ws):
    # 同时订阅quote和depth两个类型
    # GC=黄金 CL=原油,region=US
    ws.send(json.dumps({
        "ac": "subscribe",
        "params": "GC$US,CL$US",
        "types": "quote,depth"
    }))

注意 types 参数传了两个值:quotedepth,用逗号分隔。这样同一个连接里既能收到最新价推送,也能收到买卖盘口变化。

盘口消息的数据结构跟报价完全不同,是一个数组:

def on_message(ws, message):
    global authenticated
    payload = json.loads(message)

    if payload.get("resAc") == "auth" and payload.get("code") == 1 and not authenticated:
        authenticated = True
        subscribe(ws)
        start_heartbeat(ws)
        return

    if payload.get("resAc") == "pong":
        return

    data = payload.get("data") or {}

    # 报价消息:最新价
    if data.get("type") == "quote":
        print(f"[报价] {data['s']}: {data['ld']} ({data['chp']}%)")

    # 盘口消息:买卖五档
    elif data.get("type") == "depth":
        bids = data.get("b", [])  # 买盘
        asks = data.get("a", [])  # 卖盘
        print(f"\n[盘口] {data['s']}")
        for bid in bids:
            print(f"  买{bid['po']}: {bid['p']}  量={bid['v']}")
        for ask in asks:
            print(f"  卖{ask['po']}: {ask['p']}  量={ask['v']}")

盘口数据的结构:b 是买盘数组,a 是卖盘数组。每个元素有三个字段:

  • po:盘口档位(1=买一/卖一,2=买二/卖二...)
  • p:挂单价格
  • v:挂单数量

这个数据做什么用?一个常见的分析是计算买卖盘力量比——把买盘总量加起来跟卖盘总量比,看哪边更厚。

盘口数据分析:买卖盘力量比计算

盘口原始数据就是一堆挂单,得加工一下才有意义。一个简单的指标是买卖盘总量比:

def analyze_depth(data):
    """
    分析盘口数据,返回买卖盘力量对比
    """
    bids = data.get("b", [])
    asks = data.get("a", [])

    bid_volume = sum(b["v"] for b in bids)
    ask_volume = sum(a["v"] for a in asks)

    if ask_volume == 0:
        ratio = float("inf")
    else:
        ratio = bid_volume / ask_volume

    # 买一卖一价差
    spread = asks[0]["p"] - bids[0]["p"] if bids and asks else 0

    return {
        "bid_total": bid_volume,
        "ask_total": ask_volume,
        "bid_ask_ratio": round(ratio, 2),
        "spread": spread,
        "top_bid": bids[0]["p"] if bids else None,
        "top_ask": asks[0]["p"] if asks else None,
    }


# 在on_message里调用
elif data.get("type") == "depth":
    stats = analyze_depth(data)
    print(f"  {data['s']} 买卖比={stats['bid_ask_ratio']} "
          f"价差={stats['spread']} "
          f"买一={stats['top_bid']} 卖一={stats['top_ask']}")

这个指标很直观:买卖比大于1说明买盘挂单更厚,下方支撑强;小于1说明卖盘压力大。价差(spread)小说明流动性好,价差大说明交易不活跃。

像最近原油这种暴涨行情,盘口数据特别有参考价值——如果卖盘很厚但价格还在涨,说明上方有阻力但买盘更激进;如果买盘在价格上涨过程中持续撤单,那可能是拉高出货。这些光看最新价是看不出来的。

完整实现:商品期货实时行情监控脚本

把报价和盘口拼起来,就是一个完整的期货监控脚本:

import json, threading, time, requests, websocket

API_BASE = "//api.itick.org"
WS_URL = "wss://api.itick.org/future"
TOKEN = "your_token_here"
headers = {"accept": "application/json", "token": TOKEN}

watchlist = ["GC", "CL", "ZS"]  # 黄金、原油、大豆

# 启动时拉快照
def init_quotes():
    print("=== 商品期货快照 ===")
    for code in watchlist:
        r = requests.get(f"{API_BASE}/future/quote",
                         headers=headers,
                         params={"region": "US", "code": code}).json()["data"]
        print(f"  {code}: {r['ld']} ({r['chp']}%)")

# WebSocket实时订阅报价+盘口
authenticated = False

def on_message(ws, message):
    global authenticated
    payload = json.loads(message)
    if payload.get("resAc") == "auth" and payload.get("code") == 1 and not authenticated:
        authenticated = True
        ws.send(json.dumps({
            "ac": "subscribe",
            "params": ",".join(f"{c}$US" for c in watchlist),
            "types": "quote,depth"
        }))
        threading.Thread(target=heartbeat, args=(ws,), daemon=True).start()
        return

    data = payload.get("data") or {}
    if data.get("type") == "quote":
        print(f"[报价] {data['s']}: {data['ld']} ({data['chp']}%)")
    elif data.get("type") == "depth":
        bv = sum(b["v"] for b in data.get("b", []))
        av = sum(a["v"] for a in data.get("a", []))
        ratio = round(bv / av, 2) if av else 0
        print(f"[盘口] {data['s']}: 买卖比={ratio} 买盘={bv} 卖盘={av}")

def heartbeat(ws):
    while True:
        time.sleep(30)
        ws.send(json.dumps({"ac": "ping", "params": str(int(time.time() * 1000))}))

init_quotes()
ws = websocket.WebSocketApp(WS_URL, header=[f"token: {TOKEN}"], on_message=on_message)
ws.run_forever()

这个脚本跑起来之后,开盘前先看到三个品种的快照,盘中同时收到报价和盘口推送。盘口消息的频率比报价更高——每次挂单变化都会推,所以实际跑起来depth消息会很多,如果只关心报价可以只订 quote 不订 depth

接入注意事项与常见问题

盘口消息频率很高,注意限流。 期货挂单变化频繁,depth推送可能一秒好几条。如果在on_message里做了重计算(比如调外部API),很容易跟不上推送速度。建议把depth数据存到一个ring buffer里,用单独的线程去分析,不要在WebSocket回调里做重活。

kType多了6和7。 期货支持2小时K线(kType=6)和4小时K线(kType=7),这是股票和指数没有的。做隔夜趋势分析的时候4小时K线比日K更细腻。

国内期货用region=CN。 上面例子用的是美盘品种(GC、CL),如果要接国内期货比如螺纹钢、铁矿石,region传 CN,代码格式需要查一下文档里的品种列表。

盘口数据的档位深度取决于套餐。 不是所有套餐都能拿到完整五档盘口,有些基础套餐可能只有买一卖一。写代码的时候别假设一定有五档,遍历的时候用 for bid in bids 而不是按下标取。

期货有涨跌停板。 ts 字段为3的时候是熔断/涨跌停,这时候盘口数据可能出现单边挂单——涨停板上全是卖单没人买,或者跌停板上全是买单。分析买卖比的时候要考虑这种极端情况。

总结

期货行情接入的核心思路跟其他产品差不多:REST做初始化和历史数据,WebSocket做实时推送。但期货有两个独特的价值点:一是盘口depth数据,买卖五档挂单直接反映多空力量;二是多了2小时和4小时K线周期,适合做中线趋势分析。

最近原油因为地缘政治暴涨,波动率拉满,这种时候盘口数据的价值比平时更高。有一套自己写的监控脚本,比看行情软件上密密麻麻的五档数字要直观得多。

参考文档:https://docs.itick.org/websocket/future
GitHub:https://github.com/itick-org/

评论