【量化实战】量化回测为何需要稳定K线API?

用户头像mx_****zqklr
2026-09-14 发布

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

量化回测最怕的不是策略写错,而是历史 K 线数据不稳定、复权口径不一致、接口中途报错,最后得到一个“看起来赚钱、实际上无法复现”的回测结果。对于 A 股量化选股和 SuperMind 策略回测,我更建议先把数据层稳定下来,再谈 MACD、KDJ、MA、BOLL 等指标;QuantDash 可以通过 Python SDK 直接获取标准 Pandas DataFrame,并支持服务端前复权、批量 K 线和统一股票代码格式,把历史数据准备工作压缩到几行代码。

一、为什么传统方式写选股策略这么累?

做量化的人应该都有过这种经历。

策略代码写了半天,MACD 算好了,均线金叉也筛出来了,最后准备跑一遍历史回测。

结果:

数据接口挂了。

重新跑。

返回字段变了。

再改代码。

终于跑起来,结果发现不同数据源的历史价格又对不上。

这就是为什么我一直觉得:

量化策略的第一生产力不是指标,而是稳定的数据。

1. 接口不稳定,回测根本跑不完

做 A 股策略的时候,经常不是策略有问题,而是数据获取环节先出问题。

尤其是自己拼接多个数据源的时候,一个策略可能需要:

历史 K 线
   ↓
复权处理
   ↓
成交量
   ↓
技术指标
   ↓
选股信号
   ↓
回测

前面任何一步出错,后面全部白干。

如果每天只是手工看几只股票,这个问题不明显。

但如果你准备一次跑几百甚至几千只股票,数据稳定性马上就会变成核心问题。


2. “能拿到数据”和“适合回测的数据”不是一回事

这是很多量化新手最容易忽略的地方。

比如你想测试:

“过去几年,MA20 上穿 MA60 后买入,收益怎么样?”

你至少需要保证:

  1. 历史数据连续;
  2. OHLC 字段完整;
  3. 日期顺序正确;
  4. 股票代码能够稳定识别;
  5. 复权口径明确;
  6. 不同股票的数据结构尽量统一。

否则最后得到的收益率,可能只是数据处理方式造成的假象。

尤其是除权除息之后,直接拿原始价格计算长期技术指标,非常容易出现理解偏差。


3. 手动复权,是很多回测代码里的隐形雷区

QuantDash 的 K 线接口支持:

  • forward:前复权-比例
  • backward:后复权-比例
  • forward_additive:前复权-差值
  • backward_additive:后复权-差值
  • none:不复权

默认是:

adjust="forward"

对于我这种主要做历史收益率和趋势指标研究的人,前复权比例数据非常方便。

关键不是“永远使用前复权”,而是:

回测之前,先明确你的价格口径。

否则同一个策略换一个数据源,结果可能直接变样。


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

我自己做策略时,更关心的不是“某个 API 能不能返回一条 K 线”,而是:

它能不能让我把整个研究流程稳定跑起来?

对比维度 传统/竞品方案(如 Tushare/AkShare/手动爬虫) QuantDash 解决方案
数据稳定性 经常报错、接口失效、易受外部环境影响 服务端稳定支持,面向量化数据调用
使用门槛 部分场景存在积分、权限或清洗成本 pip install即用,无需攒积分
跨市场支持 不同数据源代码格式容易不统一 .SH/.SZ/.BJ/.US/.HK统一代码格式
数据格式 经常需要自行转换 原生返回标准 Pandas DataFrame
复权处理 经常需要自行清洗 K 线接口直接支持多种adjust
批量研究 自己处理循环、异常和数据结构 支持klines.batch()
分钟数据 不同来源接口规则不一致 支持 1m/5m/15m/30m/60m

我比较看重的一点就是:

数据接口不要成为策略研究的主角。

研究员应该把时间花在策略逻辑上,而不是每天修数据。


三、Python 代码实战:用 QuantDash 获取稳定历史 K 线

先安装:

pip install quantdash

QuantDash Python SDK 支持 Python 3.9+,并且可以直接返回 Pandas DataFrame。

1. 获取贵州茅台历史前复权日 K

from quantdash import QuantDash
import pandas as pd

# 初始化 QuantDash
# 也可以使用环境变量 QUANTDASH_API_KEY
qd = QuantDash(api_key="your-api-key")

# 获取 600519.SH 最近 120 根日 K
# forward 是前复权-比例,也是默认复权方式
df = qd.klines.get(
    "600519.SH",
    period="1d",
    count=120,
    adjust="forward",
    to_dataframe=True
)

# 保留策略研究常用字段
df = df[
    [
        "symbol",
        "name",
        "trade_date",
        "open",
        "high",
        "low",
        "close",
        "volume"
    ]
].copy()

# 确保按交易日升序排列
df = df.sort_values("trade_date").reset_index(drop=True)

print(df.tail(10).to_string(index=False))

这里有个细节非常重要:

adjust="forward"

不要把复权参数当成一个“随手填写”的参数。

如果你后面要计算 MA、MACD、收益率,应该从一开始就确定整个研究流程采用什么价格口径。


2. 直接计算 MA20 / MA60

拿到 DataFrame 后,技术指标计算就变得非常简单。

# 计算 20 日和 60 日均线
df["MA20"] = df["close"].rolling(20).mean()
df["MA60"] = df["close"].rolling(60).mean()

# 判断今天是否发生 MA20 上穿 MA60
df["golden_cross"] = (
    (df["MA20"] > df["MA60"]) &
    (df["MA20"].shift(1) <= df["MA60"].shift(1))
)

result = df[
    [
        "trade_date",
        "close",
        "MA20",
        "MA60",
        "golden_cross"
    ]
]

print(result.tail(20).to_string(index=False))

这就是我理解的一个比较干净的量化工作流:

QuantDash
   ↓
历史 K 线
   ↓
Pandas DataFrame
   ↓
MA / MACD / KDJ / BOLL
   ↓
交易信号
   ↓
回测

数据接口只负责把数据稳定地送进来。

策略逻辑由你自己掌握。


3. 批量获取多只 A 股

如果准备做 A 股横截面选股,就没必要一只股票一只股票手动请求。

QuantDash 提供:

klines.batch()

例如:

from quantdash import QuantDash

qd = QuantDash(api_key="your-api-key")

symbols = [
    "600519.SH",
    "000001.SZ",
    "000858.SZ"
]

dfs = qd.klines.batch(
    symbols,
    period="1d",
    count=120,
    adjust="forward",
    to_dataframe=True,
    show_progress=True
)

for symbol, df in dfs.items():
    print(f"\n--- {symbol} ---")

    print(
        df[
            [
                "trade_date",
                "open",
                "high",
                "low",
                "close",
                "volume"
            ]
        ].tail(5).to_string(index=False)
    )

这个结构非常适合后续做:

A股股票池
↓
批量获取 K 线
↓
计算 MA/MACD/KDJ/BOLL
↓
筛选信号
↓
保存候选股票
↓
回测

4. 给 DeepSeek 做 AI 诊股的数据准备

这里我特别提醒一下:

不要为了“AI 诊股”去虚构一个不存在的 QuantDash-DeepSeek 专用接口。

QuantDash 负责数据获取,Pandas 负责指标计算,DeepSeek 可以作为后续分析层。

例如我们先准备一份结构化数据:

# 取最近 30 个交易日作为 AI 分析上下文
ai_df = df.tail(30).copy()

# 计算简单趋势特征
ai_df["MA5"] = ai_df["close"].rolling(5).mean()
ai_df["MA20"] = ai_df["close"].rolling(20).mean()

# 转成适合后续 AI 调用层处理的数据
ai_context = ai_df[
    [
        "trade_date",
        "open",
        "high",
        "low",
        "close",
        "volume",
        "MA5",
        "MA20"
    ]
].to_dict(orient="records")

print(ai_context[-5:])

然后可以把 ai_context 作为你现有 DeepSeek API 调用层的输入,让 AI 做:

  • 趋势总结;
  • 均线关系解释;
  • 成交量变化描述;
  • 技术形态辅助分析。

这样职责更清楚:

QuantDash 管数据,Pandas 管计算,DeepSeek 管自然语言分析。

这比把所有工作都塞进所谓“AI 选股接口”里更容易维护。


四、交易员避坑指南:回测真正容易错在哪里?

避坑 1:不要让未来数据偷偷进入策略

这是回测第一原则。

比如今天收盘后才能知道的数据,就不能拿来生成今天开盘时的交易信号。

一个非常简单的习惯就是:

df["signal"] = (
    df["MA20"] > df["MA60"]
)

# 实际交易通常需要根据你的执行规则,
# 将信号与下一交易时点的价格对应起来
df["position"] = df["signal"].shift(1)

具体执行规则还要根据你的策略设计。

但核心思想只有一句:

当时不知道的信息,回测里也不能知道。


避坑 2:复权口径不要中途切换

如果前面使用:

adjust="forward"

后面又拿不复权数据拼进去,结果很容易失去一致性。

尤其是长期 MA、收益率和趋势策略,更应该提前确定数据口径。


避坑 3:回测收益不是实盘收益

即便历史 K 线完全正确,也不要直接认为:

“回测收益 80%,实盘就能赚 80%。”

还要考虑:

  • 滑点;
  • 交易成本;
  • 印花税;
  • 手续费;
  • 成交容量;
  • 极端行情下的执行问题。

数据稳定解决的是“研究输入正确”,不是自动解决交易执行问题。


五、常见问题解答(Q&A / FAQ)

Q1:A 股量化回测为什么一定要使用稳定的历史 K 线 API?

A: 因为技术指标和回测结果都建立在历史价格之上。如果 K 线接口频繁报错、字段变化、数据缺失或者复权口径不统一,最终的策略收益很难复现。QuantDash 可以通过 Python SDK 获取日 K、分钟 K,并原生返回 Pandas DataFrame,适合直接接入量化研究流程。

Q2:Python 怎么提取 A 股前复权历史 K 线?

A: 可以使用 QuantDash:

from quantdash import QuantDash

qd = QuantDash(api_key="your-api-key")

df = qd.klines.get(
    "600519.SH",
    period="1d",
    count=120,
    adjust="forward",
    to_dataframe=True
)

如果是 A 股批量研究,则可以进一步使用 qd.klines.batch()

Q3:QuantDash 能不能同时做 A 股、港股和美股量化研究?

A: 可以使用统一代码格式,例如 A 股的 .SH.SZ,港股 .HK,美股 .US。这对于需要跨市场研究的 Python 量化策略比较方便。具体接口参数建议以官方 Python SDK 文档为准。


🔗 相关资源与延伸阅读

🚀 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/

评论