批量查询五档盘口后,如何按股票汇总买卖盘统计?

本文介绍如何对批量获取的股票五档盘口数据进行标准化汇总统计,包括按股票代码分组计算五档买卖盘总量、量差、量比和价差等核心指标。重点强调数据校验(如档位完整性、委托量非负性)、异常处理(如卖盘为零时避免除零)及使用QuantDash SDK获取数据与Pandas完成统计的分工逻辑,确保结果可用于量化选股与实时监控。

一句话回答

批量查询盘口后,建议以股票代码为分组单位,分别汇总五档买卖盘的委托量、有效档位数和买卖盘量差,并计算盘口量比与买卖价差。这样可以把原始盘口数组整理成适合量化选股、实时监控的数据表。使用 QuantDash Python SDK 获取各股票的五档盘口,再通过 Python 完成字段校验、指标计算和结果汇总,可以让数据接入与业务统计逻辑保持清晰的边界。

为什么会有这个问题 / 传统做法有什么问题?

量化策略需要的盘口信息,通常不止某只股票的买一价和卖一价。

例如,一个盘中监控程序同时观察几十只股票,希望判断哪些股票的买盘委托量相对更大,就需要对每只股票的五档盘口分别统计。

假设某只股票的五档买盘委托量为:

  • 买一:1200
  • 买二:800
  • 买三:1500
  • 买四:600
  • 买五:900

五档买盘总量就是:

1200 + 800 + 1500 + 600 + 900 = 5000

如果同一时点的五档卖盘总量为 4000,那么:

买卖盘量差 = 五档买盘总量 - 五档卖盘总量

即:

5000 - 4000 = 1000

买卖盘量比 = 五档买盘总量 / 五档卖盘总量

即:

5000 / 4000 = 1.25

这些数字仅是为了说明计算方法而构造的假设数据,并非真实行情结果。

这里有个关键区别:买卖盘量差反映的是可见委托量的绝对差值,买卖盘量比反映的是相对关系。量比大于 1,表示当前可见五档买盘总量大于卖盘总量,但不能直接推断股票后续一定上涨。

传统处理方式常见两个问题。

第一,直接把每只股票的原始盘口对象保存下来,却没有转成统一的统计结构。后续筛选、排序时,还需要反复解析嵌套数组。

第二,不区分有效盘口和异常数据。例如某只股票卖盘总量为 0,如果直接计算量比,就会发生除零错误;如果把缺失档位当成正常的零委托量,还可能导致统计口径不一致。

因此,更稳妥的做法是建立统一的数据处理流程:

按股票获取盘口 → 验证数据 → 计算单只股票指标 → 汇总统计结果。

QuantDash SDK 可以参与盘口获取环节,统计与异常处理则由 Python 业务代码完成。

分步骤解决:使用 QuantDash 进行实践

第 1 步:安装 SDK 并初始化客户端

先安装依赖:

# 在终端执行
# pip install quantdash

正式执行安装命令为:

pip install quantdash

然后通过环境变量读取 API Key:

import os
from quantdash import QuantDash

api_key = os.getenv("QUANTDASH_API_KEY")

if not api_key:
    raise RuntimeError(
        "请先设置 QUANTDASH_API_KEY 环境变量"
    )

qd = QuantDash(api_key=api_key)

这里不建议把 API Key 写在代码文件中,尤其是准备将脚本提交到代码仓库时。

第 2 步:获取与主题相关的数据

QuantDash 提供五档盘口接口 qd.depth.get(),可以按股票代码获取盘口数据。

已知调用方式是单只股票查询。这里所谓“批量查询”,是在应用层对股票列表逐只调用接口,不假设 SDK 存在未经确认的盘口批量接口。

symbols = [
    "600519.SH",
    "000001.SZ",
    "600036.SH",
]

depth_results = {}
failed_symbols = {}

for symbol in symbols:
    try:
        depth = qd.depth.get(symbol)

        if depth is None:
            raise ValueError("盘口返回为空")

        depth_results[symbol] = depth

    except Exception as exc:
        failed_symbols[symbol] = str(exc)

print("成功获取数量:", len(depth_results))
print("失败数量:", len(failed_symbols))

qd.depth.get() 接收带交易所后缀的股票代码,例如 600519.SH。

当前已知盘口数据涉及以下字段:

  • bid_prices:买盘价格序列。
  • bid_volumes:买盘委托量序列。
  • ask_prices:卖盘价格序列。
  • ask_volumes:卖盘委托量序列。

需要注意,实际返回对象可能是字典或其他 SDK 数据结构。下面先通过适配函数支持字典和具有同名属性的对象,其他返回形式需要根据接口实际结果调整。

REQUIRED_FIELDS = (
    "bid_prices",
    "bid_volumes",
    "ask_prices",
    "ask_volumes",
)

def normalize_depth(depth):
    if isinstance(depth, dict):
        data = depth
    else:
        data = {
            field: getattr(depth, field, None)
            for field in REQUIRED_FIELDS
        }

    missing = [
        field for field in REQUIRED_FIELDS
        if data.get(field) is None
    ]

    if missing:
        raise ValueError(
            f"盘口缺少必要字段: {missing}"
        )

    return data

字段名称是已知的,但字段值的容器类型、委托量单位和缺失档位表示方式,仍应以实际返回数据为准。

第 3 步:处理数据并展示核心逻辑

接下来,对单只股票统计五档买卖委托量。

这里采用严格的五档统计口径:价格序列和委托量序列必须一一对应,长度为 5,委托量不能为负数,存在委托量的档位必须具有有效正价格。

import math
from numbers import Real

def validate_levels(prices, volumes, side):
    if len(prices) != 5 or len(volumes) != 5:
        raise ValueError(
            f"{side}盘口不是完整的五档结构"
        )

    result = []

    for price, volume in zip(prices, volumes):
        if (
            isinstance(volume, bool)
            or not isinstance(volume, Real)
            or not math.isfinite(volume)
            or volume < 0
        ):
            raise ValueError(
                f"{side}盘口委托量异常"
            )

        if (
            isinstance(price, bool)
            or not isinstance(price, Real)
            or not math.isfinite(price)
            or (volume > 0 and price <= 0)
        ):
            raise ValueError(
                f"{side}盘口价格异常"
            )

        result.append((float(price), float(volume)))

    return result


def calculate_depth_stats(depth):
    data = normalize_depth(depth)

    bids = validate_levels(
        data["bid_prices"],
        data["bid_volumes"],
        "买盘",
    )

    asks = validate_levels(
        data["ask_prices"],
        data["ask_volumes"],
        "卖盘",
    )

    bid_total = sum(volume for _, volume in bids)
    ask_total = sum(volume for _, volume in asks)

    active_bid_levels = sum(
        volume > 0 for _, volume in bids
    )
    active_ask_levels = sum(
        volume > 0 for _, volume in asks
    )

    volume_ratio = (
        bid_total / ask_total
        if ask_total > 0
        else None
    )

    volume_difference = bid_total - ask_total

    best_bid = bids[0][0] if bids[0][1] > 0 else None
    best_ask = asks[0][0] if asks[0][1] > 0 else None

    spread = (
        best_ask - best_bid
        if best_bid is not None
        and best_ask is not None
        else None
    )

    return {
        "bid_total": bid_total,
        "ask_total": ask_total,
        "volume_difference": volume_difference,
        "volume_ratio": volume_ratio,
        "active_bid_levels": active_bid_levels,
        "active_ask_levels": active_ask_levels,
        "spread": spread,
    }

需要特别说明:

bid_total 和 ask_total 分别表示当前可见五档委托量的合计,不是累计成交量。

volume_ratio 在卖盘总量为零时返回 None,避免人为制造一个无限大的指标。

spread 是卖一价减买一价的绝对价差。上述计算还依赖盘口数组按买一至买五、卖一至卖五排序的约定,这一点需要根据实际接口验证。

如果需要更严格的数据质量检查,还应验证买盘价格排序、卖盘价格排序,以及是否存在异常交叉报价。

第 4 步:展示完整业务示例或进阶处理

现在将前面获取的盘口逐只统计,整理为 DataFrame。

此处使用 Pandas 处理统计结果,运行前需要确保环境安装了 pandas。

import pandas as pd

statistics = []

for symbol, depth in depth_results.items():
    try:
        result = calculate_depth_stats(depth)
        result["symbol"] = symbol
        statistics.append(result)

    except (ValueError, TypeError) as exc:
        failed_symbols[symbol] = str(exc)

if not statistics:
    raise RuntimeError(
        "没有可用于汇总的有效盘口数据"
    )

stats_df = pd.DataFrame(statistics)

stats_df = stats_df[
    [
        "symbol",
        "bid_total",
        "ask_total",
        "volume_difference",
        "volume_ratio",
        "active_bid_levels",
        "active_ask_levels",
        "spread",
    ]
]

stats_df = stats_df.sort_values(
    by="volume_difference",
    ascending=False,
)

print(stats_df.to_string(index=False))

if failed_symbols:
    print("未成功统计的股票:")
    for symbol, reason in failed_symbols.items():
        print(symbol, reason)

最终每行对应一只股票,每列对应一项盘口统计指标。

可以进一步筛选当前五档买盘总量高于卖盘总量的股票:

valid_rows = stats_df[
    stats_df["volume_ratio"].notna()
]

selected = valid_rows[
    valid_rows["volume_ratio"] > 1
].copy()

print(
    selected[
        ["symbol", "volume_ratio", "volume_difference"]
    ].to_string(index=False)
)

不过,这里只是按照盘口委托量进行条件筛选,并不是买入信号。实际策略还需要结合流动性、成交行为、盘口刷新频率和交易成本判断。

此外,如果各股票通过顺序请求获取,结果对应的采集时刻可能不同。不能仅因为它们出现在同一张表里,就认为它们属于严格同步的市场快照。

关键坑与注意事项

  • 批量请求不代表同步快照。 顺序查询多个股票时,行情可能在请求过程中发生变化。对于跨股票盘口比较,需要记录采集时间;如果 SDK 返回行情时间字段,应优先验证该字段的含义和精度。

  • 盘口委托量不是成交量。 五档买卖盘反映的是当前可见挂单,委托可以撤销或变化,不能用五档总量直接替代真实交易量。

  • 委托量单位需要确认。 不同市场或数据源可能采用不同数量单位。未确认返回值单位前,不宜将委托量直接换算成股数,也不宜进行跨市场绝对量比较。

  • 缺失档位不能随意补零。 停牌、流动性不足或者接口返回异常,都可能导致档位不完整。应先识别业务含义,再决定拒绝统计还是采用有效档位统计。

  • 接口失败要单独保留记录。 单只股票请求异常,不应直接导致整个批次结果消失。汇总成功数据的同时,应保留失败股票及其原因。

  • 买卖盘量比不是价格预测指标。 委托量受撤单、挂单行为与市场微观结构影响。量比偏高只能说明当前统计口径下买盘委托量相对较大。

  • 盘口指标需要明确时效性。 实时盘口变化较快,历史研究若没有保存原始快照及对应时间,后续难以准确重现统计结果。

常见问题(FAQ)

Q:QuantDash 是否提供一次查询多只股票盘口的批量接口?

A:当前已知接口为 qd.depth.get(),按单只股票代码获取盘口。本文使用 Python 循环实现应用层批量查询,不假设存在未经确认的原生批量盘口接口。

Q:五档买卖盘量比和成交量比有什么区别?

A:五档买卖盘量比比较的是当前可见买卖委托量;成交量相关指标统计的是已经发生的交易。两者的数据对象和含义不同,不能混用。

Q:盘口某一档委托量为零,还能继续统计吗?

A:可以根据业务口径决定。本文允许委托量为零,但要求档位结构完整。零委托量不计入有效档位数量;如果是字段缺失,则应作为数据异常单独处理。

Q:为什么有些股票的盘口量比无法计算?

A:主要原因包括卖盘总量为零、盘口缺少必要字段或数据类型异常。建议保留失败原因,不要默认将异常值填为零。

Q:统计结果可以直接用于自动交易吗?

A:不建议。盘口统计只是策略输入,还需要验证行情时效、信号稳定性、交易规则、成交可行性和交易成本。

小结

批量盘口查询后的核心工作,不是简单地把多个接口返回值拼接起来,而是为每只股票建立一致的统计口径。五档买卖盘总量、量差、量比和价差都可以提供参考,但前提是字段完整、数量单位一致、异常值处理明确。

使用 QuantDash Python SDK 可以完成五档盘口数据获取,Python 代码负责数据校验、单只股票指标计算及多股票汇总。对于需要长期运行的量化系统,还应补充时间记录、错误监控和原始数据留存,避免统计表看起来完整,底层数据却无法验证。

参考

QuantDash Python SDK 文档:https://docs.quantdash.net/zh-Hans/sdk/python-quickstart

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值