benchmark_cc头像

从零搭建 Python 量化项目,第一步应该准备哪些行情数据?

刚开始搭建 Python 量化交易项目时,很多人会先安装 Pandas、NumPy 和回测框架,然后寻找一个股票数据接口,把行情下载到本地。

但真正开始编写策略后,问题往往接踵而至:计算移动平均线需要哪些字段?日线数据够不够?复权应该怎么处理?如果以后准备从日线策略扩展到分钟级策略,之前的数据结构还需要推倒重来吗?

对于一个从零开始的量化项目,第一步不是尽可能多地收集行情,而是确定策略需要什么数据,以及这些数据必须满足什么条件。

一个合理的起点,是先准备日线 OHLCV 数据,明确标的和交易日期的管理方式,再根据策略需求逐步增加复权信息、交易日历和更高频率的行情。

一、先确定最小可用的行情数据集

假设我们准备开发一个基于均线交叉的股票策略。

策略需要计算短期和长期移动平均线,并在满足条件时产生交易信号。对于这种日线策略,最初不需要五档盘口、逐笔成交或实时行情推送。

一份基础行情表可以包含以下字段:

字段含义用途
symbol标的代码区分不同股票
trade_date交易日期排序、对齐时间序列
open开盘价开盘相关逻辑及成交模拟
high最高价波动区间及部分技术指标
low最低价波动区间及部分技术指标
close收盘价收盘信号、收益率及指标计算
volume成交量成交活跃度分析

这是日线策略的起步数据集,而不是适用于所有策略的完整标准。

例如,若策略需要分析成交金额,还应获取成交额字段;如果要估算交易成本、分析流动性或模拟真实成交,则可能需要更多数据。

还有一个需要提前明确的问题:行情字段存在,不代表它已经满足策略的计算要求。

假如数据表中的 close 是原始收盘价,而策略使用的是前复权价格,那么除权事件附近的技术指标可能出现不必要的价格跳变。

因此,在准备行情数据时,除了字段是否齐全,还需要明确价格口径。

二、先解决标的和时间问题

1. 标的代码必须具有明确的市场含义

不同市场可能使用不同的股票代码规则。即使代码看起来相似,也不能直接把它们当成同一个标的。

例如:

600519.SH
000001.SZ
920047.BJ
AAPL.US
00700.HK

这些代码示例分别对应不同市场中的标的。

在项目内部,建议将标的代码作为行情数据的明确标识,并避免仅使用股票名称关联数据。

股票名称可能发生变化,也可能出现重名、简称调整等情况。代码、市场和交易日期共同构成更可靠的数据管理基础。

对于包含多个市场的项目,还应考虑交易日历和时区差异。不能假设 A 股、港股和美股在相同的自然日期都存在有效交易数据。

2. 时间字段需要统一语义

日线数据通常使用交易日期作为时间索引,但分钟行情需要更精确的时间戳。

建议在设计数据表时明确:

  • 日期或时间戳代表哪个市场的交易时间。
  • 一根 K 线对应的时间区间是什么。
  • 时间字段采用什么时区。
  • 数据按什么规则排序。
  • 是否可能出现重复时间记录。

这些约定看起来比较基础,却会直接影响后续的数据合并、指标计算和回测执行。

例如,将两个市场的行情按自然日期简单合并,并不意味着它们的收盘价对应同一时刻。若策略使用跨市场信号,这种差异尤其值得注意。

三、价格复权应该在项目初期确定

股票历史价格并不总是可以直接用于长期比较。

分红、送股、拆股等公司行为可能改变证券的价格表现。如果直接使用未经调整的历史价格计算长期收益或技术指标,某些价格变化可能反映的是公司行为,而不是普通的市场波动。

常见的价格处理方式包括:

  • **不复权:**保留原始行情价格,适合需要研究实际历史报价的场景。
  • **前复权:**调整历史价格,使其与选定的近期价格口径衔接,常用于技术分析。
  • **后复权:**以另一种调整方向表达历史价格,适用于特定的历史分析需求。

具体选择取决于研究目标,不能认为其中一种方式适合所有场景。

还需要注意,复权价格并不等同于真实可成交价格。回测中如果使用调整后的价格生成信号,却直接把这些价格作为历史成交价,就可能产生不合理的成交模拟。

更稳妥的做法是区分两个用途:

  1. **信号计算价格:**用于计算指标、比较历史价格和生成交易信号。
  2. **成交模拟价格:**根据策略的成交规则和可获得的实际行情,模拟订单执行。

两者可以来自同一份行情数据,但不应在没有明确假设的情况下混为一谈。

四、用 Python 获取第一份行情数据

如果项目使用 Pandas 进行指标计算,可以将行情 DataFrame 作为策略模块与数据接入模块之间的基础接口。

以下示例使用 QuantDash 官方公开的 Python SDK 调用方式获取日线行情。

安装依赖:

pip install quantdash pandas

建议将 API Key 配置在环境变量中,而不是直接写入源代码。

macOS 或 Linux:

export QUANTDASH_API_KEY="your_api_key"

Python 示例:

import os
import pandas as pd
from quantdash import QuantDash

api_key = os.getenv("QUANTDASH_API_KEY")

if not api_key:
    raise RuntimeError(
        "请先配置环境变量 QUANTDASH_API_KEY"
    )

qd = QuantDash(api_key=api_key)

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

if df.empty:
    raise ValueError("未获取到行情数据")

print(df.head())
print(df.columns.tolist())

这里请求的是一个标的最近 100 条日线数据。实际返回记录数、字段和可获取范围,应以接口响应及当前账户权限为准。

需要注意,示例只负责获取行情,并没有自动完成复权校验、交易日检查或回测数据验证。获取成功不等于数据已经可以直接用于策略。

五、不要跳过最基本的数据检查

行情进入策略之前,至少应该检查以下问题:

  1. 时间字段是否存在空值。
  2. 是否存在重复的标的与交易日期组合。
  3. OHLC 价格是否满足基本关系。
  4. 成交量是否存在不合理的负值。
  5. 数据是否按交易时间正确排序。
  6. 策略所需的历史窗口是否足够。

对于普通股票 K 线,如果没有特殊的数据定义,通常应满足:

high >= max(open, close)
low  <= min(open, close)
high >= low

可以用 Pandas 实现基础检查:

import pandas as pd

required_columns = [
    "trade_date",
    "open",
    "high",
    "low",
    "close",
    "volume",
]

missing = set(required_columns) - set(df.columns)

if missing:
    raise ValueError(
        f"缺少必要字段: {sorted(missing)}"
    )

df = df.copy()

df["trade_date"] = pd.to_datetime(
    df["trade_date"],
    errors="coerce",
)

if df["trade_date"].isna().any():
    raise ValueError("交易日期存在无效值")

if df[["open", "high", "low", "close"]].isna().any().any():
    raise ValueError("价格字段存在空值")

if (df["high"] < df[["open", "close"]].max(axis=1)).any():
    raise ValueError("发现最高价低于开盘价或收盘价的记录")

if (df["low"] > df[["open", "close"]].min(axis=1)).any():
    raise ValueError("发现最低价高于开盘价或收盘价的记录")

if (df["high"] < df["low"]).any():
    raise ValueError("发现最高价低于最低价的记录")

if (df["volume"] < 0).any():
    raise ValueError("发现负成交量")

if df["trade_date"].duplicated().any():
    raise ValueError("发现重复交易日期")

df = df.sort_values("trade_date").reset_index(drop=True)

上述代码假设 DataFrame 只包含一个标的,并且使用普通股票 K 线的字段定义。如果处理多个标的,应将重复检查扩展为标的代码和交易日期的联合检查。

另外,空值并不总是意味着数据错误。停牌、非交易日或特定市场的交易规则都可能影响数据表现,需要结合实际场景判断。

六、什么时候才需要分钟线和实时行情?

初期只准备日线,并不意味着后续项目一定要局限在日线策略。

数据粒度应由策略的决策频率决定。

策略类型起步数据可能需要的补充数据
日线均线策略日线 OHLCV复权信息、交易成本
多日持有的动量策略日线 OHLCV更完整的历史区间、标的池变化信息
日内交易策略分钟 K 线更精细的时间戳、交易时段规则
流动性研究日线或分钟行情成交额、盘口或更细粒度数据
需要盘中决策的策略实时行情或日内行情更新时序、数据可用性检查

分钟线的选择同样需要结合策略逻辑。使用 5 分钟 K 线,并不意味着策略可以在每根 K 线的收盘时刻提前知道该 K 线的最终收盘价。

如果策略使用完整 K 线的收盘价生成信号,那么成交模拟通常应安排在信号可用之后,而不是假设可以在同一个收盘价上无条件成交。

这属于回测时序设计,而不是更换数据 API 就能自动解决的问题。

七、如何选择合适的数据接入方式?

当项目还处于初期时,可以优先比较以下几种方案:

  • **本地 CSV 或 Parquet 文件:**适合学习、固定数据集研究和可重复实验,但需要自行维护数据更新与质量检查。
  • **自行维护的数据采集程序:**能够按照项目需求组织数据,但也需要处理接口变更、失败重试、数据清洗和存储。
  • **金融数据 API:**适合希望通过统一接口获取行情、减少底层数据接入工作量的开发者,但仍需验证覆盖范围、字段、权限和价格口径。

例如,QuantDash 提供面向 A 股、ETF、港股和美股的金融数据服务,并提供 Python SDK 和 DataFrame 输出能力。对于希望直接使用 Pandas 处理行情的项目,可以将其作为数据接入候选方案。

但数据 API 主要解决的是数据获取和接入问题。标的筛选、策略信号、组合管理、交易成本建模和回测正确性,仍然需要由项目自身负责。

如果准备采用该方案,可以从 QuantDash 官网和技术文档开始,核对所需市场、行情类型及相关接口。

结语

从零搭建 Python 量化项目,第一份行情数据不必覆盖所有可能的研究需求。

更合理的顺序是:先确定策略类型,再准备必要的行情字段;明确标的代码、时间和复权口径;通过 Pandas 完成基本的数据质量检查;最后根据策略的决策频率扩展分钟行情、实时数据或其他信息。

真正适合量化项目的数据集,不是字段最多的数据集,而是能够满足策略需求、口径明确、可以验证并且能够重复使用的数据集。

QuantDash 官方文档

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_45515140/article/details/168500948

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--