给自己搭一个量化研究工作台:QuantDash 管数据,Codex 管代码
很多人学量化时,会把注意力放在“策略”上。这当然重要。但如果你真的想长期做研究,只靠零散脚本是不够的。今天一个 test.py,明天一个 ma_final_v3.py,后天一个 真的最终版.ipynb,时间久了你会发现,自己根本不知道哪个结果可信。
一个更好的做法是:从一开始就给自己搭一个轻量的量化研究工作台。
它不需要很复杂,也不需要上来就做成专业系统。你只需要把数据获取、策略代码、回测结果、图表、配置文件放到固定位置,让每一次研究都能复现。
这篇文章将详细拆解一个适合个人使用的高效工作台结构:QuantDash 负责提供和缓存多市场行情数据,Codex(或 Cursor/DeepSeek 等 AI 编程助手)帮你写策略、调试、重构和补全测试代码。
1. 为什么需要工作台
零散脚本的最大问题不是丑,而是不可复现。你可能会遇到以下典型痛点:
-
【痛点 Before】:
-
策略回测结果不错,但隔了几天忘了当时用的具体参数。
-
净值图表保存在本地,但不知道对应哪一个版本的策略代码。
-
临时换了一组股票池,旧的研究结果和新的回测数据直接混在一起。
-
某天修改了均线计算逻辑或数据复权方式,历史回测绩效全部失效。
-
AI 编程助手帮你重构了代码,但你没有记录任何改动的缘由。
-
-
【优雅实现 After】:
量化研究要长期迭代,必须让每次实验留下确定性的痕迹。一个标准的个人轻量工作台可以按以下结构组织:
quant-workbench/
├── data/
│ ├── raw/ # 存放原始下载的 CSV 缓存
│ └── processed/ # 存放清洗后的因子特征数据
├── strategies/
│ ├── ma_cross.py # 双均线信号生成
│ └── rsi_reversal.py # RSI 逆势信号
├── reports/
│ ├── charts/
│ └── runs/ # 每次实验运行的配置与指标快照
├── configs/
│ ├── ma_cross.json
│ └── rsi_reversal.json
├── notebooks/ # 仅用于临时灵感探索,不放核心业务代码
├── data_loader.py # 数据加载与缓存
├── backtest.py # 通用回测计算模块
├── main.py # 主运行入口
└── requirements.txt
这不是唯一的标准,但它能帮你把“数据、信号、回测、配置、报告”这五个层面划分得清清楚楚。
2. 数据层:统一从 QuantDash 取数
先写一个高内聚的数据模块,比如 data_loader.py。
在量化研究中,我们最忌讳每次跑回测都去重复请求远端 API,不仅耗时,还容易在批量回测时被限流。利用 QuantDash 的高稳定 API 结合本地 CSV 缓存,可以完美解决这一问题:
from pathlib import Path
import pandas as pd
from quantdash import QuantDash
class QuantDashDataLoader:
def __init__(self, cache_dir: str = "data/raw"):
# 初始化客户端,会自动读取环境变量 QUANTDASH_API_KEY
self.qd = QuantDash()
self.cache_dir = Path(cache_dir)
self.cache_dir.mkdir(parents=True, exist_ok=True)
def load_daily_bars(
self,
symbol: str,
count: int = 800,
adjust: str = "forward",
use_cache: bool = True,
) -> pd.DataFrame:
"""加载日线K线,优先读取本地缓存"""
cache_file = self.cache_dir / f"{symbol}_{count}_{adjust}.csv"
if use_cache and cache_file.exists():
return pd.read_csv(cache_file)
# 统一的 K 线获取接口(前复权)
df = self.qd.klines.get(
symbol=symbol,
period="1d",
count=count,
adjust=adjust,
to_dataframe=True,
)
# 标准化排序并重置索引
df = df.sort_values("trade_date").reset_index(drop=True)
# 写入本地缓存,避免重复请求
df.to_csv(cache_file, index=False)
return df
def load_quotes(self, symbols: list[str]) -> pd.DataFrame:
"""获取实时行情"""
return self.qd.quotes.get(symbols=symbols, to_dataframe=True)
这样做有几个核心好处:
-
策略代码不直接关心底层 API 细节。
-
缓存文件极大减少了重复网络请求,回测调参快如闪电。
-
复权方式(adjust)、数据长度都写在函数参数中,防呆防错。
-
以后如果要扩展或更换数据源,只需要修改这个 data_loader.py 即可,其他策略无需改动任何一行代码。
3. 策略层:每个策略写成可复用函数
比如经典的双均线策略 strategies/ma_cross.py:
import pandas as pd
def ma_cross_signal(
df: pd.DataFrame,
short_window: int = 20,
long_window: int = 60,
) -> pd.DataFrame:
"""生成双均线交叉交易信号"""
df = df.copy()
df["ma_short"] = df["close"].rolling(short_window).mean()
df["ma_long"] = df["close"].rolling(long_window).mean()
# 均线多头排列时信号为 1,否则为 0
df["signal"] = (df["ma_short"] > df["ma_long"]).astype(int)
return df
注意,这里策略函数只负责生成 signal(信号),绝对不参与计算收益。
把“信号生成”和“回测计算”彻底解耦,是一个至关重要的专业习惯。否则,你每个策略文件里都会充斥着大量的收益率计算、滑点扣除、绩效画图代码,越写越臃肿,极难维护。
4. 回测层:统一处理收益、成本和指标
在 backtest.py 中写一个通用的回测引擎:
import numpy as np
import pandas as pd
def calc_metrics(equity: pd.Series, returns: pd.Series) -> dict:
"""计算核心量化绩效指标"""
total_return = equity.iloc[-1] / equity.iloc[0] - 1
annual_return = (1 + total_return) ** (252 / len(equity)) - 1
drawdown = equity / equity.cummax() - 1
sharpe = 0 if returns.std() == 0 else returns.mean() / returns.std() * np.sqrt(252)
return {
"total_return": total_return,
"annual_return": annual_return,
"max_drawdown": drawdown.min(),
"sharpe": sharpe,
}
def backtest_single_asset(
df: pd.DataFrame,
fee: float = 0.0003,
slippage: float = 0.0002,
) -> tuple[pd.DataFrame, dict]:
"""对单只标的运行标准回测(含手续费与滑点)"""
df = df.copy().dropna(subset=["signal"])
# 【避坑红线】:信号后移一天,保证收盘后次日开盘买入,规避未来函数
df["position"] = df["signal"].shift(1).fillna(0)
df["ret"] = df["close"].pct_change().fillna(0)
df["strategy_ret"] = df["position"] * df["ret"]
# 计算交易摩擦
df["turnover"] = df["position"].diff().abs().fillna(0)
df["cost"] = df["turnover"] * (fee + slippage)
df["strategy_ret"] = df["strategy_ret"] - df["cost"]
# 净值曲线
df["equity"] = (1 + df["strategy_ret"]).cumprod()
metrics = calc_metrics(df["equity"], df["strategy_ret"])
return df, metrics
有了这个模块,以后你写任何单标的策略(如突破、MACD、RSI 等),只要在策略函数里生成标准的 signal 序列,就能直接扔进这个回测引擎里。这就是工作台的意义:把重复劳动变少,把研究动作变标准。
5. 配置层:每次实验都保存参数
不要把任何选股参数、均线窗口死写在 Python 代码里。我们统一使用外部 JSON 文件(例如 configs/ma_cross.json)来进行实验配置:
{
"name": "ma_cross_600519",
"symbol": "600519.SH",
"count": 800,
"adjust": "forward",
"short_window": 20,
"long_window": 60,
"fee": 0.0003,
"slippage": 0.0002
}
主运行程序 main.py 只需要读取这个配置,并依次调用我们的工作台各层组件:
import json
from data_loader import QuantDashDataLoader
from strategies.ma_cross import ma_cross_signal
from backtest import backtest_single_asset
# 1. 加载本次实验的配置文件
with open("configs/ma_cross.json", "r", encoding="utf-8") as f:
config = json.load(f)
# 2. 从数据层取数(自动命中本地缓存)
loader = QuantDashDataLoader()
df = loader.load_daily_bars(
config["symbol"],
count=config["count"],
adjust=config["adjust"],
)
# 3. 策略信号生成
df = ma_cross_signal(
df,
short_window=config["short_window"],
long_window=config["long_window"],
)
# 4. 执行标准化回测
result, metrics = backtest_single_asset(
df,
fee=config["fee"],
slippage=config["slippage"],
)
print("=== 回测绩效 ===")
print(metrics)
这样你每次实验的输入都被清晰、固化地记录了下来。当你以后回看结果时,再也不会面对一堆不知道用什么参数跑出来的“孤儿”图表而抓狂。
6. 报告层:保存结果,而不是只打印
每次回测运行结束后,将这三样东西保存到同一个实验文件夹中:
-
配置快照(config.json)
-
回测指标(metrics.json)
-
收益曲线及明细(result.csv + equity.png)
from pathlib import Path
import json
import matplotlib.pyplot as plt
# 根据实验名建立专属报告夹
run_dir = Path("reports/runs/ma_cross_600519")
run_dir.mkdir(parents=True, exist_ok=True)
with open(run_dir / "config.json", "w", encoding="utf-8") as f:
json.dump(config, f, ensure_ascii=False, indent=2)
with open(run_dir / "metrics.json", "w", encoding="utf-8") as f:
json.dump(metrics, f, ensure_ascii=False, indent=2)
result.to_csv(run_dir / "result.csv", index=False)
# 绘制净值图并保存
result.set_index("trade_date")["equity"].plot(figsize=(10, 5))
plt.tight_layout()
plt.savefig(run_dir / "equity.png", dpi=160)
plt.close()
运行后,一个确定性的实验目录就诞生了:
reports/runs/ma_cross_600519/
├── config.json
├── metrics.json
├── result.csv
└── equity.png
这对于长期维护和复盘非常舒服。你可以随时翻阅、随时对比,也可以直接打包发给 AI 帮助你做更深一步的绩效归因和漏洞分析。
7. AI 在工作台里能做什么
当你的项目结构(目录树、文件调用职责、参数标准)稳定下来之后,大语言模型(如 Codex 等)的作用会被无限放大。你可以非常轻松地对 AI 发出以下指令:
-
【新增策略】:
"请在 strategies/ 下新增一个 rsi_reversal.py。要求生成 signal 字段:RSI 小于 30 时买入信号设为 1,大于 50 时卖出信号设为 0。不要在策略函数里计算收益,保持和 ma_cross.py 完全一致的函数和入参风格。"
-
【扩展回测引擎特征】:
"请给 backtest.py 中的 backtest_single_asset 函数增加一个可选的 benchmark 参数。如果传入基准价格序列,请自动计算超额收益(Alpha)和信息比率(Information Ratio),并并入 metrics 返回。"
-
【全面防作弊自查】:
"请检查我整个 quant-workbench/ 目录下的回测代码,重点帮我检查信号(signal)、持仓(position)和收益率(ret)的对齐关系,看看有没有任何未来函数或偷看收盘价的可能。如果有,请立刻指出并给出修改方案。"
最关键的是,你不再让 AI 去面对一团无章可循的散乱脚本,而是在一个具有严谨标准的高内聚项目里工作。 这样 AI 能够以极高的成功率理解你的开发意图,并产生极高质量的代码改动。
8. 一个适合发给 AI 的项目提示词
当你新开一个 AI 会话时,建议把这段作为工作台的全局说明发给它:
这是我的个人量化研究工作台。
数据源使用 QuantDash:
- QuantDash 官网:https://quantdash.net/
- Python SDK 文档:https://docs.quantdash.net/
常用接口:
- 日K线:qd.klines.get(symbol, period="1d", count=800, adjust="forward", to_dataframe=True)
- 批量 K 线:qd.klines.batch(symbols, period="1d", count=800, adjust="forward", to_dataframe=True)
- 实时行情:qd.quotes.get(symbols=symbols, to_dataframe=True)
- 全量 A 股:qd.quotes.get(universes="CN_Stock", to_dataframe=True)
- 全量 ETF:qd.quotes.get(universes="CN_ETF", to_dataframe=True)
- 五档盘口:qd.depth.get(symbol)
项目约定:
1. data_loader.py 只负责从 QuantDash 取数和本地 CSV 缓存。
2. strategies/ 里的各个策略函数只负责生成 signal 字段,绝对不计算收益。
3. backtest.py 统一负责处理 position、returns、cost、equity、metrics 的核心回测逻辑。
4. 所有的 signal 都必须 shift(1) 后才能转化为下一天的持仓 position,以彻底避免未来函数。
5. 每次运行完,都要在 reports/runs/[实验名]/ 下保存 config.json、metrics.json、result.csv、equity.png。
6. 不要把 API key 暴露在明文代码里,使用 QUANTDASH_API_KEY 环境变量自动读取。
有了这段上下文,你后续让 AI 新增策略、写多标的回测、甚至参数扫描时,它都会表现得像一个深谙你习惯的熟手助理。
9. 工作台的下一步:从脚本到小应用
当你这个命令行的工作台稳定运行、积累了几十次策略回测之后,你可以顺理成章地借助 Streamlit 做一个简单的本地可视化面板:
-
参数面板:用 Streamlit 拖拽滑动条选择均线窗口、止损比例,自动重写 config.json。
-
图表展示:用 Streamlit 直接绘制动态交互的净值曲线、回撤曲线、持仓占比图。
-
实验历史列表:读取 reports/runs,做一个历史回测夏普比率排行榜。
-
盘中行情监控:接入 QuantDash 的实时行情,计算当前自选股的多周期指标,自动生成预警提示。
量化研究是一门长期的工程实践。先从一个最简单的、数据与逻辑解耦的轻量级工作台开始。不要一开始就追求庞大完美,追求**“让每次实验都有据可查,让每次回测都真实可信”**,你的研发和迭代效率就会获得质的飞跃。
结语与“三步走”落地指引
-
第一步:获取完整源码。请访问官方开源托管仓库获取本文完整 Demo 代码架构及进阶配置:https://github.com/quantdash-net/QuantDash(请认准官方 quantdash-net 组织,欢迎 Star 支持)。
-
第二步:申请专属密钥。注册获取您的个人免费/生产级 API Key:https://quantdash.net/。
-
第三步:查阅开发细节。更多高频行情、多市场 Tick 及实时深度五档盘口接口参数请参考:https://docs.quantdash.net/。
更多推荐

所有评论(0)