数据清洗与对齐:处理不同市场交易时间差异、缺失值处理、重采样与频率对齐

做跨市场分析,最头疼的是什么?

不是策略逻辑,不是模型选型。是数据本身。

我刚开始做跨市场套利的时候,天真地以为把A股和港股数据拉下来就能直接跑。结果一跑,全是NaN。为什么?A股中午休盘,港股不休息。美股还有盘前盘后。三个市场的时间轴根本对不上。

这一章,我们就来解决这个核心问题。说白了,就是让不同市场的时钟「同步」起来。

1. 不同市场的「时间鸿沟」

先看看几个典型市场的交易时间差异:

市场 交易时间(北京时间) 特殊说明
A股 09:30-11:30, 13:00-15:00 中午休市1.5小时
港股 09:30-12:00, 13:00-16:00 中午休市1小时
美股 21:30-04:00(夏令时) 无午休,有盘前盘后
期货(夜盘) 21:00-23:00, 09:00-15:00 分日盘和夜盘

你看,光是交易时段就五花八门。更别说节假日了。A股春节休市一周,美股可不过春节。这时候你拿两个市场的数据直接合并,结果就是一堆空洞。

核心原则:跨市场分析必须基于「对齐后的时间戳」,而不是原始交易时间。

2. 缺失值处理:别让NaN毁了你的模型

数据对齐后,缺失值就冒出来了。我见过有人直接dropna(),把一大半数据扔了。这太粗暴了。

我个人习惯分三步走:

  1. 先判断缺失原因——是休市导致的?还是数据源本身丢了?
  2. 再选择填充策略——前向填充、插值、还是用其他市场数据辅助填充?
  3. 最后做标记——填充过的数据最好加个flag,方便后续回测时剔除。

举个例子,A股中午休市产生的缺失,用前向填充(ffill)最合理。因为价格在休市期间没变。

import pandas as pd

# 假设df是A股分钟数据,中午11:30-13:00缺失
df['close'].fillna(method='ffill', inplace=True)
# 这样就把中午的价格延续到下午开盘前

但如果是美股和A股之间的跨市场缺失呢?比如A股收盘后,美股还在交易。这时候用ffill就不对了。我建议用「最近可用数据」对齐。

小技巧:对于高频策略,缺失值超过连续3个时间点,我建议直接标记为「无效区间」,而不是强行填充。强行填充会引入未来信息,回测结果会虚高。

3. 重采样:把不同频率的数据「拧」到一起

不同市场的数据频率往往不一样。A股可能是1分钟线,美股可能是5分钟线,期货可能是Tick级数据。怎么对齐?

重采样就是干这个的。

我常用的重采样规则:

  • 低频转高频:用前向填充或插值。比如日线转小时线,把当日数据复制到每个小时。
  • 高频转低频:用聚合函数。比如分钟线转小时线,取收盘价、最高价、最低价、成交量总和。
  • 跨市场对齐:统一到一个「基准时间轴」。我一般用UTC时间,避免时区转换的麻烦。
# 将A股分钟数据重采样为5分钟线
df_5min = df.resample('5T').agg({
    'open': 'first',
    'high': 'max',
    'low': 'min',
    'close': 'last',
    'volume': 'sum'
})

# 注意:resample会包含非交易时段,需要过滤掉
df_5min = df_5min.between_time('09:30', '15:00')

我曾经踩过的坑:重采样时没过滤非交易时段,结果把收盘后的空数据也聚合进去了,导致凌晨出现「假价格」。后来我加了一步:先过滤交易时段,再重采样。顺序很重要。

4. 频率对齐实战:多市场时间轴统一

好了,我们来看一个完整的例子。假设我们要分析A股和港股的联动性,数据都是1分钟线,但交易时间不同。

我的做法是:

  1. 把两个市场的数据都转成UTC时间戳
  2. 创建一个「联合时间轴」,包含两个市场所有交易时段的并集
  3. 对每个市场的数据,按联合时间轴重采样
  4. 缺失值用前向填充(因为非交易时段价格不变)
import pandas as pd

# 假设a_df和hk_df已经加载,时间列名为'timestamp'
# 步骤1:创建联合时间轴
all_times = pd.concat([
    a_df['timestamp'],
    hk_df['timestamp']
]).drop_duplicates().sort_values()

# 步骤2:重采样到联合时间轴
a_aligned = a_df.set_index('timestamp').reindex(all_times).fillna(method='ffill')
hk_aligned = hk_df.set_index('timestamp').reindex(all_times).fillna(method='ffill')

# 步骤3:合并
merged = pd.concat({
    'A': a_aligned['close'],
    'HK': hk_aligned['close']
}, axis=1)

# 步骤4:去掉两个市场都休市的时间段
merged.dropna(how='all', inplace=True)

嗯,这里要注意:reindex 加上 ffill 的组合,是我最常用的对齐方式。它不会引入未来数据,逻辑上也说得通——非交易时段的价格就是上一笔成交价。

5. 知识体系总览

下面这张图,是我自己整理的数据清洗与对齐流程。每次做新项目,我都会先过一遍这个流程,避免遗漏。

跨市场数据清洗与对齐流程 原始多市场数据 时间标准化(UTC) 创建联合时间轴(交易时段并集) 重采样到统一频率 缺失值处理(ffill/标记) 关键注意事项 • 先过滤交易时段再重采样 • 连续缺失>3个点标记无效 • 填充数据加flag标记 • 节假日单独处理 • 盘前盘后数据谨慎使用 • 回测时剔除填充区间 • 不同市场用不同填充策略 • 最终数据做完整性检查

6. 避坑指南:我踩过的那些坑

做数据清洗这么多年,有些坑真的是刻骨铭心。

  • 坑一:时区没统一。 有一次我把A股和美股数据直接合并,结果发现相关性算出来是负的。查了半天,原来是A股用的北京时间,美股用的美东时间,差了12个小时。从那以后,我所有数据一律转UTC。
  • 坑二:节假日没处理。 春节、感恩节、圣诞节...每个市场都有自己的假期。我写过一个函数,专门拉取各市场的交易日历,然后做差集。这样就不会把非共同交易日的数据强行对齐了。
  • 坑三:重采样时用了错误的聚合函数。 比如成交量用mean(),这不对。成交量应该用sum()。价格用last(),而不是mean()。这些细节决定了数据的准确性。

我的经验法则:数据清洗花的时间,至少占整个项目的60%。别嫌麻烦。数据干净了,后面的分析就是水到渠成的事。

好了,这一章的内容就到这里。数据清洗与对齐,说白了就是让不同市场的「时钟」同步。方法不复杂,但细节决定成败。你想想看,如果数据本身都是错的,再牛的策略也是白搭。

专注资料整理