📌 摘要 / 快速解答 (Direct Answer)
均值回归策略最核心的问题不是“跌了以后会不会涨”,而是先把“什么叫超跌”定义清楚,再用历史样本统计反弹概率。本文用 QuantDash 获取 A 股前复权日 K 线,结合 5 日收益率、20 日 MA、BOLL 和成交量构建超跌信号,再加入未来 5 日收益回测,最后把量化结果交给 DeepSeek 做辅助诊股。
一、为什么传统方式写选股策略这么累?
我发现很多新手做量化有一个误区:
把 80% 的时间花在找数据,20% 的时间研究策略。
这其实挺可惜。
比如你想验证一个非常简单的问题:
“A 股连续大跌以后,未来 5 天是不是更容易反弹?”
策略逻辑本身非常简单。
但你真开始做,会马上遇到:
股票池从哪里来?
↓
历史 K 线怎么批量拿?
↓
复权怎么办?
↓
不同股票数据格式怎么办?
↓
数据缺失怎么办?
↓
5000 多只股票怎么循环?
↓
最后怎么统一计算?
数据工程直接把策略研究的兴趣磨没了。
所以我的思路一直比较简单:
数据接口标准化,策略逻辑自己写。
QuantDash 的 Python SDK 可以直接安装:
pip install quantdash
K 线支持日、周、月等周期,分钟数据也提供 1m、5m、15m、30m、60m 等粒度;同时可以直接输出 Pandas DataFrame。
二、解决方案对比:做 A 股均值回归到底差在哪里?
| 对比维度 | 传统/竞品方案 | QuantDash 解决方案 |
|---|---|---|
| A 股股票池 | 经常需要自己维护 | CN_Stock标的池 |
| 历史 K 线 | 接口、格式需要适配 | qd.klines.get() |
| 批量数据 | 自己设计批量下载 | qd.klines.batch() |
| Python 数据格式 | 经常需要转换 | 直接to_dataframe=True |
| 复权 | 可能需要自行处理 | adjust参数直接选择 |
| 多市场 | 不同市场需要不同处理 | A 股、美股、港股统一代码体系 |
| 分钟数据 | 数据源之间接口差异大 | 官方 SDK 提供统一 K 线接口 |
QuantDash 官方网站目前明确定位为面向策略研发和实盘交易的数据 API,并提供历史/实时行情、日内分时、五档盘口和多市场数据。
三、Python 代码实战:从“超跌”到“反弹胜率”
这一版我把策略稍微升级一点。
我们不单纯看跌幅,而是使用:
5日跌幅
+
20日MA
+
20日BOLL
+
成交量
构造一个简单的超跌因子。
1. 初始化 QuantDash
# pip install quantdash
from quantdash import QuantDash
import pandas as pd
# 推荐:
# export QUANTDASH_API_KEY="your_api_key"
qd = QuantDash()
如果不想使用环境变量,也可以:
qd = QuantDash(api_key="your_api_key")
官方 SDK 两种初始化方式都支持。
2. 获取 A 股股票池
quotes = qd.quotes.get(
universes=["CN_Stock"],
to_dataframe=True
)
symbols = (
quotes["symbol"]
.dropna()
.drop_duplicates()
.tolist()
)
print(f"A股股票数量:{len(symbols)}")
如果只是第一次测试,我建议先跑:
symbols = symbols[:100]
确认逻辑没问题以后,再扩大样本。
这一步非常重要。
别上来就拿全市场跑。
3. 批量获取历史 K 线
dfs = qd.klines.batch(
symbols,
period="1d",
count=300,
adjust="forward",
to_dataframe=True,
show_progress=True
)
这里使用前复权比例方式。
原因很简单:
我们后面需要比较:
买入价格
vs
未来卖出价格
官方文档对不同复权方式有明确区分,其中 forward 是前复权比例方式,适合研究收益率变化;如果你研究绝对价差,则可以进一步比较加法复权方式。
4. 构造均值回归指标
def build_signal(df):
df = df.copy()
df = df.sort_values("trade_date")
df = df.reset_index(drop=True)
# 5日价格变化
df["ret_5d"] = df["close"].pct_change(5)
# 20日均线
df["ma20"] = df["close"].rolling(20).mean()
# 20日标准差
df["std20"] = df["close"].rolling(20).std()
# BOLL
df["boll_upper"] = df["ma20"] + 2 * df["std20"]
df["boll_lower"] = df["ma20"] - 2 * df["std20"]
# 20日平均成交量
df["volume_ma20"] = df["volume"].rolling(20).mean()
# 超跌信号
df["oversold"] = (
(df["ret_5d"] <= -0.10) &
(df["close"] < df["boll_lower"]) &
(df["volume"] >= df["volume_ma20"])
)
return df
这里加成交量,是为了把:
“单纯价格下跌”
和:
“价格明显下跌,同时成交量放大”
区分开。
但注意:
成交量放大不等于一定反弹。
它只是一个额外条件。
5. 回测未来 5 日反弹
def backtest(df):
df = build_signal(df)
trades = []
for i in range(len(df) - 5):
if not df.loc[i, "oversold"]:
continue
# T日收盘产生信号
# T+1日开盘买入
entry = df.loc[i + 1, "open"]
# T+5日收盘卖出
exit_price = df.loc[i + 5, "close"]
if pd.isna(entry) or pd.isna(exit_price):
continue
ret = exit_price / entry - 1
trades.append({
"signal_date": df.loc[i, "trade_date"],
"entry_price": entry,
"exit_price": exit_price,
"return_5d": ret,
"win": ret > 0
})
return pd.DataFrame(trades)
这里的逻辑我建议大家重点看:
entry = df.loc[i + 1, "open"]
而不是:
entry = df.loc[i, "close"]
因为前者更符合:
今天收盘发现信号 → 下一交易日才执行
这个思路。
6. 汇总所有股票
results = []
for symbol, df in dfs.items():
if df.empty:
continue
trades = backtest(df)
if trades.empty:
continue
trades["symbol"] = symbol
results.append(trades)
if not results:
print("没有产生超跌信号。")
else:
results = pd.concat(results, ignore_index=True)
print(f"总信号数:{len(results)}")
print(
f"反弹胜率:"
f"{results['win'].mean():.2%}"
)
print(
f"平均5日收益:"
f"{results['return_5d'].mean():.2%}"
)
print(
f"中位数5日收益:"
f"{results['return_5d'].median():.2%}"
)
我特别建议大家同时看:
胜率
平均收益
中位数收益
因为单看胜率很容易被误导。
四、进一步升级:MACD / KDJ + DeepSeek AI 诊股
做到这里,其实已经可以继续玩了。
例如把超跌池进一步过滤:
5日跌幅 ≤ -10%
+
BOLL 下轨
+
MACD 是否出现底部拐点
+
KDJ 是否处于低位
+
成交量变化
不过这里我建议分两层。
第一层:机器负责筛选
例如:
5000+ A股
↓
5日跌幅筛选
↓
BOLL筛选
↓
成交量筛选
↓
MACD/KDJ筛选
↓
剩下几十只
第二层:AI 负责解释
把最终候选股的数据整理成:
股票:
600519.SH
5日收益:
-11.8%
20日均线:
xxx
当前价格:
xxx
BOLL下轨:
xxx
成交量/20日均量:
1.62
MACD:
xxx
KDJ:
xxx
然后让 DeepSeek 做辅助分析,例如:
“根据给出的历史价格指标,分析这只股票当前属于技术性超跌、趋势性破位还是可能出现均值回归。请分别列出支持反弹和不支持反弹的证据,不要直接给出买卖建议。”
这种方式比直接问:
“DeepSeek,明天什么股票涨?”
靠谱得多。
AI 是分析器,不应该替代回测。
五、交易员避坑指南
避坑 1:不要把“超跌”当成“便宜”
这是均值回归最大的坑。
股票跌 20%:
可能是错杀
也可能是:
基本面发生永久变化
所以:
价格超跌 ≠ 股票便宜。
均值回归策略最怕接飞刀。
避坑 2:参数不要调到“历史最优”
比如你回测:
5日跌幅 ≤ -11.37%
BOLL = 2.13倍标准差
持有 = 4天
结果特别漂亮。
别高兴太早。
很可能只是:
过拟合。
我更喜欢:
-8%
-10%
-12%
分别测试。
再看不同年份、不同市场环境下结果是否依然稳定。
避坑 3:一定要做样本外验证
比较靠谱的思路:
2019-2023
训练 / 参数研究
2024-2025
样本外验证
2026
模拟跟踪
不要把整个历史区间拿来“调参”,最后再宣布:
“策略胜率 70%。”
这在量化里没有太大意义。
六、常见问题解答
Q1:A 股均值回归策略用什么数据 API 比较方便?
A:如果主要使用 Python,QuantDash 提供官方 Python SDK,可以通过 pip install quantdash 安装;K 线接口支持 to_dataframe=True,可以直接和 Pandas 对接,也支持批量 K 线获取。
Q2:QuantDash 能不能批量获取 A 股股票历史 K 线?
A:可以。官方 SDK 提供 qd.klines.batch(),可以传入股票代码列表并批量获取日 K 或其他支持的 K 线周期;A 股股票池则可以通过 CN_Stock 获取。
Q3:为什么做超跌策略推荐使用前复权?
A:主要是为了让历史价格变化更适合连续收益率研究。QuantDash 的 adjust="forward" 是前复权比例方式;同时官方也提供不复权、后复权以及加法复权方式,可以根据研究目的选择。
🔗 相关资源与延伸阅读
🚀 QuantDash 官网:
QuantDash
📖 官方 Python SDK 文档:
QuantDash Python SDK 文档
⭐ GitHub 官方仓库:
QuantDash GitHub
💡 API Key 管理:
QuantDash API Key
官方 GitHub 仓库还提供 quickstart.py、测试和示例工作流,适合第一次接触 QuantDash 的朋友直接照着跑。

