OHLCV 数据结构与 pandas 时间序列
:::info 学习目标 你将能解释 OHLCV 每列的生成规则,正确聚合周/月 K 线,并在处理前验证索引排序、重复时间戳、时区与价格合法性。 :::
直觉
金融行情最标准的数据结构是 OHLCV:每个时间点一行,含「开盘、最高、最低、收盘、成交量」。pandas 用 DatetimeIndex 处理这类「按时间排好序」的数据非常顺手——这一节把它的基本操作过一遍。
OHLCV 含义
| 列 | 含义 |
|---|---|
open | 开盘价 |
high | 区间最高价 |
low | 区间最低价 |
close | 收盘价(最常用) |
volume | 成交量 |
OHLCV 不是五个独立观测:必须满足 ,成交量通常非负。同一时间戳出现两行、索引未排序、零价格或高低价颠倒都应在计算收益前报错。日线的“收盘”还依赖交易所和时区;跨市场对齐时应先统一到明确的决策时刻。
内置 spy_daily.csv 就是标准 OHLCV(外加前复权 adj_close),前几行长这样:
/data/spy_daily.csv
pandas 时间序列三板斧
- 解析日期 + 设为索引:
pd.read_csv(..., parse_dates=['date']).set_index('date'); - 按时间切片:
df.loc['2020':'2021']直接按年份取; - 重采样:把高频聚合成低频(如日→周),用
.resample(...)+ 聚合函数。
把日 OHLCV 聚合到周
把一周内若干交易日的「开高低收量」合成一根周 K:
可运行案例:从日 K 合成周 K
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('/data/spy_daily.csv', parse_dates=['date']).set_index('date')
# 按时间切片示例:只取 2020 年
df_2020 = df.loc['2020']
print("2020 年交易日数:", len(df_2020))
print(df_2020.head(3).round(2))
# 日 K → 周 K 的标准聚合规则
weekly = df.resample('W').agg({
'open': 'first', 'high': 'max', 'low': 'min',
'close': 'last', 'volume': 'sum'
}).dropna()
print("\n合成周 K 行数:", len(weekly))
plt.figure(figsize=(9, 3.6))
plt.plot(df_2020.index, df_2020['close'], color="#2563eb", lw=1, label="日收盘")
weekly_2020 = weekly.loc['2020']
plt.plot(weekly_2020.index, weekly_2020['close'], color="crimson",
lw=0, marker='o', ms=3, label="周末收盘")
plt.title("日收盘 vs 周收盘(2020)"); plt.xlabel("日期"); plt.ylabel("价格")
plt.legend(); plt.tight_layout(); plt.show()
小结
- OHLCV 是行情的标准五列;
- pandas:解析日期→设索引→按时间切片→
.resample().agg()聚合; - 周K 聚合规则:开=first、高=max、低=min、收=last、量=sum。
实践与延伸
- 人为加入重复日期和
low>high的错误,写validate_ohlcv(df)让它主动失败。 - 比较周五收盘周线与自然周周线,检查节假日周的标签是否符合预期。
延伸阅读:pandas resample/Grouper 文档;所用交易所的官方交易日历说明。
下一节处理数据里最烦人的部分:缺失、复权、异常值。
章末自测
检查核心概念
1. 关于本章主题,哪项说法更准确?