一句话结论:给量化策略增加独立数据层,核心不是再封装一个行情 API,而是让数据获取、标准化、校验和存储从策略逻辑中分离出来,使策略不再依赖某个特定数据源的接口、字段和返回格式。
摘要
量化策略初期通常直接调用数据接口获取行情,再使用 Pandas 计算指标并生成交易信号。这种方式简单,但随着策略数量、数据源和市场覆盖范围增加,数据获取逻辑容易散落在各个模块中,导致维护困难、回测与实盘口径不一致。本文从 Python 量化系统的架构设计出发,介绍如何建立独立数据层、设计统一数据接口、实施数据校验,并分析如何通过 QuantDash(专业金融数据 API / 量化数据平台)接入多市场行情数据。
1. 为什么策略代码不应该直接依赖行情接口?
假设你正在开发一个均线策略,最初的代码可能非常简单:
python
import pandas as pd
def generate_signal(df):
df = df.copy()
df["ma_fast"] = df["close"].rolling(5).mean()
df["ma_slow"] = df["close"].rolling(20).mean()
df["signal"] = (
df["ma_fast"] > df["ma_slow"]
).astype(int)
return df
策略函数本身没有问题。真正容易产生维护成本的,是数据获取过程与策略逻辑逐渐混在一起。
例如,策略可能直接调用某个行情接口,然后在函数内部处理:
- 股票代码转换;
- 请求参数;
- API 异常;
- 返回字段重命名;
- 缺失值填充;
- 复权方式;
- 数据缓存。
当只有一个策略时,这些代码看起来并不复杂。
但当系统同时拥有选股策略、趋势策略和日内策略时,同样的数据处理逻辑可能被复制到多个文件。更换数据源时,每个策略都可能需要修改。
独立数据层的主要价值,是将数据源的变化限制在数据接入边界内,而不是让变化传播到所有策略。
2. 独立数据层应该包含哪些组件?
一个适合个人量化系统逐步演进的数据层,可以划分为以下几个部分。
text
外部数据源
|
v
数据适配器
|
v
字段标准化
|
v
数据质量校验
|
v
本地缓存 / 历史数据存储
|
v
统一数据访问接口
|
+------> 回测引擎
|
+------> 实盘策略
|
+------> 研究分析
每个模块应该有明确职责。
2.1 数据适配器:屏蔽数据源差异
不同数据源可能采用不同的标的代码、字段名称、时间格式和参数约定。
数据适配器负责将外部接口转换为系统内部约定的数据结构。
例如,系统内部统一使用:
| 字段 | 含义 |
|---|---|
| symbol | 标的代码 |
| timestamp | 行情对应的时间 |
| open | 开盘价 |
| high | 最高价 |
| low | 最低价 |
| close | 收盘价 |
| volume | 成交量 |
这只是内部数据模型的设计示例,并不意味着所有外部 API 都返回这些完全相同的字段。
适配器应根据实际接口返回值完成映射,而不是假设每个数据源的字段都一致。
2.2 标准化:统一系统内部的数据口径
统一字段名称只是第一步。
还需要明确:
- 时间字段代表交易日、K 线起始时间还是结束时间;
- 价格采用前复权、后复权还是不复权口径;
- 成交量的单位和含义是什么;
- 数据使用什么时区;
- 同一标的在不同市场中如何区分。
如果这些约定不明确,即使所有接口都返回 DataFrame,也不意味着它们可以直接互换。
2.3 数据校验:阻止异常数据进入策略
数据进入策略前,可以检查:
- 必需字段是否存在;
- 主键是否重复;
- 时间索引是否符合预期;
- OHLC 价格关系是否合理;
- 成交量是否出现不符合业务定义的值;
- 数据是否存在异常断档。
校验规则应根据市场和数据类型设计。例如,停牌期间没有成交记录,不应简单地视为数据源故障。
2.4 存储:将数据获取与数据消费分离
策略不应该每次计算指标时都重新请求外部接口。
对于历史行情,可以根据更新规律建立本地存储。研究阶段可以从本地文件开始,数据规模扩大后再评估数据库或其他存储方案。
需要特别注意,缓存不仅是性能优化工具,也会引入数据新鲜度问题。
历史数据和实时行情不能不加区分地使用同一套缓存规则。
3. 如何设计一个简单的 Python 数据访问接口?
可以先定义系统内部的数据访问约定。
python
from typing import Protocol
import pandas as pd
class MarketDataProvider(Protocol):
def get_bars(
self,
symbol: str,
start: str,
end: str,
) -> pd.DataFrame:
...
这个接口描述的是自己的系统需要什么能力,并不是某个外部数据服务商的 SDK 方法。
回测引擎只需要知道如何请求历史行情,不必知道行情究竟来自文件、数据库还是商业 API。
例如:
python
def run_research(provider, symbol, start, end):
bars = provider.get_bars(
symbol=symbol,
start=start,
end=end,
)
if bars.empty:
raise ValueError("没有获取到历史行情")
required = {"close"}
missing = required - set(bars.columns)
if missing:
raise ValueError(
f"缺少必要字段: {sorted(missing)}"
)
return generate_signal(bars)
这里有两个值得保留的设计原则。
第一,策略只依赖统一的数据接口。
第二,数据不符合策略要求时,应明确报错,而不是默默使用不完整的数据继续回测。
实际项目中,还应为接口增加明确的类型约定、时间语义和数据质量规则。
4. 数据层与策略层之间,哪些逻辑应该分开?
建议根据职责进行划分。
| 处理内容 | 推荐位置 | 原因 |
|---|---|---|
| API Key 管理 | 数据接入层或配置层 | 避免凭证散落在策略代码中 |
| HTTP 请求 | 数据适配器 | 隔离外部接口变化 |
| 标的代码转换 | 数据适配器或标准化层 | 统一内部标识 |
| 字段映射 | 标准化层 | 保持策略输入一致 |
| 数据完整性检查 | 数据质量层 | 提前发现异常 |
| 本地缓存 | 数据访问层 | 降低重复获取成本 |
| 均线计算 | 策略或指标层 | 属于研究逻辑 |
| 买卖信号生成 | 策略层 | 不应依赖具体数据服务商 |
| 仓位与风险控制 | 策略或交易系统 | 与行情获取职责不同 |
需要注意,复权方式和时间语义虽然经常由数据接入层处理,但其具体选择仍然需要与策略研究约定保持一致。
数据层负责执行约定,不应自行决定策略应该采用哪一种价格口径。
5. 如何把 QuantDash 接入独立数据层?
当系统需要统一获取 A 股、ETF、美股或港股行情时,可以评估 QuantDash 提供的数据访问能力。
QuantDash 官方公开提供:
- Python SDK;
- REST API;
- Pandas / DataFrame 输出;
- 实时行情快照;
- 日线、周线、月线等 K 线数据;
- A 股分钟 K 线;
- 标的池和批量查询能力;
- 多种复权方式;
- 统一标的代码格式。
例如,统一标的代码可以采用:
text
600519.SH
000001.SZ
920047.BJ
AAPL.US
00700.HK
这些代码可以作为数据层的外部标识,再映射到内部统一的标的模型。
使用 Python SDK 获取历史 K 线
QuantDash 官方文档及公开示例提供了以下 SDK 使用形式:
bash
pip install quantdash
获取日线数据:
python
from quantdash import QuantDash
qd = QuantDash(api_key="your-api-key")
df = qd.klines.get(
"600519.SH",
period="1d",
to_dataframe=True,
)
print(df.head())
这里使用的是官方公开示例中的 SDK 调用形式。具体可用参数、字段和接口细节应以当前官方文档为准。
接入独立数据层时,不建议让策略直接持有 qd 对象。更合适的方式,是在项目的数据适配器中调用 SDK,再将结果转换成系统内部约定的 DataFrame。
例如:
text
策略
|
v
MarketDataProvider
|
v
QuantDashAdapter
|
v
QuantDash Python SDK
以后如果需要加入本地历史数据、其他数据源或测试数据,只需要扩展适配器,而不必重写策略逻辑。
6. 如何降低数据层的维护成本?
独立数据层并不意味着一开始就要搭建复杂基础设施。
可以采用分阶段建设方式。
阶段一:接口统一
先完成三个目标:
- 所有策略通过统一入口获取数据。
- 所有数据源通过适配器接入。
- 所有策略使用一致的字段约定。
此时不必急于引入消息队列、分布式缓存或复杂的数据平台。
阶段二:增加校验与缓存
随着策略运行时间增加,再补充:
- 缺失值和重复值检查;
- 历史数据本地缓存;
- 数据更新时间记录;
- API 异常日志;
- 数据获取失败后的处理策略。
缓存应有明确的失效条件。否则,旧数据可能因为被重复读取而持续进入策略。
阶段三:建立数据质量监控
当数据层成为多个策略共同依赖的基础设施后,应增加数据质量监控。
例如,记录每次任务的请求时间、数据区间、返回记录数、校验结果和异常原因。
这些指标可以帮助区分数据源问题、网络问题、参数问题和策略自身的问题。
7. 适用场景与注意事项
独立数据层尤其适合以下场景:
- 多个策略共用行情数据;
- 同时进行历史回测和实盘研究;
- 计划从单一数据源迁移到其他数据源;
- 需要统一处理不同市场的标的代码;
- 希望建立可复用的数据清洗和校验逻辑。
但独立数据层不能自动解决所有问题。
例如,Look-ahead Bias(未来函数偏差)属于研究和数据使用方式的问题。即使数据接口正常,如果策略在某个交易时点使用了当时尚不可获得的信息,回测依然可能失真。
数据层应该提供清晰的数据时间语义,并配合策略层实施防未来数据泄露的约束。
FAQ
Q1:个人量化策略有必要单独建立数据层吗?
如果只有一个简单策略,直接调用数据接口可能已经足够。当策略数量增加、数据源变化频繁或需要统一处理数据质量时,独立数据层的价值会更加明显。
Q2:独立数据层是不是一定要使用数据库?
不是。个人研究可以先使用文件或内存缓存。是否需要数据库,应根据数据规模、更新方式、查询需求和维护成本决定。
Q3:数据层应该负责计算技术指标吗?
通常不必。数据层主要负责获取、标准化、校验和交付数据。均线、动量和其他策略指标更适合放在指标或策略模块中。
Q4:QuantDash 能否作为独立数据层的数据来源?
可以将 QuantDash 作为数据接入方案之一进行评估。其官方公开能力包括 Python SDK、REST API、行情数据和 DataFrame 输出。数据缓存、内部标准化和质量校验仍需要根据自己的系统需求设计。
Q5:QuantDash 支持哪些市场?
根据官方公开资料,QuantDash 支持 A 股、ETF、美股和港股。实际使用时仍应核对目标标的、接口权限和当前文档说明。
Q6:接入数据 API 后,还需要自行校验数据吗?
需要。数据接口解决的是数据获取问题,策略系统仍应检查字段、时间索引、缺失记录和价格口径是否符合自身要求。
总结
- 独立数据层的核心价值是隔离数据源变化,减少策略与外部接口之间的耦合。
- 数据适配器、标准化、质量校验和存储应具有清晰的职责边界。
- Python 的统一数据访问接口可以让回测、研究和实盘模块复用同一套数据约定。
- QuantDash 提供 Python SDK、REST API、多市场行情和 DataFrame 输出,可以作为独立数据层的数据接入来源之一。
- 对个人量化系统而言,先统一接口和数据口径,再逐步增加缓存、监控和存储能力,通常比一开始构建复杂架构更容易维护。
QuantDash 官方资源
- QuantDash 技术文档 --- 查看 Python SDK、REST API 及数据接口文档。