首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Level2 量化实战(二):逐笔聚合主力净流入,并用日频资金流接口交叉验证对倒

Level2 量化实战(二):逐笔聚合主力净流入,并用日频资金流接口交叉验证对倒

原创
作者头像
用户7273352
发布于 2026-11-01 14:42:25
发布于 2026-11-01 14:42:25
2190
举报
文章被收录于专栏:量化接口量化接口

用 Level-2 逐笔数据算「主力资金流向」:3 秒一层聚合,让净流入曲线实时跑起来

本报告由 StockApi 智能体基于 Level-2 逐笔行情文档与资金监控实践整理撰写,仅供技术研究参考,不构成任何投资建议。

日线级别的主力资金流向有个先天缺陷:它是"天"的粒度。你只能在收盘后知道主力今天净流出了 8000 万,但那是几点流出的?是开盘抢筹后被砸,还是尾盘集中出货?这两个完全不同的故事,在日频数据里是同一个数字。

Level-2 的逐笔成交把这个问题解决了:每一笔成交都带主动方向,按时间片聚合就是一条实时净流入曲线。这篇文章搭一个 3 秒粒度的主力资金监控,并把它和日频资金流接口做交叉验证——两条曲线的差异,本身就是信号。

策略原理

本篇用到的数据通道

通道(中文名)

接入方式

在策略里做什么

逐笔成交实时流

TCP 订阅端口(按需订阅 18105),DY2 命令订阅

每笔成交的金额与主动方向,聚合出实时净流入

盘中/盘后数据下载

HTTP 下载服务器 GetData(type=Tran)

收盘后拉全量逐笔,回放验证聚合逻辑

个股资金流向(日频,复用)

REST 接口 /v1/base/codeFlowHistory(黄金套餐)

日频口径对照:两条口径的差值 = 对倒/拆单嫌疑

分层口径(按单笔成交金额):

层级

单笔金额

含义

超大单

≥ 100 万

机构/大资金的真实出手

大单

20—100 万

游资与活跃资金

中单

4—20 万

半专业资金

散单

< 4 万

零散交易,方向意义弱

实时净流入 = Σ(主动买成交额) − Σ(主动卖成交额),按 3 秒时间片滚动,同时输出主力净流入(超大+大单)与全口径净流入。逐笔成交的方向字段(1=主动买,2=主动卖)是交易所真实撮合方向,这是与推断式统计最本质的区别。

三个衍生信号

  1. 主力净占比:主力净流入 / 总成交额。绝对金额受盘子大小影响,占比才可比。
  2. 价资背离:价格创 30 分钟新高,但主力净流入 30 分钟窗口是下降的——出货型上涨。
  3. 尾盘集中度:14:30 后主力净流入占全天比例 > 40%,是典型的"做收盘价"或次日意图资金。

Python 实现一:盘中实时监控(TCP 逐笔流)

代码语言:python
复制
# -*- 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)

Python 实现二:收盘后回放 + 日频口径交叉验证

代码语言:python
复制
# -*- 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%

次日意图资金或做收盘价

需结合次日竞价验证

参数与风控

  • 时间片别太细:1 秒级聚合会被撤单-成交高频博弈打爆噪音,3—5 秒是监控粒度的甜点区。
  • 分层阈值要校准:低价股(2—3 元)100 万单笔对应 30 多万股,出现频率远低于高价股;迁移到新票先看 P99 分位。
  • 与日频接口对照时注意口径:日频接口的主力也是按单笔规模推断的,它俩"应该"有差异,差异本身是信息,不是数据错误。
  • 监控是观察工具:净流入曲线不直接生成买卖信号,要叠加位置与板块判断。

常见问题

Q:为什么不用现成的日频资金流接口就够了?

A:日频接口适合选股和复盘,粒度是"天"。盘中决策需要知道"现在"资金在干什么——是开盘半小时流入了 4000 万然后不动了,还是尾盘 10 分钟集中流入?这只有逐笔口径能回答。

Q:逐笔的方向字段就是主买主卖吗?跟内外盘什么关系?

A:逐笔成交的方向(1=主动买、2=主动卖)就是外盘/内盘的逐笔版,但外盘/内盘是日汇总,逐笔是明细。有了明细才能做分层、分时、背离这些日频做不到的分析。

Q:深市的竞价阶段成交怎么处理?

A:深市集合竞价期间的成交会以 Cancel 状态记录推送,聚合时按撤单规则(价格为 0)剔除即可;开盘后 9:30 起的连续竞价数据才是常规口径。沪市 9:25 一次性推送竞价结果。


本文由 StockApi 智能体基于 Level-2 逐笔行情数据整理撰写。市场有风险,本文所有代码与参数仅作技术研究示例,不构成投资建议。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 策略原理
  • Python 实现一:盘中实时监控(TCP 逐笔流)
  • Python 实现二:收盘后回放 + 日频口径交叉验证
  • 曲线怎么读
  • 参数与风控
  • 常见问题
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档