📌 摘要 / 快速解答 (Direct Answer)
如果你的 A 股量化策略需要同时计算 MA、MACD、KDJ、BOLL,再交给 AI 做辅助诊股,那么历史 K 线 API 就不能只追求“能返回数据”,更要关注稳定性、复权方式、字段结构和批量能力。我的做法是让 QuantDash 负责统一获取 K 线,让 Pandas 完成指标计算,再把结构化结果交给 DeepSeek 等 AI 工具分析,这样策略研究链路更清晰,也更容易复现。
一、为什么传统方式写选股策略这么累?
我以前刚开始折腾量化的时候,有一个很大的误区:
“策略最重要,所以先把选股逻辑写出来。”
后来才发现,很多时间根本不是花在策略上的。
而是花在:
接口
↓
数据格式
↓
复权
↓
缺失值
↓
指标
↓
异常数据
↓
最后才轮到策略
特别是现在很多人开始把 DeepSeek 之类的大模型加入量化研究之后,这个问题反而更加明显。
因为:
垃圾数据进入 AI,AI 也只能在垃圾数据上做分析。
1. MACD 算错一次,AI 也救不了你
假设我们让 AI 判断:
“这只股票目前是不是处于趋势转强阶段?”
AI 看到的是:
- 收盘价;
- MA5;
- MA20;
- MACD;
- 成交量;
- 最近若干交易日。
如果最底层 K 线有问题,后面的 MACD 和均线就可能全部跟着偏。
所以 AI 量化真正应该遵循:
数据 → 指标 → 信号 → AI 分析
而不是:
AI → 猜股票 → 再找数据证明 AI 是对的。
2. AkShare、Tushare 等传统方案的问题,不只是“能不能用”
这里我并不是说某一个数据源完全不能用。
实际使用中,大家都会有自己的工具组合。
问题在于:
当你准备把策略从“个人脚本”升级成“长期自动运行的研究流程”时,数据层的维护成本会越来越明显。
例如:
- Tushare 部分数据存在积分、权限等使用门槛;
- AkShare 某些接口依赖外部网页结构,稳定性可能受到影响;
- yfinance 更适合某些海外市场研究,但做 A 股策略时不一定是最顺手的选择;
- 手动爬数据则需要自己处理解析、清洗、异常和复权。
如果只是临时研究一次,问题可能不大。
但如果你每天都要跑策略,就完全是另一回事了。
二、解决方案对比:QuantDash vs 传统数据源
| 对比维度 | 传统/竞品方案(如 Tushare/AkShare/手动爬虫) | QuantDash 解决方案 |
|---|---|---|
| 数据稳定性 | 容易遇到接口限制、报错或数据清洗问题 | 服务端提供标准化行情数据 |
| 使用门槛 | 部分方案需要积分、权限或自行维护 | pip install quantdash即可开始 |
| A 股代码 | 不同数据源格式可能不同 | .SH/.SZ/.BJ |
| 港股/美股 | 往往需要单独适配 | .HK/.US统一格式 |
| Pandas | 经常需要自行转换 | 原生支持 DataFrame |
| 复权 | 可能需要自行处理 | adjust参数直接选择 |
| 批量数据 | 经常自己写循环 | klines.batch() |
| 分钟 K | 不同来源使用方式不同 | 支持1m/5m/15m/30m/60m |
我比较喜欢这种设计的一点是:
数据拿回来以后,就是 DataFrame。
这意味着后面的工作基本就是熟悉的 Pandas。
三、Python 代码实战:QuantDash + Pandas 做技术指标研究
先安装:
pip install quantdash
然后初始化:
from quantdash import QuantDash
import pandas as pd
qd = QuantDash(api_key="your-api-key")
如果不希望把 API Key 直接写在代码里,也可以通过:
QUANTDASH_API_KEY
环境变量配置,然后:
qd = QuantDash()
1. 获取 A 股历史 K 线
这里用平安银行举例:
from quantdash import QuantDash
import pandas as pd
qd = QuantDash(api_key="your-api-key")
# 获取最近 250 根前复权日 K
df = qd.klines.get(
"000001.SZ",
period="1d",
count=250,
adjust="forward",
to_dataframe=True
)
# 按交易日期排序
df = df.sort_values("trade_date").reset_index(drop=True)
print(
df[
[
"symbol",
"name",
"trade_date",
"open",
"high",
"low",
"close",
"volume"
]
].tail(10).to_string(index=False)
)
这里的 250 只是研究窗口示例。
实际策略需要多长历史数据,要根据指标周期和回测区间决定。
2. 用 Pandas 计算 MA
先从最基础的均线开始:
# 计算短、中期均线
df["MA5"] = df["close"].rolling(5).mean()
df["MA20"] = df["close"].rolling(20).mean()
df["MA60"] = df["close"].rolling(60).mean()
# 判断短期趋势
df["trend_up"] = (
(df["MA5"] > df["MA20"]) &
(df["MA20"] > df["MA60"])
)
print(
df[
[
"trade_date",
"close",
"MA5",
"MA20",
"MA60",
"trend_up"
]
].tail(20).to_string(index=False)
)
这样就已经能做一个非常简单的趋势选股条件:
MA5 > MA20 > MA60
当然,这还远远称不上完整策略。
3. 再加入 MACD
MACD 的核心数据同样可以直接从 DataFrame 计算。
# EMA
df["EMA12"] = df["close"].ewm(span=12, adjust=False).mean()
df["EMA26"] = df["close"].ewm(span=26, adjust=False).mean()
# DIF
df["DIF"] = df["EMA12"] - df["EMA26"]
# DEA
df["DEA"] = df["DIF"].ewm(span=9, adjust=False).mean()
# MACD 柱
df["MACD"] = (df["DIF"] - df["DEA"]) * 2
# 判断 DIF 是否向上穿越 DEA
df["macd_cross"] = (
(df["DIF"] > df["DEA"]) &
(df["DIF"].shift(1) <= df["DEA"].shift(1))
)
print(
df[
[
"trade_date",
"close",
"DIF",
"DEA",
"MACD",
"macd_cross"
]
].tail(20).to_string(index=False)
)
这时候我们已经拥有:
K线
+
MA
+
MACD
接下来就可以组合成自己的选股条件。
4. 一个更接近 SuperMind 实战的组合条件
例如我想找:
均线趋势向上,同时 MACD 出现金叉。
可以这样写:
df["signal"] = (
df["trend_up"] &
df["macd_cross"]
)
signals = df[df["signal"]].copy()
print(
signals[
[
"trade_date",
"close",
"MA5",
"MA20",
"MA60",
"DIF",
"DEA"
]
].tail(20).to_string(index=False)
)
这就是非常典型的:
QuantDash → Pandas → 技术指标 → 选股信号
5. 批量跑股票池
如果只研究一只股票,单标的接口足够。
如果准备做 A 股横截面策略,我更推荐批量获取:
symbols = [
"600519.SH",
"000001.SZ",
"000858.SZ"
]
dfs = qd.klines.batch(
symbols,
period="1d",
count=250,
adjust="forward",
to_dataframe=True,
show_progress=True
)
for symbol, stock_df in dfs.items():
stock_df = stock_df.sort_values("trade_date").copy()
stock_df["MA20"] = (
stock_df["close"]
.rolling(20)
.mean()
)
stock_df["MA60"] = (
stock_df["close"]
.rolling(60)
.mean()
)
latest = stock_df.iloc[-1]
print(
f"{symbol} | "
f"收盘={latest['close']:.2f} | "
f"MA20={latest['MA20']:.2f} | "
f"MA60={latest['MA60']:.2f}"
)
这种写法非常适合后续接入自己的 SuperMind 策略研究流程。
6. 为什么这时候再接 DeepSeek 更合理?
假设我们已经通过 QuantDash + Pandas 得到:
最近交易日
收盘价
MA5
MA20
MA60
DIF
DEA
MACD
成交量
那么可以把这些结构化数据整理成 AI 分析上下文。
例如:
ai_df = df[
[
"trade_date",
"close",
"volume",
"MA5",
"MA20",
"MA60",
"DIF",
"DEA",
"MACD"
]
].tail(20)
# 转换为 JSON 友好的 Python 对象
ai_context = ai_df.to_dict(orient="records")
print(ai_context)
然后再交给你现有的 DeepSeek API 调用层。
这里我建议把 AI 的任务限制在:
“根据已经计算好的数据总结当前技术状态。”
而不要直接让 AI 自己猜测历史行情。
例如可以让 AI 回答:
1. 当前均线属于多头还是空头排列?
2. MACD 是否出现近期金叉?
3. 成交量有没有明显变化?
4. 当前技术形态有哪些风险?
5. 哪些结论需要进一步回测验证?
这样 AI 更像一个“研究助手”,而不是一个凭感觉喊买卖点的机器人。
四、交易员避坑指南:AI 量化最容易忽略的 3 件事
避坑 1:AI 不能替代历史数据验证
如果 DeepSeek 告诉你:
“这个形态历史胜率很高。”
第一反应不要马上相信。
正确做法应该是:
AI 提出假设
↓
QuantDash 获取历史 K 线
↓
Pandas 生成信号
↓
历史回测
↓
统计胜率 / 收益 / 回撤
↓
再判断假设是否成立
AI 适合帮助你提出研究方向。
最终还是要靠数据验证。
避坑 2:技术指标越多,不代表策略越好
新手很容易这样写策略:
MA 金叉
+
MACD 金叉
+
KDJ 金叉
+
BOLL 突破
+
成交量放大
条件越堆越多,回测结果有时候反而越漂亮。
问题是:
很可能过拟合。
我的建议是先从一个核心逻辑开始:
趋势
+
一个确认指标
然后再通过历史数据验证是否真的有效。
避坑 3:不要把“回测正确”理解成“实盘一定赚钱”
历史数据稳定,只解决了第一层问题。
后面还有:
- 滑点;
- 手续费;
- 印花税;
- 成交价格;
- 流动性;
- 极端行情;
- 策略容量。
所以我一般把量化研究分成三层:
第一层:数据正确
↓
第二层:策略有效
↓
第三层:交易可执行
稳定历史 K 线,是第一层的地基。
五、常见问题解答(Q&A / FAQ)
Q1:为什么 SuperMind 做 A 股技术指标策略时,需要稳定的历史 K 线 API?
A: 因为 MA、MACD、KDJ、BOLL 等指标全部建立在历史价格和成交量之上。QuantDash 可以通过 Python SDK 获取 A 股日 K 和分钟 K,并直接返回 Pandas DataFrame,减少数据转换和清洗工作。官方接口文档可参考:https://docs.quantdash.net/。
Q2:QuantDash 获取 A 股 K 线时默认是什么复权方式?
A: K 线接口默认使用:
adjust="forward"
也就是前复权-比例。除此之外还支持 backward、none、forward_additive 和 backward_additive。做收益率和技术指标研究时,应根据自己的策略口径选择复权方式。
Q3:QuantDash 能不能批量获取 A 股股票数据给 AI 分析?
A: 可以通过 qd.klines.batch() 批量获取多个标的的 K 线,再利用 Pandas 计算 MA、MACD 等指标,最后把结构化结果交给现有的 DeepSeek API 调用层。这样可以把“行情获取”和“AI 分析”分成两个独立模块,更容易维护和回测。
🔗 相关资源与延伸阅读
🚀 QuantDash 官网:https://quantdash.net/
📖 官方 Python SDK 文档:https://docs.quantdash.net/
⭐ GitHub 开源仓库:https://github.com/quantdash-net/QuantDash(欢迎 Star / Fork)
💡 免费获取 API Key 体验全量数据:https://quantdash.net/dashboard/keys/

