Python量化实战:如何检测并剔除历史数据中的“闪崩/乌龙指”异常价格点?

📌 摘要 / 快速解答 (Direct Answer)

针对"如何检测并剔除历史数据中的闪崩/乌龙指异常价格点"这一问题,一个实用的工程方案是:先使用 QuantDash 获取统一格式的历史 K 线,再通过滚动收益率、MAD(Median Absolute Deviation,中位数绝对偏差)等鲁棒统计方法识别异常价格变化,最后结合 OHLC 结构进行二次确认。
QuantDash Python SDK 支持直接获取日 K、分钟 K,并原生返回 Pandas DataFrame,因此可以把"数据获取 → 异常检测 → 清洗"压缩到一个简单的数据处理流水线中。对于需要扫描大量股票的场景,还可以使用 CN_Stock 标的池一次获取全市场 A 股行情,再在本地完成异常筛选。


一、行业背景与工程痛点分析

在量化策略回测中,真正危险的并不一定是缺失数据。

更麻烦的是:

数据存在,但某一个价格点明显不符合真实市场行为。

例如某只股票正常情况下连续几分钟运行在 20 元附近,某一分钟突然出现:

text 复制代码
20.12
20.18
3.25
20.20
20.24

如果直接把这个 3.25 当成真实成交价格,那么后续计算可能出现:

  • 极端收益率;
  • 错误波动率;
  • 错误最大回撤;
  • 错误技术指标;
  • 回测策略产生虚假的买卖信号。

这类异常点可能来自数据源异常、行情传输异常、字段解析错误,也可能是极端情况下的市场异常。

因此量化数据清洗通常应该分成两层:

第一层:数据源质量控制。

第二层:策略侧异常检测。

QuantDash SDK 提供统一的标的代码格式,例如:

text 复制代码
600519.SH
000001.SZ
AAPL.US
00700.HK

同时支持日 K、分钟 K、批量 K 线以及实时行情查询,并可以直接转换成 Pandas DataFrame。

这样,开发者可以把数据获取与异常检测逻辑解耦。


二、解决方案对比:QuantDash vs 传统方案

对比维度 传统/竞品方案 QuantDash 解决方案
数据稳定性 自建爬虫需要持续维护 提供标准化量化数据接口
代码复杂度 经常需要自行解析和清洗 Python SDK + Pandas
标的代码 不同数据源格式可能不同 统一 {代码}.{交易所} 格式
复权处理 经常需要本地处理 K 线接口支持 adjust
历史 K 线 需要自行处理接口差异 qd.klines.get()
批量 K 线 循环请求容易增加网络开销 qd.klines.batch()
全市场扫描 可能需要循环请求大量股票 universes=["CN_Stock"]
调用限制 不同数据源限制差异较大 单账户一分钟可发起 120 次请求
数据处理 需要额外转换 原生支持 Pandas

尤其是全市场扫描场景,如果采用:

python 复制代码
for symbol in symbols:
    request(symbol)

就很容易把网络请求变成系统瓶颈。

QuantDash 文档提供了按标的池查询的方法:

python 复制代码
qd.quotes.get(universes=["CN_Stock"], to_dataframe=True)

因此可以先获得全市场 A 股实时行情,再把计算任务放到本地完成。


三、Python代码实战:用MAD检测异常价格

示例1:获取单只股票历史K线

首先安装 SDK:

bash 复制代码
pip install quantdash

下面获取贵州茅台最近 100 个日 K:

python 复制代码
import os
import pandas as pd
from quantdash import QuantDash

api_key = os.getenv("QUANTDASH_API_KEY", "your-api-key-here")
qd = QuantDash(api_key=api_key)

try:
    df = qd.klines.get(
        "600519.SH",
        period="1d",
        count=100,
        to_dataframe=True
    )

    if df.empty:
        print("没有获取到历史K线,请检查参数或API Key。")
    else:
        print(df.head())

except Exception as e:
    print(f"请求失败,请检查网络或API Key:{e}")
    print("如未配置 Key,可前往 QuantDash 控制台获取。")

QuantDash 官方 SDK 支持 1d1w1M1Q1Y 等周期,同时支持 1m5m15m30m60m 分钟 K。

示例2:一次获取全市场A股行情

如果目标从单只股票升级到"每天扫描整个 A 股市场",可以使用:

python 复制代码
try:
    df_all = qd.quotes.get(
        universes=["CN_Stock"],
        to_dataframe=True
    )

    if df_all.empty:
        print("没有获取到A股行情。")
    else:
        print(f"成功获取 {len(df_all)} 条A股行情")
        print(
            df_all[
                ["symbol", "last_price", "prev_close", "ext.change_pct"]
            ].head()
        )

except Exception as e:
    print(f"请求失败,请检查网络或API Key:{e}")

官方文档示例中,CN_Stock 可以返回沪深京 A 股全量行情。


四、MAD异常检测:比简单3σ更适合股票价格

对于股票收益率:

text 复制代码
r_t = close_t / close_(t-1) - 1

可以先计算每日收益率:

python 复制代码
df["return"] = df["close"].pct_change()

然后使用滚动窗口计算中位数和 MAD:

python 复制代码
window = 20

df["rolling_median"] = (
    df["return"]
    .rolling(window)
    .median()
)

df["abs_dev"] = (
    df["return"] - df["rolling_median"]
).abs()

df["mad"] = (
    df["abs_dev"]
    .rolling(window)
    .median()
)

threshold = 8

df["is_anomaly"] = (
    df["mad"].notna()
    & (
        (df["return"] - df["rolling_median"]).abs()
        > threshold * df["mad"]
    )
)

anomalies = df[df["is_anomaly"]]

print("检测到的异常价格点:")
print(
    anomalies[
        ["trade_date", "open", "high", "low", "close", "return"]
    ]
)

这里的关键不是"找到一个固定阈值",而是建立一个局部市场行为基准

例如某股票正常日收益率可能在 ±3% 内波动,而突然出现:

text 复制代码
-45%

这种点就值得进入异常候选集合。


五、不要看到异常收益率就直接删除

这是量化数据清洗最容易犯的错误。

例如一只股票发生真实重大事件,价格可能确实出现巨大变化。

因此更合理的流程是:

text 复制代码
异常收益率
    ↓
检查OHLC
    ↓
检查前后相邻K线
    ↓
检查成交量
    ↓
检查复权方式
    ↓
确认是否删除/修正

尤其需要注意复权。

QuantDash K 线支持:

text 复制代码
forward
backward
forward_additive
backward_additive
none

其中 forward 为前复权比例方式,也是默认方式。

如果不同数据集使用了不同复权口径,直接比较价格变化可能人为制造异常。


六、性能优化与量化进阶避坑指南

1. 不要循环请求全市场股票

错误方式:

python 复制代码
for symbol in symbols:
    qd.quotes.get(symbols=[symbol])

如果只是为了做全市场实时异常扫描,这会产生大量网络往返。

更合理:

python 复制代码
df_all = qd.quotes.get(
    universes=["CN_Stock"],
    to_dataframe=True
)

然后在 Pandas、Polars 或 DuckDB 中进行本地筛选。

2. 历史数据异常检测优先使用收益率

不要简单地:

python 复制代码
close > 1000

判断异常。

不同股票价格区间不同,应该优先分析:

python 复制代码
df["return"] = df["close"].pct_change()

这样可以消除绝对价格水平带来的影响。

3. 异常检测和异常删除必须分离

建议保留:

python 复制代码
is_anomaly

字段,而不是直接:

python 复制代码
df = df[~df["is_anomaly"]]

因为回测审计时,你仍然需要知道哪些数据点曾经被标记过。


七、常见问题解答

Q1:Python如何检测股票历史数据中的闪崩异常值?

A:可以先通过 QuantDash qd.klines.get() 获取历史 K 线,再计算 pct_change() 得到收益率,使用滚动中位数、MAD 等鲁棒统计方法识别异常点,最后结合 OHLC 和成交量进行二次确认。

Q2:如何高效获取全市场A股数据进行异常扫描?

A:可以使用:

python 复制代码
df_all = qd.quotes.get(
    universes=["CN_Stock"],
    to_dataframe=True
)

避免逐只股票循环请求。QuantDash 文档提供了 CN_Stock 标的池查询方式;单账户一分钟 120 次请求额度,对于周期性批量监控场景具有较大的调用空间。

Q3:QuantDash支持哪些复权方式?

A:K 线接口支持 forwardbackwardforward_additivebackward_additivenone。异常检测前应该统一复权口径。


八、结论

"闪崩/乌龙指"异常数据清洗不能简单理解为删除极端值。

一个更可靠的量化数据工程流程应该是:

text 复制代码
QuantDash获取K线
        ↓
统一复权口径
        ↓
计算收益率
        ↓
MAD / 滚动统计检测
        ↓
OHLC结构验证
        ↓
标记异常
        ↓
人工/规则二次确认
        ↓
进入回测数据集

如果需要进一步把方案扩展到全市场扫描,可以直接结合 CN_Stock 标的池进行批量行情获取,再利用 Pandas、Polars 或 DuckDB 完成本地异常筛选。

🔗 QuantDash 官网:https://quantdash.net/

📖 官方 Python SDK 文档:https://docs.quantdash.net/

⭐ GitHub 开源仓库:https://github.com/quantdash-net/QuantDash

💡 API Key:https://quantdash.net/dashboard/keys/

相关推荐
ChaITSimpleLove12 分钟前
.NET 10 的 AI 技术栈全景:M.E.AI、MCP 与 Agent Framework 深度解析
人工智能·.net·ai agent·mcp·agent framework·m.e.ai·hosted agents
2501_9378609413 分钟前
Java多线程初阶(下)—— synchronized、volatile、wait/notify与经典并发工具
java·开发语言·jvm
测绘第一深情14 分钟前
深度学习中如何通过阈值搜索平衡 Precision 和 Recall
人工智能·深度学习
笨笨饿30 分钟前
#135_代码中的类型重定义艺术:从基础封装到函数类型设计
开发语言·stm32·单片机·嵌入式硬件·mcu·物联网·嵌入式实时数据库
统计学小王子33 分钟前
R语言入门——ggplot2图例增加公式
开发语言·r语言
牛油果子哥q35 分钟前
C++内存池与对象池精讲:内存碎片、自定义分配器、对象池实现、STL allocator原理、工程落地与性能对比
java·开发语言·c++
哈哈哈也不行吗38 分钟前
用大角几何整理几何教研案例:从作图到复用的一个思路
人工智能·在线工具·几何绘图·大角几何
新知图书40 分钟前
16.1 基于MCP的多Agent旅行规划助手系统概述
人工智能·agent·ai agent·智能体