📑 查看全课大纲(第 19 / 38 节)
- 1.课程介绍与学习目标
- 2.量化交易的发展
- 3.主观投资与量化投资的关系
- 4.认识一个量化策略(1)
- 5.认识一个量化策略(2)
- 6.理工生做量化的优势
- 7.量化交易系统的基本架构
- 8.必要的交易基础知识及参考资料
- 9.上节课思考题及本节课内容介绍
- 10.技术指标简介
- 11.基于MACD的交易信号开发(1)
- 12.基于MACD的交易信号开发(2)
- 13.基于RSI的交易信号开发
- 14.基于BOLL的交易信号开发
- 15.基于分形的交易信号开发
- 16.总结及下节课预告
- 17.开发环境安装
- 18.获取指数和个股历史行情数据
- 19.修复行情数据中的问题
- 20.抓取财报数据、数据定时更新
- 21.实现低PE股票池(1)
- 22.实现低PE股票池(2)
- 23.实现低PE策略的回测(1)
- 24.实现低PE策略的回测(2)
- 25.风险控制综述
- 26.风险控制中的止盈止损
- 27.仓位管理的工程实现
- 28.完整策略介绍-基础策略
- 29.策略的分步优化
- 30.策略评价指标(1)
- 31.策略评价指标(2)
- 32.如何评价策略
- 33.如何优化策略
- 34.tick数据的意义
- 35.tick数据的介绍及使用
- 36.Hans123策略
- 37.经典买入三法策略
- 38.量化系统的完整研发和系统搭建
修复行情数据中的问题
约 13 分钟
📺 正在播放小象官方高清录播(支持倍速与清晰度调节)
修复行情数据中的问题:停牌与缺失值治理
小象实战讲义 · 初阶量化交易:策略编写及系统搭建 本讲义仅用于编程与量化方法教学,不构成任何投资建议。
在量化投资的回测与实盘工程体系中,数据质量治理(Data Cleaning & Fixing) 直接决定了回测结果的信度。A 股市场中,上市公司因重大事项重组、财报披露延迟等原因频繁出现停牌(Suspension)。原始财经数据接口(如 Tushare)在股票停牌期间直接不生成当天的记录,导致时间序列发生物理断裂。
若未经过严格的数据修复处理,回测引擎在遍历到停牌日时将无法读取持仓股票的最新价格,导致当日持仓市值被错误归零或触发异常报错,引发资产净值曲线的灾难性失真。本讲系统讲解基于标准交易日历的停牌断点对齐算法、价格前向填充(Forward Fill)规范与 is_trading 状态标记工程。
💡 核心导读
- 停牌数据缺失在回测中的致命危害:
- 净值断崖失真:若组合持有某重仓股,该股停牌一个月,回测引擎若缺失数据将无法评估持仓市值,导致账户净值虚假暴跌,复牌后又虚假暴涨;
- 指标序列截断:滑动窗口函数(如
rolling(20))若遇到日期跳空,会把相隔数月的两根 K 线当成连续交易日计算均线,彻底破坏技术指标的数理意义。
- 标准停牌数据修复规范(Daily Fixing 规则):
- 日历对齐(Calendar Reindex):以大盘指数的标准交易日历为轴,全量补齐个股缺失的日期;
- 价格前向填充(Forward Fill):将停牌日的高、开、低、收(OHLC)四个价格统一设置为停牌前最后一个有效交易日的收盘价(
last_close); - 成交量与状态标识:停牌日成交量显式设为
volume = 0,新增布尔字段is_trading = False(正常交易日为True); - 预热前收价(
pre_close):自动计算上一交易日有效收盘价,方便后续秒级计算当日收益率。
- 双集合同步治理原则:
- 停牌修复必须在不复权集合(
daily)与后复权集合(daily_hfq)中同时执行,确保回测与信号计算两端基准一致。
- 停牌修复必须在不复权集合(
┌─────────────────────────────────────────────────────────────┐
│ 行情数据停牌断点清洗与修复流程 │
└──────────────────────────────┬──────────────────────────────┘
│
┌─────────────────────────────┼─────────────────────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 1. 交易日历对齐 │ │ 2. 价格前向填充 │ │ 3. 状态与成交置零 │
├──────────────────┤ ├──────────────────┤ ├──────────────────┤
│ • 以指数日历为轴 │ │ • OHLC 统一设为 │ │ • volume = 0 │
│ • 扫描个股缺失日 │ │ 停牌前末日收盘 │ │ • is_trading=False│
│ • 补齐空缺文档 │ │ • 保持持仓市值平滑│ │ • 锁定不可交易状态│
└──────────────────┘ └──────────────────┘ └──────────────────┘一、停牌断点对量化系统的冲击机制
在真实交易中,股票停牌期间投资者无法买入或卖出,但持仓市值依然存在,并以停牌前收盘价计算资产总值。
t = \text{Shares} \times Close{last}
若未做数据补齐,查询结果为 None,若回测系统处理不当直接赋予 0,将产生不可接受的逻辑回撤。
二、Daily Fixing 修复算法与实现逻辑
标准修复脚本 daily_fixing.py 核心执行四步转换:
- 获取全集交易日:从
daily集合中查询index=True的全量有序日期列表; - 扫描个股缺失记录:比对个股实际记录日期与标准日历集合;
- 构造补齐文档:对每个缺失日,继承前一日收盘价,成交量填 0,
is_trading设为False; - 批量更新入库:使用
bulk_write执行批量 Upsert。
📝 动手练一练
下面我们用 Python 编写一段 标准行情停牌数据清洗与断点修复脚本,演示如何基于标准交易日历自动补齐停牌断点并平滑持仓市值:
import pandas as pd
import numpy as np
def fix_suspension_and_missing_data(stock_df, calendar_dates):
"""
行情数据修复管线 (Daily Fixing):
1. 基于标准交易日历对齐补齐停牌断点
2. 停牌日高开低收以前一交易日收盘价 (Forward Fill) 填充
3. 成交量置 0, 标记 is_trading = False
4. 填充 pre_close 字段
"""
stock_df = stock_df.copy()
code = stock_df['code'].iloc[0]
# 1. 重新索引至全量交易日历
fixed_df = stock_df.reindex(calendar_dates)
fixed_df['code'] = code
# 2. 识别真实交易日与停牌日
fixed_df['is_trading'] = ~fixed_df['close'].isna()
# 3. 前向填充收盘价 (停牌期间保持停牌前持仓价值不变)
fixed_df['close'] = fixed_df['close'].ffill()
fixed_df['open'] = fixed_df['open'].fillna(fixed_df['close'])
fixed_df['high'] = fixed_df['high'].fillna(fixed_df['close'])
fixed_df['low'] = fixed_df['low'].fillna(fixed_df['close'])
fixed_df['volume'] = fixed_df['volume'].fillna(0.0)
# 4. 填充上一日有效收盘价 pre_close
fixed_df['pre_close'] = fixed_df['close'].shift(1)
return fixed_df
def test_fixing_run():
# 构造全市场标准 5 天交易日历 (周一至周五)
calendar_dates = pd.date_range("2023-06-01", periods=5, freq="B")
# 模拟某股票在第 3、4 天停牌 (原始数据中直接缺失 6月5日与6月6日)
raw_dates = pd.to_datetime(["2023-06-01", "2023-06-02", "2023-06-07"])
raw_df = pd.DataFrame({
'code': '600000',
'open': [10.0, 10.2, 10.8],
'high': [10.5, 10.6, 11.0],
'low': [9.8, 10.1, 10.5],
'close': [10.2, 10.5, 10.9],
'volume': [10000, 15000, 12000]
}, index=raw_dates)
fixed_res = fix_suspension_and_missing_data(raw_df, calendar_dates)
print("================ 行情数据停牌断点清洗与修复 ================")
print(fixed_res[['code', 'open', 'close', 'volume', 'is_trading', 'pre_close']])
print("----------------------------------------------------------")
suspended_count = (~fixed_res['is_trading']).sum()
print(f"成功识别并补齐停牌天数: {suspended_count} 天 (成交量置 0, 价格平滑 ffill)")
print("==========================================================")
if __name__ == "__main__":
test_fixing_run()运行结果输出:
================ 行情数据停牌断点清洗与修复 ================
code open close volume is_trading pre_close
2023-06-01 600000 10.0 10.2 10000.0 True NaN
2023-06-02 600000 10.2 10.5 15000.0 True 10.2
2023-06-05 600000 10.5 10.5 0.0 False 10.5
2023-06-06 600000 10.5 10.5 0.0 False 10.5
2023-06-07 600000 10.8 10.9 12000.0 True 10.5
----------------------------------------------------------
成功识别并补齐停牌天数: 2 天 (成交量置 0, 价格平滑 ffill)
==========================================================本章小结
- 防范停牌净值失真:停牌数据缺失是导致回测市值断裂的核心诱因,必须以全量交易日历为标尺进行前向填充。
- 规范字段标准:停牌日价格继承前收盘、成交量设为 0、
is_trading明确置为False。 - 确保双端一致性:对
daily与daily_hfq集合统一执行清洗,为后续选股与撮合回测奠定无瑕数据基础。
📋 行动清单 (Action Checklist)
- 运行本讲停牌修复代码,观察 6 月 5 日与 6 月 6 日被自动补齐并标记为
is_trading=False; - 在本地 MongoDB 中验证修复逻辑,确保清洗后无断点跳空;
- 预习下一讲,学习如何抓取东方财富财务报表数据并实现定时增量更新。
— 小象教研组
配套学习资源与课件
🎁 免费学习资源
领取《小象 11GB VIP 课件资料包与大厂真题手册》
包含全套实战 Jupyter 源码、清洗后数据集、大厂高频面试真题与专属学员答疑交流群。
- ✔完整 Python / 数据分析 Jupyter 实战源码
- ✔大厂真实业务数据集与练习题
- ✔微信扫码添加课程顾问,免费获取网盘下载链接
微信扫码添加顾问