Python A股实时行情API接入:沪深股票数据与WebSocket推送实战

做国内量化或者行情工具的开发者,A股数据肯定是绕不开的。但接A股数据的时候有个问题:A股的交易规则跟美股、港股都不一样——涨跌停、T+1、集合竞价、午休,这些规则在API数据里是怎么体现的?
A股实时行情API接入
这篇从A股交易规则出发,讲一下怎么用Python接A股实时行情,以及这些特殊规则在返回数据里怎么对应。如果你在找一个稳定的股票数据接口或者实时行情API,这篇应该能帮你省掉不少踩坑的时间。

为什么需要专业的A股数据接口

做量化策略或者行情面板的时候,数据是最基础的。一开始我试过爬财经网站的页面,但稳定性太差了——页面结构一改就挂,而且延迟很高,做实时监控根本没法用。后来才转用专业的金融数据API,至少数据格式稳定、接口响应快,不用每天盯着爬虫脚本挂没挂。

选接口的时候主要看几点:一是数据覆盖全不全,沪深两市的股票能不能都拿到;二是实时性够不够,做日内策略延迟太高就没意义了;三是历史K线数据够不够全,回测需要长时间的历史数据。最后找了一圈试了几个接口,留下来一直在用的是itick,主要是接口设计比较干净,文档也写得清楚。

A股交易规则与数据字段的对应

先把A股的交易规则理清楚,这样看返回数据的时候才知道每个字段是什么意思。

交易时间:上午9:30-11:30,下午13:00-15:00。中午有1.5小时休市。

涨跌停:主板股票±10%,创业板/科创板±20%,ST股票±5%。涨停的时候买盘挂单很多,卖盘很少;跌停反过来。

T+1:当天买的股票第二天才能卖,但API返回的成交量和成交额是实时的。

集合竞价:开盘前9:15-9:25是集合竞价时间,这时候也有成交数据。

这些规则在API返回数据里怎么体现呢?看几个关键字段:

  • ts:交易状态,0=正常交易,1=停牌,2=退市,3=熔断。停牌的时候没有成交。

  • ld:最新价。涨停的时候这个价就是涨停价。

  • chp:涨跌幅百分比。±10%就是涨停/跌停了。

  • v:当日累计成交量。

  • tu:当日累计成交额。

REST拉取A股报价

先从REST开始,确认数据格式。做行情面板或者批量拉快照的时候,REST接口最方便。


import requests

API_BASE = "https://api.itick.org"

TOKEN = "your_token_here"

headers = {"accept": "application/json", "token": TOKEN}

# 拉A股实时报价

def  get_a_share_quote(code):

resp = requests.get(

f"{API_BASE}/stock/quote",

headers=headers,

params={

"region": "CN",

"code": code

}

)

return resp.json()["data"]

# 拉几只A股大盘股

stocks = ["600519", "000001", "300750"]

for code in stocks:

q = get_a_share_quote(code)

sign = "+"  if q["chp"] >= 0  else  ""

print(f"{code}: {q['ld']} ({sign}{q['chp']}%)")

返回字段跟其他市场基本一致:ld最新价、chp涨跌幅、o/h/l开高低、v成交量。做技术分析或者行情看板这些字段够用了。

注意:A股代码是6位数字,传参数的时候要传字符串形式(”600519”),不要传数字。一开始我传了数字类型,结果接口返回参数错误,折腾了半天才反应过来。

WebSocket订阅A股

做实时监控或者盘中告警的时候,轮询REST接口效率太低,这时候就得用WebSocket实时推送了。

WebSocket订阅格式跟美股一样,是两个参数:代码$市场。


import json

import threading

import time

import websocket

WS_URL = "wss://api.itick.org/stock"

TOKEN = "your_token_here"

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

# A股订阅格式:代码$市场

ws.send(json.dumps({

"ac": "subscribe",

"params": "600519$CN,000001$CN",

"types": "quote"

}))

return

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

return

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

if data.get("type") == "quote":

sign = "+"  if data["chp"] >= 0  else  ""

print(f"{data['s']}: {data['ld']} ({sign}{data['chp']}%)")

A股订阅是两个参数(600519$CN),跟美股一样,不是印度那种三个参数。做实时行情推送的时候,WebSocket比轮询REST效率高很多——不需要每秒发一次请求,服务端有数据就主动推过来。

K线数据获取

做技术分析或者策略回测的时候,需要历史K线数据。K线接口跟其他市场一样,只是region传 CN。


def  get_a_share_kline(code, k_type=8, limit=100):

"""

k_type: 1=1分钟 2=5分钟 5=1小时 8=日K 9=周K 10=月K

"""

resp = requests.get(

f"{API_BASE}/stock/kline",

headers=headers,

params={

"region": "CN",

"code": code,

"kType": k_type,

"limit": limit

}

)

return resp.json()["data"]

# 拉贵州茅台近100根日K

daily = get_a_share_kline("600519", k_type=8, limit=100)

closes = [bar["c"] for bar in daily]

# 算20日均线

ma20 = sum(closes[-20:]) / 20

print(f"600519最新收盘: {closes[-1]}, 20日均线: {ma20:.2f}")

K线返回标准OHLCV:t时间戳、o/h/l/c开高低收、v成交量。做技术分析直接用这些字段就行,不用自己再清洗数据。

A股特有的注意事项

交易时间有午休。 A股中午休市1.5小时(11:30-13:00),这个时间段没有成交数据。做实时监控的时候要注意,别把午休时间当成流动性枯竭——我一开始做告警的时候,午休期间一直没数据还以为接口挂了,后来才反应过来是休市了。

涨跌停判断。 主板股票涨跌幅超过±10%就是涨停/跌停,创业板/科创板是±20%。做策略的时候要判断当前是否涨停,涨停的时候买不进去。可以通过chp字段判断,如果涨跌幅接近10%或者20%就要小心了。

代码是6位数字。 A股代码是6位数字(600519、000001),跟港股的5位数字(00700)、日本的4位数字(7203)都不一样。一开始我传了”700”,结果返回空数据——那是港股腾讯的代码,A股没有700这个代码。

region是CN。 A股市场region传 CN,不是 SH 或 SZ。

集合竞价时间。 开盘前9:15-9:25是集合竞价,这时候也有成交数据,但价格波动很大。做策略的时候要注意区分集合竞价和连续竞价,别把集合竞价的成交量当成正常交易的量。

完整脚本:A股行情监控

把前面几块拼起来,最终的完整脚本:


import json, time, threading, requests, websocket

API_BASE = "https://api.itick.org"

WS_URL = "wss://api.itick.org/stock"

TOKEN = "your_token_here"

headers = {"accept": "application/json", "token": TOKEN}

# A股监控列表

watchlist = ["600519", "000001", "300750"]

# 启动时拉快照

print("=== A股快照 ===")

for code in watchlist:

r = requests.get(f"{API_BASE}/stock/quote",

headers=headers,

params={"region": "CN", "code": code}).json()["data"]

sign = "+"  if r["chp"] >= 0  else  ""

print(f" {code}: {r['ld']} ({sign}{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

params = ",".join(f"{c}$CN"  for c in watchlist)

ws.send(json.dumps({

"ac": "subscribe",

"params": params,

"types": "quote"

}))

threading.Thread(target=heartbeat, args=(ws,), daemon=True).start()

return

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

return

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

if data.get("type") == "quote":

sign = "+"  if data["chp"] >= 0  else  ""

print(f"[实时] {data['s']}: {data['ld']} ({sign}{data['chp']}%)")

def  heartbeat(ws):

while  True:

time.sleep(30)

ws.send(json.dumps({"ac": "ping", "params": str(int(time.time() * 1000))}))

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

ws.run_forever()

这个脚本跑起来之后,开盘前先看到一组A股的快照,盘中实时更新价格和涨跌幅。做行情面板或者盘中告警的话,这个基础上再扩展就行。

小结

接A股数据的技术框架跟美股差不多——REST做快照和历史数据,WebSocket做实时推送。主要区别在交易规则(涨跌停、T+1、午休)和代码格式(6位数字)。这些细节不踩一遍坑很容易忽略。

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

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

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

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