Skip to content

7.5 时间序列处理

课前导读

本节目标

你将学会:把 A 股行情看成按时间排队的记录,理解日期索引、排序、交易日、重采样和数据对齐。

适合基础:已经会创建 DataFrame、读取保存 CSV,知道时间序列是第 6 章量化数据里的核心概念。

预计用时:约 36 分钟。

本节边界:只讲 pandas 时间序列的基础处理,不展开完整回测系统、因子检验或实盘调度。


知识正文

1. 把时间序列想成“按日期排队的体检记录”

一只股票每天都有行情记录。

如果把这些记录随便打乱,就像把体检报告按随机顺序装订。

你看到 1 月 8 日在前,1 月 5 日在后,就很难判断变化过程。

时间序列的关键不是“有很多数字”。

关键是这些数字有先后顺序。

在 A 股量化研究中,顺序尤其重要。

今天的收盘价只能和之前已经发生的价格比较。

今天的公告只能在披露后影响研究判断。

如果你让程序不小心“看到未来”,结果会看起来很漂亮,却无法在真实交易中复现。

所以 pandas 处理时间序列的第一课,就是把日期处理清楚。

2. 日期列和日期索引有什么区别

DataFrame 里可以有一列叫“日期”。

这时日期只是普通字段。

你也可以把日期设为索引。

这时日期就变成每一行的时间标签。

类比一下。

普通日期列像表格里写着“体检日期”的一列。

日期索引像档案柜抽屉外面的日期标签。

当日期成为索引后,pandas 可以更自然地按时间切片、排序、重采样。

下面先创建一张顺序有点乱的小行情表。

python
import pandas as pd

data = {
    "日期": ["2026-01-07", "2026-01-05", "2026-01-08", "2026-01-06"],
    "股票代码": ["600000", "600000", "600000", "600000"],
    "开盘价": [10.10, 10.00, 10.45, 10.20],
    "最高价": [10.50, 10.25, 10.60, 10.28],
    "最低价": [10.05, 9.95, 10.25, 10.00],
    "收盘价": [10.45, 10.20, 10.30, 10.10],
    "成交量": [1500000, 1200000, 1100000, 980000],
}

df = pd.DataFrame(data)

print(df)

这张表的数据是手写的。

它故意把 2026-01-07 放在第一行。

如果直接计算收益率,就会拿错误的上一行做比较。

3. 转成日期类型,再设为索引

日期如果只是字符串,pandas 不一定知道它是时间。

所以第一步是转换日期类型。

第二步是把日期设为索引。

第三步是按日期排序。

python
df["日期"] = pd.to_datetime(df["日期"])

df = df.set_index("日期")

df = df.sort_index()

print(df)

pd.to_datetime() 的作用是把文本日期转换成真正的日期类型。

set_index("日期") 把日期列放到索引位置。

sort_index() 按索引从早到晚排序。

这三步是 A 股日线数据处理的基本动作。

关键心得

只要涉及“上一天”“过去 N 天”“从左往右验证”,就必须先确认日期已经正确排序。

4. 交易日不是自然日

A 股不是每天都交易。

周末不开市。

法定节假日不开市。

有些股票还可能因为重大事项临时停牌。

所以你不能简单地把“下一天”理解为日历上的明天。

在量化数据里,“下一行”通常代表下一个已有记录的交易日。

比如 1 月 9 日是周五,下一条记录可能是 1 月 12 日周一。

如果中间遇到春节假期,间隔会更长。

这会影响收益率、滚动计算和数据对齐。

新手阶段先记住:不要强行补出每一个自然日,然后假装每天都交易。

5. 计算日收益率前先检查排序

排序完成后,再计算日收益率才更合理。

python
df["日收益率"] = df["收盘价"].pct_change()

print(df[["股票代码", "收盘价", "日收益率"]])

pct_change() 使用上一行作为对比。

如果日期没排序,上一行就不是前一个交易日。

这类错误很隐蔽。

程序不会主动提醒你“顺序错了”。

它会认真地把错误顺序算完。

这也是量化开发需要严谨的原因。

6. 用日期切片观察一段时间

把日期设为索引后,可以按时间范围取数据。

python
window = df.loc["2026-01-06":"2026-01-08"]

print(window[["收盘价", "成交量"]])

loc 可以按索引标签选择。

这里的意思是:取 2026-01-06 到 2026-01-08 之间的记录。

如果其中某一天不是交易日,结果里不会凭空出现那一天。

这和 A 股研究很贴近。

我们研究的是实际可交易记录,而不是日历上每一天。

7. 重采样:把日线装进周线篮子

重采样可以理解为“换一个时间篮子重新汇总”。

日线是一天天记录。

周线是把一周内的多个交易日合成一条记录。

例如开盘价用这一周第一条记录。

最高价用这一周最高值。

最低价用这一周最低值。

收盘价用这一周最后一条记录。

成交量用这一周合计。

python
weekly = df.resample("W-FRI").agg(
    {
        "开盘价": "first",
        "最高价": "max",
        "最低价": "min",
        "收盘价": "last",
        "成交量": "sum",
    }
)

print(weekly)

W-FRI 表示以周五作为一周结束的标签。

它不代表每周一定有周五交易。

如果周五是节假日,这一周的 last 会使用这一周内最后一个已有交易日。

如果整周没有交易记录,就可能出现空值。

常见误区

重采样不是随便平均价格。A 股 K 线汇总通常要分别处理开、高、低、收和成交量。

8. 停牌和节假日会怎样影响重采样

如果一只股票某几天停牌,日线表可能没有这些日期的交易记录。

也可能保留日期但价格为空或成交量为 0。

不同数据源处理方式不一样。

如果你不先理解数据来源,就直接重采样,周线结果可能被误读。

例如一周只有两天交易。

成交量合计自然会比五天交易的周少。

这不一定代表市场兴趣突然下降。

它可能只是交易日减少。

又比如停牌复牌后出现跳空。

这个价格变化不是普通连续交易造成的。

如果后续要研究收益,需要在记录中保留停牌和复牌信息。

本节不展开停牌规则细节,只强调:时间序列不是机械日期表,它承载了交易制度。

9. 数据对齐:让不同表站在同一天说话

量化研究常常不止一张表。

一张是价格表。

一张是公告表。

一张可能是财务披露表。

数据对齐就是让这些表按同一个时间标准合在一起。

例如我们做一个极简公告示例。

python
events = pd.DataFrame(
    {
        "日期": ["2026-01-06", "2026-01-08"],
        "事件": ["业绩预告披露", "临时停牌提示"],
    }
)

events["日期"] = pd.to_datetime(events["日期"])
events = events.set_index("日期")

aligned = df.join(events, how="left")

print(aligned[["收盘价", "事件"]])

join(..., how="left") 的意思是以价格表的日期为主,把同日期的事件贴上去。

没有事件的日期就留空。

这只是最小示例。

真实研究还要关心事件是什么时候披露、投资者当时是否可见。

第 6 章提过“可得性”,在这里仍然重要。

10. 不能把未来信息提前对齐

假设公司在 1 月 8 日晚间披露业绩预告。

那这条信息通常不能用于 1 月 8 日盘中的决策。

如果你把它简单贴到 1 月 8 日整天,并用来解释当天收盘前的操作,就可能“偷看未来”。

时间对齐不是只看日期相同。

还要看信息在当时是否已经可见。

新手阶段可以先用一个保守原则。

如果不确定公告是在盘前、盘中还是盘后可见,就不要把它用于当天买卖判断。

宁可把它放到下一交易日观察。

这个原则虽然简单,但能帮助你远离很多纸面研究陷阱。

11. 时间序列处理流程

mermaid
graph TD
    A["拿到行情 DataFrame"] --> B["确认日期字段"]
    B --> C["转换为日期类型"]
    C --> D["设为日期索引"]
    D --> E["按日期排序"]
    E --> F["检查交易日缺口"]
    F --> G["计算收益率或重采样"]
    G --> H["与事件或财务数据对齐"]
    H --> I["记录可得性假设"]

这条流程不复杂。

但每一步都关系到研究是否可信。

A 股有节假日、停牌、涨跌停、公告披露时点。

这些制度因素会进入数据表。

所以时间序列处理不是纯技术小技巧,而是投资事实的整理方式。


交互实验室

练习 1:观察排序前后的差异

运行本节最开始的乱序 DataFrame。

先不要 sort_index(),直接计算一次 pct_change()

再执行 sort_index() 后重新计算。

请比较两次结果。

你会看到同样的收盘价,只要顺序不同,日收益率就会不同。

练习 2:找出一段时间窗口

请用 loc 取出 2026-01-06 到 2026-01-08 的数据。

然后只显示收盘价和成交量。

思考:如果 2026-01-07 是停牌日而数据中没有这一行,你的窗口结果会怎样变化?

练习 3:手动新增一个停牌样例

把数据改成少一行 2026-01-07。

再次执行重采样。

观察周线的开盘价、最高价、最低价、收盘价和成交量。

请写一句话:交易日减少会怎样影响周成交量?

练习 4:给公告做保守对齐

假设 2026-01-08 晚间披露公告。

请在笔记里写下你的处理规则。

可以采用:“如果公告披露时点不清楚,就从下一交易日开始观察影响”。

这不是最精细的方法,但适合新手避免提前使用未来信息。


核心复盘

知识清单

  • [ ] 时间序列的核心是顺序,日期错位会让收益率和观察结论失真。
  • [ ] pd.to_datetime()set_index()sort_index() 是处理日期数据的基础三步。
  • [ ] A 股交易日不同于自然日,节假日和停牌会影响数据间隔。
  • [ ] resample() 可以把日线汇总成周线,但开高低收和成交量要分别处理。
  • [ ] 数据对齐不仅是日期相同,还要考虑信息当时是否可见。
  • [ ] 不确定披露时点时,保守地从下一交易日观察更安全。

金句总结

时间序列不是一串数字,而是一条按交易制度发生的投资时间线。

风险提醒

排序错误、自然日与交易日混淆、停牌缺口和未来信息提前对齐,都会让量化研究结果看起来合理却无法真实复现。

本文档仅供学习交流用途,不构成任何投资建议。股市有风险,入市需谨慎。