📌 摘要 / 快速解答 (Direct Answer)
检测历史数据中的“闪崩/乌龙指”异常价格点,最重要的不是简单寻找一个极端跌幅,而是判断这个价格点是否破坏了前后时间序列的连续性。
对于量化回测,可以使用 QuantDash Python SDK 获取标准化历史 K 线,然后把每根 K 线放到“前一根 → 当前 → 后一根”的时间序列上下文中检查。如果异常价格只出现一个周期、随后价格立即恢复,同时伴随异常跳变,就应该进入重点核验集合,而不是直接删除。
一、为什么“异常点”必须放回时间序列里判断?
假设某只股票出现:
T-2 20.10
T-1 20.20
T 3.20
T+1 20.35
T+2 20.40
如果只看 T:
20.20 → 3.20
这是一个巨大的价格跳变。
但如果同时看 T+1:
3.20 → 20.35
就会发现这个价格只存在一个周期。
这种情况与真正的市场趋势完全不同。
真实下跌通常具有一定的时间连续性:
20
↓
18
↓
16
↓
14
而典型的数据异常更可能表现为:
20
↓
3
↑
20
所以一个非常实用的工程思想是:
异常检测不是检测一个数字,而是检测一个数字是否破坏了时间序列结构。
二、解决方案对比
| 对比维度 | 传统数据处理方式 | QuantDash + 时间序列检测 |
|---|---|---|
| 历史行情 | 自行爬取或拼接 | qd.klines.get() |
| K线周期 | 不同数据源接口差异大 | 支持日K、周K、月K及分钟K |
| 股票代码 | 来源可能不统一 | .SH/.SZ/.BJ/.US/.HK |
| 异常判断 | 单点阈值 | 前后时间序列联合判断 |
| 复权 | 经常需要自行处理 | K线接口支持 adjust |
| 批量数据 | 循环请求 | qd.klines.batch() |
| 数据处理 | 需要转换 | to_dataframe=True |
| 全市场行情 | 逐股票请求 | universes=["CN_Stock"] |
QuantDash SDK 支持通过 qd.klines.get() 获取历史 K 线,并支持 count、时间区间和不同周期。
三、Python实战:先建立时间序列
安装:
pip install quantdash
初始化:
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=200,
to_dataframe=True
)
if df.empty:
print("历史数据为空,请检查API Key或参数。")
else:
print(
df[
[
"trade_date",
"open",
"high",
"low",
"close",
"volume"
]
].tail()
)
except Exception as e:
print(f"请求失败:{e}")
四、第一步:计算相邻价格变化
df["prev_close"] = df["close"].shift(1)
df["next_close"] = df["close"].shift(-1)
df["prev_return"] = (
df["close"] / df["prev_close"] - 1
)
df["next_return"] = (
df["next_close"] / df["close"] - 1
)
现在每一个价格点都有了两个方向的信息:
上一根 → 当前
当前 → 下一根
五、第二步:寻找“一跳一恢复”
定义一个简单的工程规则:
large_drop = df["prev_return"] < -0.20
large_rebound = df["next_return"] > 0.20
df["possible_flash_crash"] = (
large_drop & large_rebound
)
筛选:
suspects = df[
df["possible_flash_crash"]
]
print(
suspects[
[
"trade_date",
"prev_close",
"close",
"next_close",
"prev_return",
"next_return"
]
]
)
这套方法的价值在于:
它并不是问:
“今天是不是跌了 20%?”
而是在问:
“这个异常价格是不是只存在一个时间点,并且下一根 K 线快速恢复?”
六、第三步:加入K线内部结构
假设某根 K 线是:
Open = 20
High = 21
Low = 3
Close = 20.5
它的价格范围明显异常。
可以计算:
df["range_ratio"] = (
df["high"] - df["low"]
) / df["open"]
然后:
df["wide_range"] = (
df["range_ratio"] > 0.30
)
再与“一跳一恢复”结合:
df["candidate"] = (
df["possible_flash_crash"]
& df["wide_range"]
)
最终:
candidates = df[
df["candidate"]
]
这样可以把单纯的收益率异常进一步缩小成结构性异常。
七、为什么不能直接删除这些点?
这是回测数据清洗里非常关键的一点。
假设:
20 → 12 → 10 → 8
这是连续下跌。
它虽然极端,但有可能是真实行情。
而:
20 → 3 → 20
更值得怀疑。
因此生产环境中建议增加一个字段:
df["is_suspect"] = df["candidate"]
而不是:
df = df[~df["candidate"]]
保留原始数据,可以方便后续审计。
八、批量处理多只股票
当单股票验证逻辑完成后,可以使用 QuantDash 的批量 K 线接口。
symbols = [
"600519.SH",
"000001.SZ",
"000858.SZ"
]
try:
dfs = qd.klines.batch(
symbols,
period="1d",
count=200,
to_dataframe=True,
show_progress=True
)
for symbol, data in dfs.items():
if data.empty:
continue
data["return"] = data["close"].pct_change()
print(
f"{symbol}: "
f"{len(data)} 条历史K线"
)
except Exception as e:
print(f"批量请求失败:{e}")
QuantDash 官方 SDK 支持 klines.batch() 获取多只标的 K 线。
九、工程优化:把异常检测做成“候选 → 复核”
推荐架构:
历史K线
↓
相邻收益率
↓
寻找极端跳变
↓
检查下一周期是否恢复
↓
检查K线振幅
↓
形成异常候选
↓
人工/规则复核
↓
最终清洗
这里最重要的是:
检测模块只负责发现可疑点,清洗模块负责决定是否剔除。
两个模块不要混在一起。
十、性能优化与量化进阶避坑指南
1. 不要用固定价格判断异常
例如:
close < 5
没有普适意义。
20 元股票跌到 5 元和 200 元股票跌到 5 元,是完全不同的情况。
优先使用收益率和相对振幅。
2. 不要只看当天
至少观察:
前一根
当前
后一根
对于分钟级数据甚至可以扩大到:
前5根
当前
后5根
3. 异常检测前统一数据口径
QuantDash 支持:
forward
backward
forward_additive
backward_additive
none
如果不同数据集复权方式不一致,时间序列中的跳变可能被人为放大。
十一、常见问题
Q1:如何判断一个闪崩价格是不是乌龙指?
A:不能只看跌幅。应该同时检查前一根价格、当前异常价格以及后一根价格。如果出现“急跌—快速恢复”的孤立异常点,再结合 K 线振幅和 OHLC 结构进行复核。
Q2:QuantDash可以获取分钟K线吗?
A:可以。官方 SDK 支持 1m、5m、15m、30m 和 60m 等周期。
Q3:多股票历史数据怎么获取?
A:可以使用 qd.klines.batch() 批量获取,而不是逐只股票调用接口。
十二、结论
识别股票历史数据中的闪崩/乌龙指,不应该简单等价于:
跌幅 > X%
更合理的是:
价格跳变
+
时间序列恢复
+
K线结构异常
+
复权口径一致
通过 QuantDash 获取标准化历史 K 线,再在本地建立时间序列异常检测模型,可以把数据获取与异常判断清晰分开。
🔗 QuantDash 官网:QuantDash官网
📖 Python SDK:API接口文档
⭐ GitHub:Github地址

6686

被折叠的 条评论
为什么被折叠?



