金融数据基础:股票、期货、外汇等数据类型,OHLCV、复权因子、时间序列特征

在搭建金融回测系统时,数据层是整个系统的地基。如果数据不准确、口径不一致或时间序列断裂,后续的策略逻辑、信号计算和绩效分析都将失去可靠性。本章将系统梳理股票、期货、外汇等主流金融品种的数据类型差异,深入解析OHLCV(开盘、最高、最低、收盘、成交量)的核心字段含义,阐明复权因子的必要性与计算方法,并归纳金融时间序列的典型特征。理解这些基础概念,是设计数据存储结构、清洗流程和回测引擎的前提。

金融数据基础架构与时间序列特征 品种数据源 • 股票:日线/分钟线/盘口 • 期货:主力连续/指数合约 • 外汇:Tick/1min/5min • 加密:永续/现货/资金费率 OHLCV 核心字段 • Open 开盘价(撮合首笔) • High/Low 极值(含影线) • Close 收盘价(结算基准) • Volume 成交量/持仓量 复权因子 • 前复权:以最新价为基准 • 后复权:以首日为基准 • 除权除息调整 • 因子 = 除权前价/除权后价 金融时间序列四大特征 ① 非平稳性:价格均值/方差随时间变化 ② 自相关性:收益率序列存在短期记忆 ③ 波动率聚集:大波动后跟大波动 ④ 尖峰厚尾:极端值出现概率高于正态分布 ⑤ 长记忆性:部分品种存在长期依赖 ⑥ 日历效应:周内/月内/节假日效应 回测系统数据链路 原始数据 → 清洗对齐 → 复权处理 → 特征工程 → 存储(Parquet/DB) → 回测引擎读取 关键点:时间戳统一、缺失值处理、异常值剔除、复权一致性、时区转换

一、核心原理:不同金融品种的数据本质差异

股票、期货、外汇虽然都表现为价格与成交量的时间序列,但其数据生成机制和业务规则存在显著差异。理解这些差异是设计回测系统数据接口的第一步。

股票数据以交易所撮合结果为准,包含完整的OHLCV信息,且存在分红、送股、配股等公司行为导致的除权除息缺口。股票市场有涨跌停限制(A股主板±10%、科创板/创业板±20%),这会影响价格序列的连续性。此外,股票存在停牌机制,停牌期间无交易数据,回测时需特殊处理。

期货数据的核心难点在于合约换月。每个期货品种在不同月份有不同合约,主力合约会随时间切换。直接拼接不同合约的价格会产生跳空缺口,因此业界通常使用主力连续合约或指数合约。期货还包含持仓量(Open Interest)字段,这是股票数据没有的,反映市场参与深度。期货交易有保证金制度和交割日,临近交割月流动性会显著下降。

外汇数据是典型的场外交易(OTC)市场,没有统一交易所,数据来自做市商报价。外汇市场24小时交易,数据粒度通常为Tick级或分钟级。外汇没有复权概念,但存在隔夜利息(Swap)和点差(Spread)成本,回测时必须计入交易成本。外汇数据的另一个特点是周末休市,但部分经纪商提供周五收盘至周一开盘的跳空缺口。

加密货币数据作为新兴品种,7×24小时交易,无涨跌停限制,波动率极高。永续合约的资金费率(Funding Rate)是重要数据字段,影响持仓成本。

对比维度 股票 期货 外汇 加密货币
交易场所 中心化交易所 期货交易所 OTC/银行间 数字交易所
交易时间 4-6小时/日 日盘+夜盘 24h×5天 24h×7天
复权需求 必须 换月处理 无 无(但需资金费率)
特有字段 涨跌停、停牌 持仓量、交割日 点差、隔夜利息 资金费率、未平仓量
数据粒度 日/分钟/盘口 日/分钟/Tick Tick/分钟 Tick/分钟

二、OHLCV字段深度解析与数据质量陷阱

OHLCV是回测系统最基础的数据结构,但每个字段都有其特定的生成规则和潜在陷阱。

Open(开盘价)在股票市场中指集合竞价产生的第一笔成交价,期货市场则指日盘开盘时的第一笔价格。需要注意,部分数据源将开盘价定义为"当日第一笔成交价",而另一些定义为"开盘时刻的指示价",两者在极端行情下可能不同。外汇市场的开盘价则取决于经纪商定义的交易日起始时间(通常为纽约时间17:00)。

High/Low(最高/最低价)是当日成交的最高和最低价格,包含上下影线。但这里存在一个常见陷阱:部分数据源在计算High/Low时剔除了盘后交易或电子盘数据,导致与交易所官方数据不一致。对于期货夜盘品种,日线High/Low应包含夜盘时段。

Close(收盘价)是回测中最常用的价格,也是计算收益率的基础。股票收盘价通常指最后一笔成交价或收盘集合竞价价格;期货收盘价则指日盘收盘价,但部分品种以结算价(Settlement Price)作为官方收盘价。结算价是当日成交量的加权平均价,与最后一笔成交价可能不同,回测时需明确使用哪种价格。

Volume(成交量)在股票中表示成交股数(手),期货中表示成交手数(双边计算),外汇中则没有统一成交量概念,通常用Tick数或报价次数代替。期货的持仓量(Open Interest)是独立字段,表示未平仓合约总数,其变化反映资金流入流出。

数据质量风险提示:回测系统中最隐蔽的错误往往来自数据源不一致。例如,同一品种的日线数据,不同数据商对"收盘价"的定义可能不同(最后一笔成交 vs 结算价),这会导致回测结果产生系统性偏差。建议在数据入库时记录数据源版本和字段定义,并做交叉验证。

三、复权因子的计算逻辑与实战应用

股票分红送股后,股价会向下跳空,但投资者的实际资产并未减少。如果直接使用原始价格序列计算收益率,会得到错误的负收益。复权因子的作用就是消除这些非交易因素造成的价格缺口。

前复权(Backward Adjustment)以最新交易日为基准,将历史价格按复权因子向下调整。前复权价格 = 原始价格 × 复权因子。复权因子的计算方式为:当日复权因子 = 前日复权因子 ×(除权除息前收盘价 / 除权除息后理论价格)。前复权的优点是当前价格与市场真实价格一致,便于观察近期走势;缺点是历史价格会随新除权事件而不断变化,导致历史数据不稳定。

后复权(Forward Adjustment)以上市首日为基准,将后续价格向上调整。后复权价格 = 原始价格 × 累计复权因子。后复权的优点是历史价格固定不变,适合长期趋势分析和回测;缺点是当前价格与市场真实价格差异较大,不便于直观理解。

在回测系统中,推荐使用后复权数据进行策略计算,因为其历史数据稳定,不会因后续分红事件而改变。但展示图表时,通常使用前复权数据以贴近真实价格。

# 复权因子计算示例(简化版)
def calculate_adjust_factor(dividend, split_ratio, close_before, close_after):
    """
    dividend: 每股分红金额
    split_ratio: 送股比例(如10送5则传0.5)
    close_before: 除权除息日收盘价
    close_after: 除权除息日理论开盘价
    """
    theoretical_price = (close_before - dividend) / (1 + split_ratio)
    adjust_factor = close_before / theoretical_price
    return adjust_factor

# 实际应用中,复权因子由数据商计算并直接提供
# 回测系统只需读取 factor 字段,将原始价格乘以累计因子即可
实战建议:对于期货数据,虽然没有分红复权,但存在换月缺口。处理方式有两种:一是使用复权连续合约(类似股票复权逻辑),二是使用价差调整法(将新合约价格加上或减去换月时的价差)。推荐使用指数合约进行策略开发,用主力合约进行交易执行验证。

四、金融时间序列的核心特征与工程应对

金融时间序列与普通时间序列(如气象数据、传感器数据)有本质区别,这些特征直接影响回测系统的数据预处理和特征工程模块设计。

非平稳性是最核心的特征。价格序列的均值和方差随时间变化,因此不能直接用于统计建模。回测系统中通常将价格转换为收益率序列(对数收益率或简单收益率),收益率序列近似平稳。但需要注意,波动率本身也是时变的,这引出了第二个特征。

波动率聚集(Volatility Clustering)指大波动后往往跟随大波动,小波动后跟随小波动。这一特征在GARCH模型中被量化描述。在回测系统中,波动率聚集意味着风险不是均匀分布的,止损和仓位管理需要动态调整。例如,ATR(平均真实波幅)指标就是基于这一特征设计的。

尖峰厚尾(Fat Tails)指收益率分布比正态分布有更多的极端值。这意味着回测中出现的极端亏损可能不是异常,而是市场的固有属性。回测系统需要引入极值理论(EVT)或压力测试来评估尾部风险。

自相关性与长记忆性在日线级别通常较弱,但在高频数据中显著。部分策略(如动量策略、均值回归策略)正是利用这些短期自相关特征。回测系统需要提供自相关函数(ACF)和偏自相关函数(PACF)的计算工具,帮助策略开发者识别可交易的模式。

日历效应包括周一效应、月末效应、节假日效应等。例如,A股市场在春节前后往往有季节性行情。回测系统应支持按日历维度切分数据,便于验证策略在不同时间段的表现。

时间序列特征 对回测的影响 工程应对方案
非平稳性 价格序列不可直接建模 转换为收益率序列;使用协整关系
波动率聚集 风险时变,固定止损失效 使用ATR动态止损;GARCH族模型
尖峰厚尾 极端值概率被低估 压力测试;极值理论;分位数回归
自相关性 短期可预测性 ACF/PACF分析;动量/反转因子
日历效应 特定时段表现异常 按日历切片;虚拟变量回归

五、实战案例:构建一个多品种数据清洗管道

假设我们需要搭建一个回测系统,同时处理A股股票、螺纹钢期货和EUR/USD外汇的日线数据。以下是具体的数据清洗流程和关键决策点。

背景与约束:数据源为某第三方数据商,提供CSV格式的原始数据。股票数据包含复权因子字段,期货数据为主力连续合约(但换月规则不透明),外汇数据为分钟线需聚合为日线。系统要求数据入库后支持快速查询和回测。

初始现象:直接拼接三类数据后,发现股票收益率序列在分红季出现异常负值;期货价格在换月日出现巨大跳空;外汇日线数据与经纪商提供的官方日线不一致。

分析判断过程:

  1. 股票异常:检查发现数据商提供的"收盘价"为不复权价格,但复权因子字段存在。需要将原始价格乘以累计复权因子得到后复权价格。
  2. 期货跳空:主力连续合约的换月规则为"成交量最大合约",但换月日新旧合约价差未做调整。需要计算换月价差并修正。
  3. 外汇不一致:数据商将交易日定义为UTC 0点,而经纪商使用纽约时间17点。需要统一交易日边界。

实际操作步骤:

# 数据清洗管道核心逻辑
def clean_stock_data(df):
    """股票数据后复权处理"""
    df['adj_close'] = df['close'] * df['cum_factor']
    df['adj_open'] = df['open'] * df['cum_factor']
    df['adj_high'] = df['high'] * df['cum_factor']
    df['adj_low'] = df['low'] * df['cum_factor']
    return df

def clean_futures_data(df):
    """期货换月价差调整"""
    df['contract_change'] = df['contract'].ne(df['contract'].shift())
    df['price_gap'] = df['close'] - df['close'].shift()
    # 换月日的价差视为跳空,需要调整
    df.loc[df['contract_change'], 'adj_close'] = df['close'] - df['price_gap']
    return df

def clean_forex_data(df):
    """外汇交易日边界统一"""
    # 将UTC时间转换为纽约时间,并重新定义交易日
    df['ny_time'] = df['utc_time'] - pd.Timedelta(hours=5)
    df['trade_date'] = df['ny_time'].dt.date
    daily_df = df.groupby('trade_date').agg(
        open=('price', 'first'),
        high=('price', 'max'),
        low=('price', 'min'),
        close=('price', 'last'),
        volume=('volume', 'sum')
    )
    return daily_df

结果对比:清洗后,股票收益率序列在分红季不再出现异常负值;期货价格序列在换月日跳空幅度从平均3.2%降至0.1%以内;外汇日线与经纪商数据对齐,回测结果与实盘表现的相关性从0.82提升至0.95。

风险与代价:后复权处理导致历史价格与真实价格差异较大,在图表展示时需额外转换;期货换月价差调整假设价差恒定,实际中价差会随时间变化;外汇交易日边界统一后,部分跨日持仓的隔夜利息计算需要重新校准。

复盘经验:数据清洗不是一次性工作,而是需要持续监控的工程环节。建议在数据管道中增加质量监控模块,每日检查价格跳空、成交量异常、复权因子变化等指标,并设置告警阈值。

核心要点总结:
  • 不同金融品种的数据生成机制差异巨大,回测系统必须针对品种特性设计数据接口。
  • OHLCV字段的定义在不同数据源间可能存在差异,入库前必须明确字段口径。
  • 股票必须使用复权数据,推荐后复权用于计算,前复权用于展示。
  • 期货需处理换月缺口,指数合约和主力连续合约各有优劣。
  • 金融时间序列的非平稳性、波动率聚集、尖峰厚尾等特征,决定了回测系统需要专门的预处理模块。
  • 数据清洗管道需要持续监控和迭代,建议建立数据质量看板。