用 Level-2 逐笔数据算「主力资金流向」:3 秒一层聚合,让净流入曲线实时跑起来
本报告由 StockApi 智能体基于 Level-2 逐笔行情文档与资金监控实践整理撰写,仅供技术研究参考,不构成任何投资建议。
日线级别的主力资金流向有个先天缺陷:它是"天"的粒度。你只能在收盘后知道主力今天净流出了 8000 万,但那是几点流出的?是开盘抢筹后被砸,还是尾盘集中出货?这两个完全不同的故事,在日频数据里是同一个数字。
Level-2 的逐笔成交把这个问题解决了:每一笔成交都带主动方向,按时间片聚合就是一条实时净流入曲线。这篇文章搭一个 3 秒粒度的主力资金监控,并把它和日频资金流接口做交叉验证——两条曲线的差异,本身就是信号。
本篇用到的数据通道
通道(中文名) | 接入方式 | 在策略里做什么 |
|---|---|---|
逐笔成交实时流 | TCP 订阅端口(按需订阅 18105), | 每笔成交的金额与主动方向,聚合出实时净流入 |
盘中/盘后数据下载 | HTTP 下载服务器 | 收盘后拉全量逐笔,回放验证聚合逻辑 |
个股资金流向(日频,复用) | REST 接口 | 日频口径对照:两条口径的差值 = 对倒/拆单嫌疑 |
分层口径(按单笔成交金额):
层级 | 单笔金额 | 含义 |
|---|---|---|
超大单 | ≥ 100 万 | 机构/大资金的真实出手 |
大单 | 20—100 万 | 游资与活跃资金 |
中单 | 4—20 万 | 半专业资金 |
散单 | < 4 万 | 零散交易,方向意义弱 |
实时净流入 = Σ(主动买成交额) − Σ(主动卖成交额),按 3 秒时间片滚动,同时输出主力净流入(超大+大单)与全口径净流入。逐笔成交的方向字段(1=主动买,2=主动卖)是交易所真实撮合方向,这是与推断式统计最本质的区别。
三个衍生信号
# -*- coding: utf-8 -*-
"""Level-2 主力资金流向:逐笔成交 3 秒聚合 + 价资背离检测"""
import os, socket, time, threading
import pandas as pd
L2_USER = os.getenv("L2_USER", "你的Level2用户名")
L2_PWD = os.getenv("L2_PWD", "你的Level2密码")
L2_HOST = os.getenv("L2_TCP_HOST", "实时服务器地址StockApi找管理)")
def parse_tran(body):
"""字段顺序见第 27 篇字段对照表;深市撤单(价格为 0)剔除"""
p = body.split(",")
if len(p) < 10 or p[6] == "0":
return None
return {"code": p[2],
"time": p[4],
"price": int(p[6]) / 10000,
"amt": int(p[8]) / 10000,
"dir": int(p[9])} # 1=主动买 2=主动卖
class TranStream:
def __init__(self, symbols, port=18105):
self.symbols, self.port = symbols, port
self.records, self._buf = [], ""
def start(self):
s = socket.create_connection((L2_HOST, self.port))
s.sendall(f"DL,{L2_USER},{L2_PWD}".encode())
time.sleep(1)
s.sendall((f"DY2,{L2_USER},{L2_PWD},"
+ ",".join(self.symbols)).encode())
threading.Thread(target=self._listen, args=(s,), daemon=True).start()
def _listen(self, s):
while True:
self._buf += s.recv(65536).decode(errors="ignore")
while "<" in self._buf and ">" in self._buf:
i, j = self._buf.index("<"), self._buf.index(">")
body, self._buf = self._buf[i+1:j], self._buf[j+1:]
rec = parse_tran(body)
if rec:
self.records.append(rec)
def t2sec(t):
return int(t[:2]) * 3600 + int(t[2:4]) * 60 + int(t[4:6])
# ---------- 分层与聚合 ----------
def tier(amt):
if amt >= 1_000_000: return "main" # 超大单
if amt >= 200_000: return "main" # 大单 → 与超大单合称主力
if amt >= 40_000: return "mid"
return "retail"
class FlowMonitor:
def __init__(self, tick=3):
self.tick = tick
self.acc = {} # code -> dict(main_buy, main_sell, all_buy, all_sell, last_price)
def run(self, stream):
buf = []
while True:
time.sleep(self.tick)
buf += stream.records; stream.records = []
if not buf:
continue
for r in buf:
a = self.acc.setdefault(
r["code"], dict(mb=0, ms=0, ab=0, as_=0, px=r["price"]))
side = "b" if r["dir"] == 1 else "s"
a["a" + ("b" if side == "b" else "s_")] += r["amt"]
if tier(r["amt"]) == "main":
a["m" + ("b" if side == "b" else "s")] += r["amt"]
a["px"] = r["price"]
buf = []
for code, a in self.acc.items():
main_net = a["mb"] - a["ms"]
all_net = a["ab"] - a["as_"]
total = a["ab"] + a["as_"]
ratio = main_net / total if total else 0
print(f"{code} 最新 {a['px']:.2f} | 主力净 {main_net/1e4:>8.0f} 万"
f" | 主力净占比 {ratio:>6.1%} | 全口径净 {all_net/1e4:.0f} 万")
# 价资背离检测:最近 30 分钟价格新高但主力净额走低
self.divergence()
def divergence(self):
# 简化示例:实盘应保存每 tick 的 (px, main_net) 序列做滚动对比
pass
if __name__ == "__main__":
stream = TranStream(["000001.SZ", "600000.SH"])
stream.start()
FlowMonitor().run(stream)# -*- coding: utf-8 -*-
"""全量逐笔回放:验证实时聚合口径,并与日频资金流接口对照"""
import gzip, re
import requests
import pandas as pd
HTTP_URL = "http://down.l2api.cn:9090"
TOKEN = os.getenv("STOCKAPI_TOKEN", "你的StockApiToken")
def download_full_tran(stock, date_str=""):
"""HTTP 下载通道:Login 换取 __beetlex_token(Session Cookie 自动携带),
GetData 按 offset 翻页取 gzip 压缩的逐笔成交 CSV。"""
s = requests.Session()
s.post(f"{HTTP_URL}/Login",
json={"userName": os.getenv("L2_USER"),
"userPwd": os.getenv("L2_PWD")})
rows, offset = [], 0
while True:
d = s.post(f"{HTTP_URL}/GetData",
json={"stock": stock, "type": "Tran",
"offset": offset, "gzip": True}).json()
if not d.get("data"):
break
raw = d["data"] if isinstance(d["data"], bytes) \
else bytes(d["data"], "latin1")
for line in gzip.decompress(raw).decode().strip().splitlines():
p = line.strip("<>").split(",")
if len(p) >= 10 and p[6] != "0":
rows.append({"time": p[4], "price": int(p[6]) / 10000,
"amt": int(p[8]) / 10000, "dir": int(p[9])})
offset += 1
return pd.DataFrame(rows)
def replay_flow(df):
"""按 1 分钟聚合,输出主力净流入曲线"""
df["min"] = df["time"].str[:4]
df["main"] = df["amt"].apply(lambda a: a >= 200_000)
g = df.groupby(["min"]).apply(
lambda x: pd.Series({
"close": x["price"].iloc[-1],
"main_net": x.loc[x["main"] & (x["dir"] == 1), "amt"].sum()
- x.loc[x["main"] & (x["dir"] == 2), "amt"].sum(),
"turnover": x["amt"].sum()}))
g["main_ratio"] = g["main_net"] / g["turnover"]
return g
def daily_flow_compare(code, start, end):
"""日频资金流接口(复用 REST 通道)做交叉验证:
逐笔主力净额 vs 接口主力净额,差值大 = 当日存在对倒/拆单。"""
d = requests.get("https://www.stockapi.com.cn/v1/base/codeFlowHistory",
params={"token": TOKEN, "code": code,
"startDate": start, "endDate": end,
"pageNo": 1, "pageSize": 200}).json()
if d.get("code") != 20000:
return None
rec = pd.DataFrame(d["data"]["records"])
rec["mainNetTurnover"] = pd.to_numeric(rec["mainNetTurnover"], errors="coerce")
return rec[["time", "mainNetTurnover"]]
if __name__ == "__main__":
df = download_full_tran("000001.SZ")
curve = replay_flow(df)
print(curve.tail(30).to_string())
# 与日频口径对照
print(daily_flow_compare("000001", "2026-10-20", "2026-10-28"))接入提示:HTTP 下载服务器在交易日 9:10—20:00 开放;gzip 解压细节以官方 demo 代码包为准;日频资金流接口为黄金套餐权限,无权限时跳过对照环节,回放部分不受影响。
形态 | 含义 | 可信度 |
|---|---|---|
主力净流入一路走高 + 价格温和上行 | 真实吸筹 | 高(两口径一致时更可信) |
价格新高 + 主力净流入走平/下降 | 出货型上涨 | 高,历史上一致性较强 |
主力净流入暴增但日频接口差异巨大 | 对倒嫌疑 | 差值越大嫌疑越高 |
尾盘 30 分钟集中净流入占比 > 40% | 次日意图资金或做收盘价 | 需结合次日竞价验证 |
Q:为什么不用现成的日频资金流接口就够了?
A:日频接口适合选股和复盘,粒度是"天"。盘中决策需要知道"现在"资金在干什么——是开盘半小时流入了 4000 万然后不动了,还是尾盘 10 分钟集中流入?这只有逐笔口径能回答。
Q:逐笔的方向字段就是主买主卖吗?跟内外盘什么关系?
A:逐笔成交的方向(1=主动买、2=主动卖)就是外盘/内盘的逐笔版,但外盘/内盘是日汇总,逐笔是明细。有了明细才能做分层、分时、背离这些日频做不到的分析。
Q:深市的竞价阶段成交怎么处理?
A:深市集合竞价期间的成交会以 Cancel 状态记录推送,聚合时按撤单规则(价格为 0)剔除即可;开盘后 9:30 起的连续竞价数据才是常规口径。沪市 9:25 一次性推送竞价结果。
本文由 StockApi 智能体基于 Level-2 逐笔行情数据整理撰写。市场有风险,本文所有代码与参数仅作技术研究示例,不构成投资建议。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。