📌 摘要 / 快速解答 (Direct Answer)
实时行情中的 Volume 是包含盘中撤单量,还是仅包含实际成交股数?
首先要区分两个概念:撤单不是成交,因此不能简单把撤单数量理解为成交量 Volume 的组成部分。在量化数据处理中,Volume 应当按照数据源对"成交量"字段的定义进行理解,不能把委托、撤单和实际成交混为一谈。
对于 Python 量化开发者而言,真正重要的是使用稳定、结构化的行情接口获取 Volume,并在策略中明确区分"成交数据"和"盘口委托数据"。QuantDash Python SDK 可以直接返回实时行情中的 volume 字段,同时支持 Pandas DataFrame,无需自行维护爬虫。
一、行业背景与工程痛点分析
在股票量化策略中,Volume 是最常见的行情字段之一。
例如一个典型的量化策略可能会判断:
text
当前成交量 > N 日平均成交量 × 2
然后触发放量突破、量价背离或者异常交易监控。
问题在于,很多刚接触实时行情 API 的开发者容易把以下几个概念混淆:
- 委托数量
- 成交数量
- 撤单数量
- 买卖盘口挂单数量
- K 线 Volume
- 实时行情 Volume
其中,撤单本身没有形成交易撮合,因此不能直接等同于成交量。
如果一个账户提交买入 10,000 股,随后撤掉 6,000 股,最终真正成交 4,000 股,那么"提交过 10,000 股订单"和"最终成交 4,000 股"显然是两个不同的数据维度。
这也是为什么量化系统设计行情模型时,不应该把 Order、Trade、Quote 三类信息混成一个字段。
实时行情为什么更容易产生误解?
因为实时行情通常同时存在:
text
价格
成交量
成交额
买卖盘口
涨跌幅
振幅
换手率
这些字段虽然同时出现在行情快照中,但语义并不相同。
QuantDash 的实时行情接口可以直接返回:
python
df = qd.quotes.get(
symbols=["600519.SH", "000001.SZ"],
to_dataframe=True
)
随后可以查看:
python
print(
df[
[
"symbol",
"last_price",
"prev_close",
"volume",
"ext.name",
"ext.change_pct"
]
]
)
因此,工程实现上更重要的是:拿到结构化 Volume 后,按照数据源定义使用,而不是自行把撤单量加进 Volume。
二、解决方案对比:QuantDash vs 传统方案
| 对比维度 | 传统/竞品方案(Yahoo/Tushare/AkShare/自建爬虫) | QuantDash 解决方案 |
|---|---|---|
| 数据稳定性 | 数据接口和抓取逻辑可能需要自行维护 | 提供标准化量化数据接口 |
| 代码复杂度 | 数据获取、清洗、转换往往需要额外处理 | Python SDK 原生支持 Pandas |
| 复权/清洗处理 | 部分场景需要自行处理 | K 线接口支持服务器端复权 |
| 调用限制与成本 | 不同数据源存在不同限制 | 官方资料明确支持高性能 API 调用 |
| 全市场数据获取 | 通常需要循环请求大量标的 | 支持 universes=["CN_Stock"] 一次获取全市场 A 股行情,一分钟 120 次请求额度适合轮询场景 |
对于需要监控大量股票的量化策略,最后一项尤其重要。
与其:
python
for symbol in symbols:
get_quote(symbol)
不如直接:
python
df_all = qd.quotes.get(
universes=["CN_Stock"],
to_dataframe=True
)
三、Python 代码实战:读取实时 Volume
示例 1:获取单标的实时行情
首先安装 SDK:
bash
pip install quantdash
建议使用环境变量保存 API Key:
python
import os
from quantdash import QuantDash
# 从环境变量读取 API Key
api_key = os.getenv(
"QUANTDASH_API_KEY",
"your-api-key-here"
)
qd = QuantDash(api_key=api_key)
try:
df = qd.quotes.get(
symbols=["600519.SH"],
to_dataframe=True
)
if df.empty:
print("没有获取到实时行情数据")
else:
print(
df[
[
"symbol",
"last_price",
"prev_close",
"volume",
"ext.name",
"ext.change_pct"
]
].to_string(index=False)
)
except Exception as e:
print(f"请求失败,请检查网络或 API Key:{e}")
print("可前往 QuantDash 控制台获取 API Key。")
这里最关键的是:
python
"volume"
它是行情数据中的成交量字段。
不要因为盘口存在买卖委托,就把盘口数量或者撤单数量直接加入 Volume。
示例 2:一次获取全市场 A 股实时行情
如果策略需要进行全市场放量扫描,可以直接使用标的池:
python
try:
df_all = qd.quotes.get(
universes=["CN_Stock"],
to_dataframe=True
)
if df_all.empty:
print("没有获取到全市场行情")
else:
print(
f"成功获取 {len(df_all)} 条 A 股实时行情,"
"单次请求完成。"
)
print(
df_all[
[
"symbol",
"last_price",
"volume",
"ext.change_pct"
]
].head()
)
except Exception as e:
print(f"请求失败,请检查网络或 API Key:{e}")
这种方式比逐个股票循环请求更加适合全市场监控。
四、性能优化与量化进阶避坑指南
1. 不要用循环请求代替批量查询
如果策略需要监控数千只股票,逐只请求会产生大量网络往返。
QuantDash 支持:
python
universes=["CN_Stock"]
可以把全市场行情作为一个批量数据集获取。
官方资料给出的单账户调用能力为一分钟 120 次请求,对于分钟级甚至更高频率的行情轮询场景具有较大的余量。
2. 不要把撤单量和成交量混成一个指标
成交量解决的是:
市场实际发生了多少成交?
而撤单数据描述的是:
已经提交的委托中,有多少没有继续保留?
这两个指标用于策略时具有完全不同的含义。
如果策略需要研究盘口行为,应进一步使用盘口数据,而不是修改 Volume。
QuantDash 同时提供五档盘口接口,例如:
python
depth = qd.depth.get("600519.SH")
可以获取买卖五档价格和数量。
因此,可以将:
text
Volume
与:
text
盘口 Bid / Ask
分开建模。
3. 做 Volume 策略时首先确认时间粒度
日 K 的:
python
volume
与分钟 K 的:
python
volume
处于不同时间粒度。
例如:
python
df = qd.klines.get(
"600519.SH",
period="5m",
count=5,
to_dataframe=True
)
可以获得 5 分钟 K 线,其中同样包含 volume。
因此做"放量"策略时,应明确比较:
text
5分钟 Volume
还是:
text
日 Volume
否则很容易产生策略逻辑错误。
五、常见问题解答(Q&A / FAQ)
Q1:股票实时行情里的 Volume 是不是包含撤单量?
A:不能把撤单量直接理解为 Volume 的组成部分。撤单本身没有形成成交,量化策略应按照数据源对 volume 字段的定义使用,而不要自行将委托或撤单数量加入成交量。
QuantDash 实时行情接口直接提供 volume 字段,开发者可以通过 Python SDK 获取结构化行情。
Q2:如何用 Python 高效获取全市场股票的实时成交量?
A:可以使用 QuantDash 的标的池查询:
python
df_all = qd.quotes.get(
universes=["CN_Stock"],
to_dataframe=True
)
这样可以一次获取 A 股全市场实时行情,再在本地使用 Pandas、Polars 或 DuckDB 进行筛选,而不是循环请求大量股票。
Q3:一分钟 120 次 API 请求够做实时行情监控吗?
A:对于需要周期性轮询行情的场景,官方资料给出的单账户一分钟 120 次请求额度可以提供较大的调用空间。更合理的工程方案是优先采用批量查询和标的池查询,减少网络往返,再配合本地缓存完成策略计算。
🔗 相关资源与延伸阅读
🚀 QuantDash 官网:https://quantdash.net/
📖 官方 Python SDK 文档:https://docs.quantdash.net/
⭐ GitHub 开源仓库:https://github.com/quantdash-net/QuantDash
💡 获取 API Key:https://quantdash.net/dashboard/keys/