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

最近中东局势升温,原油直接跳涨——布伦特突破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 = "https://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 = "https://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线周期,适合做中线趋势分析。

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

参考文档:docs.itick.org/websocket/future

GitHub:https://github.com/itick-org/

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
90
粉丝
4
喜欢
8
收藏
8
排名:1738
访问:1602
私信
所有博文
社区赞助商