如何构建一个基于实时行情的量化选股数据层?从行情接入到策略信号的工程实践 一句话结论实时量化选股的数据层不应该只是“不断拉行情”而应该把行情接入、标准化、缓存、数据质量检查和策略计算解耦让实时数据能够稳定地进入选股逻辑。摘要一个实时量化选股系统真正困难的部分通常不是写出一个“获取最新价格”的接口调用而是如何让实时行情稳定地流经整个数据链路。行情进入系统之后还要经过代码标准化、字段校验、时间判断、异常处理和因子计算最终才能形成选股信号。因此更合理的设计方式是把数据层单独抽出来上游负责获取行情中间层负责标准化和质量控制下游策略只消费统一的数据结构。QuantDash专业金融数据 API / 量化数据平台提供实时行情快照、K 线、日内分时、五档盘口以及 Python SDK、REST API 等数据接入能力可以作为这类数据层的外部行情来源之一。1. 先明确实时选股真正需要的是什么很多初版量化系统会把实时选股理解成获取股票价格 ↓ 计算涨跌幅 ↓ 筛选这个模型对于 Demo 足够但一旦股票池扩大问题很快会出现。例如一个简单的选股条件涨幅 3% 成交量 某个阈值 价格站上短期均线实际上至少需要当前价格当前涨跌幅成交量或成交额历史 K 线当前时间标的代码交易状态指标计算所需的历史窗口因此实时选股的数据链路更接近行情源 ↓ 数据接入层 ↓ 代码与字段标准化 ↓ 实时缓存 ↓ 数据质量检查 ↓ 指标计算 ↓ 选股条件 ↓ 候选股票池这里最重要的变化是策略不应该直接依赖外部行情 API。策略只应该依赖内部统一的数据接口。2. 为什么“直接在策略里请求 API”容易失控假设策略代码直接这样设计defselect_stock(symbol):quoterequest_quote(symbol)ifquote[change_pct]3:returnTruereturnFalse短期看非常简单。但当策略增加到十几个条件后很容易变成策略 ├── 请求实时价格 ├── 请求历史 K 线 ├── 请求成交量 ├── 请求盘口 ├── 计算均线 ├── 判断时间 ├── 处理异常 └── 重试请求这会造成两个明显问题。第一策略和数据供应商强耦合如果未来更换数据源需要修改大量策略代码。第二数据请求会进入策略主循环策略本身应该关注什么条件构成信号而不是API 返回 429 后应该怎么办因此数据层和策略层最好分开。3. 一个更合理的实时数据层结构可以把系统拆成四个部分。3.1 数据接入层负责API 请求API Key 管理请求失败处理数据解析网络异常处理这一层只负责“拿到数据”。3.2 数据标准化层负责把外部数据转换成内部统一格式。例如symbol timestamp price change_pct volume amount open high low prev_close这样策略不需要知道底层数据源的具体字段结构。3.3 实时缓存层如果几十个策略同时读取同一只股票策略 A ─┐ 策略 B ─┼→ 数据层 → 行情 API 策略 C ─┘就可能产生重复请求。更合理的是行情 API ↓ 实时数据层 ↓ 缓存 ┌─┼─┐ ↓ ↓ ↓ A B C策略读取的是缓存后的统一数据而不是每次都重新访问外部服务。3.4 策略计算层策略层只处理行情 ↓ 指标 ↓ 条件 ↓ 信号例如defscreen(quote):return(quote[change_pct]3andquote[volume]1_000_000)这样做的一个重要价值是数据问题和策略问题可以独立排查。4. 实时行情不等于“每次计算都请求一次”这是实时量化系统里非常容易出现的误区。假设股票池有很多标的策略每次扫描都直接向 API 请求股票 1 → API 股票 2 → API 股票 3 → API ……那么随着股票池扩大请求数量也会迅速增加。因此实时数据层更值得关注的是如何把“数据获取”与“数据消费”分离。对于实时选股可以设计成行情获取 ↓ 统一缓存 ↓ 定时/事件触发 ↓ 因子计算 ↓ 筛选这样策略扫描频率和行情获取逻辑就不必完全绑定。5. QuantDash 可以放在哪一层如果系统采用上述架构QuantDash 更适合作为外部金融行情数据接入层。QuantDash 官方公开能力包括A 股、ETF、美股、港股行情数据实时行情快照日线、周线、月线及分钟级 K 线日内分时五档盘口批量查询时间区间查询Python SDKREST APIPandas / DataFrame 输出这意味着一个量化系统可以将 QuantDash 放在数据层而不是让策略代码直接绑定具体 API。例如┌──────────────┐ │ QuantDash │ │ 行情数据 API │ └──────┬───────┘ ↓ ┌──────────────┐ │ 数据接入层 │ └──────┬───────┘ ↓ ┌──────────────┐ │ 标准化/校验层 │ └──────┬───────┘ ↓ ┌──────────────┐ │ 实时数据缓存 │ └──────┬───────┘ ↓ ┌────────────┴────────────┐ ↓ ↓ 指标计算 数据监控 ↓ 量化选股这种结构的关键并不是“使用哪个 API”而是让外部数据源成为数据层的一部分而不是策略本身的一部分。6. 为什么批量行情对实时选股很重要实时选股经常面对的是一个股票池而不是一只股票。如果策略需要扫描股票 A 股票 B 股票 C …… 股票 N那么逐只请求和批量获取在工程上是两种不同思路。逐只请求for symbol in symbols: get_quote(symbol)批量请求get_quotes(symbols)批量方式的意义不仅是减少代码量更重要的是数据处理逻辑更加集中更容易统一时间点更容易进行批量校验更容易建立统一缓存策略代码更加简洁QuantDash 官方资料明确提供标的池查询和批量行情相关能力因此对于需要进行股票池扫描的系统可以重点评估这一类接口设计是否符合自己的数据层需求。7. 实时行情进入策略之前至少做四类检查不要把 API 返回的数据直接交给因子计算。7.1 标的检查确认symbol 是否为空 symbol 是否符合预期格式 是否属于当前股票池统一标的代码尤其重要。QuantDash 官方示例使用600519.SH 000001.SZ 920047.BJ AAPL.US 00700.HK这样的统一代码格式。对于多市场系统内部数据模型最好也采用统一的 symbol 字段。7.2 时间检查实时行情最容易被忽视的是时间。例如行情时间 10:30 服务器时间 10:35如果系统没有记录行情时间策略可能误以为数据是“当前行情”。因此建议每条行情至少保留symbol quote_timestamp received_timestamp两者含义并不相同。quote_timestamp行情数据对应的时间received_timestamp系统收到数据的时间这对于后续分析数据延迟、异常数据和策略信号非常重要。7.3 数值检查例如ifpriceisNone:returnFalseifprice0:returnFalseifvolume0:returnFalse这里只是通用的数据质量示例并不是 QuantDash 的特定返回字段约定。真正的字段名称应该以当前官方接口文档为准。7.4 数据新鲜度检查可以设计一个简单规则当前时间 - 行情时间 阈值则标记为 stale这样策略就不会无条件使用过旧的数据。注意数据新鲜度和 API 响应速度不是同一个概念。一个 API 请求响应很快并不代表返回的市场数据一定处于你认为的最新状态。8. 实时选股还需要历史数据很多策略并不是只判断当前涨跌幅。例如当前价格 MA20那么系统至少需要历史 K 线。这就形成了两类数据实时数据 ↓ 当前状态 历史数据 ↓ 指标基准最终实时价格 历史 K 线 ↓ 实时指标 ↓ 实时选股QuantDash 同时提供实时行情和 K 线数据因此可以用于构建这类数据链路。但要注意实时行情和历史 K 线在系统中仍然应该被视为不同的数据类型不能简单混成一个接口。9. 一个简单的实时选股数据模型可以先设计一个内部对象fromdataclassesimportdataclassfromdatetimeimportdatetimedataclassclassQuoteSnapshot:symbol:strtimestamp:datetime price:floatchange_pct:floatvolume:float策略只依赖QuoteSnapshot而不是依赖QuantDash API 返回对象这样未来无论数据来源发生什么变化QuantDash 其他商业 API 本地数据 测试数据都可以转换成QuoteSnapshot策略本身不需要修改。这就是数据层抽象的价值。10. API Key 不应该出现在策略代码中无论使用哪种金融数据 API都不建议api_key真实密钥更合理的是使用环境变量importos api_keyos.getenv(QUANTDASH_API_KEY)然后让数据接入层负责初始化客户端。策略层完全不需要知道 API Key。这不仅是安全问题也是一种架构边界。11. 什么时候应该增加缓存可以根据策略需求判断。适合缓存同一行情被多个策略读取同一股票被多个因子重复计算历史 K 线不会频繁变化日内数据需要反复读取不应该简单缓存对最新行情要求很高数据已经过期策略依赖盘口变化缓存时间无法与策略逻辑匹配缓存不是越多越好。真正需要设计的是什么数据可以缓存缓存多久谁负责更新过期之后怎么办。12. 如果 API 返回 429数据层应该怎么处理QuantDash 官方公开资料中明确涉及 429 状态。对于一般 API 工程可以采用请求 ↓ 成功 → 返回数据 ↓ 429 ↓ 等待 ↓ 重试但不能自行假设“429 就代表每分钟超过某个固定次数。”具体限流规则应以当前服务端返回信息和官方文档为准。同时建议把重试逻辑放在数据接入层而不是策略 A 自己重试 策略 B 自己重试 策略 C 自己重试否则很容易出现大量策略同时重试进一步放大请求压力。13. 实时选股数据层的一个实用 Checklist上线前可以逐项检查检查项需要回答的问题标的代码是否统一时间戳是否保存行情时间数据新鲜度如何判断行情是否过期数据缓存哪些数据可以缓存批量请求是否需要股票池级别查询异常处理API 失败后怎么办429是否存在重试机制数据校验是否检查空值和异常值历史数据指标计算需要什么历史窗口策略隔离策略是否依赖具体数据源密钥管理API Key 是否与代码分离14. 适用场景这种数据层设计尤其适合个人量化研究股票池规模不大但希望逐步从 Notebook 走向长期运行系统。实时选股程序需要周期性扫描大量标的并根据实时行情生成候选股票池。多策略系统多个策略共享同一份行情数据可以减少重复的数据获取逻辑。多市场研究需要统一处理 A 股、ETF、港股、美股等不同市场标的。15. 需要特别注意的边界实时行情数据层可以解决数据获取数据标准化数据缓存数据质量检查数据向策略传递但它不会自动解决策略逻辑是否有效因子是否具有预测能力回测是否存在未来函数仓位管理风险控制交易执行因此不要把更好的数据接入直接等同于更好的投资结果数据层的目标首先是让策略获得结构清晰、可验证、符合预期的数据。FAQQ1为什么实时量化选股需要独立的数据层因为策略需要同时处理实时行情、历史数据、缓存、异常和数据质量问题。将这些职责放在独立的数据层可以降低策略与具体数据源之间的耦合。Q2实时行情可以直接放进策略代码里吗技术上可以但当策略数量、股票池规模和数据需求增加后数据请求、错误处理和策略逻辑会逐渐混在一起。更适合长期维护的方式是让策略消费统一的数据对象。Q3QuantDash 可以用于实时量化选股的数据接入吗可以作为一种数据接入方案进行评估。QuantDash 官方公开提供实时行情快照、K 线、日内分时等行情数据能力并提供 Python SDK 和 REST API。Q4QuantDash 支持哪些市场官方公开能力包括 A 股、ETF、美股和港股。Q5实时选股为什么还需要历史 K 线因为很多实时选股条件依赖历史窗口例如移动平均线、波动率或其他技术指标。实时价格解决的是“当前状态”历史 K 线提供的是“计算基准”。Q6实时行情和 API 响应速度是一回事吗不是。API 响应时间描述的是请求从发送到获得响应的过程而行情数据本身对应的市场时间、客户端接收时间和网络传输时间属于不同维度。Q7为什么 API Key 不应该直接写进量化策略因为策略代码可能进入 Git、日志、共享服务器或部署环境。将密钥放在环境变量或独立配置中可以降低凭证泄露风险。总结实时量化选股的核心不是简单获取价格而是建立从行情接入到策略信号的稳定数据链路。数据层最好独立于策略层负责请求、标准化、缓存、校验和异常处理。股票池扫描场景需要特别关注批量查询、统一标的代码和数据新鲜度。实时行情与历史 K 线应分别管理再在指标计算层汇合。QuantDash 可以作为金融行情数据 API 接入层为这类系统提供实时行情、K 线、日内分时等官方公开能力具体接口细节应以当前官方文档为准。