第 03 课:数学与统计基础

量化的本质是用数学语言描述市场。如果你的数学假设错了,模型越精确,亏得越快。


LTCM:诺贝尔奖得主的致命假设

1998 年,长期资本管理公司(LTCM)拥有两位诺贝尔经济学奖得主、华尔街最顶尖的数学家、以及 1250 亿美元的资产。

他们的模型精妙绝伦,基于一个核心假设:市场收益服从正态分布

按正态分布计算,他们的策略一天亏损超过 1% 的概率是 10 万分之一。一年 252 个交易日,理论上要 400 年才会遇到一次。

然后俄罗斯债务违约了。

1998 年 8 月 21 日一天,LTCM 亏损 5.5 亿美元。接下来的一个月,他们亏损了 46 亿美元——几乎全部资本。按正态分布,这种事件发生的概率是 10 的负 27 次方,大约是宇宙诞生以来每秒发生一次都不可能遇到。

但它发生了。

问题出在哪里?

  1. 市场不是正态分布:真实市场是"厚尾分布",极端事件的频率远超正态分布预测
  2. 相关性会突变:正常时期资产相关性低,危机时所有资产相关性飙升到 1
  3. 波动率会聚集:大跌之后往往还是大跌,不是独立的"抛硬币"

LTCM 的教训:不是模型不够精确,是数学假设从根本上错了。

这一课的目标:让你理解金融数据的真实特性,避免用"抛硬币"的数学去分析市场。


3.1 时间序列基础

序列 vs IID 假设

传统统计学假设数据是 IID (Independent and Identically Distributed):独立同分布。

  • 独立:今天的数据和昨天无关
  • 同分布:每天的数据来自同一个分布

金融数据几乎从不满足 IID 假设

import numpy as np

# IID 数据:抛硬币
coin_flips = np.random.choice([0, 1], size=100)  # 每次独立,概率恒定

# 金融数据:今天的价格依赖昨天
prices = [100]
for _ in range(99):
    # 今天的价格 = 昨天的价格 + 随机变动
    prices.append(prices[-1] * (1 + np.random.normal(0, 0.02)))

为什么这很重要?

  • 如果你用 IID 假设建模,会低估连续亏损的概率
  • 真实市场有"惯性":涨了容易继续涨,跌了容易继续跌

滞后 (Lag) 与自相关

自相关 (Autocorrelation):当前值与过去值的相关性。

纸上计算示例

假设连续 5 天的收益率是:+2%, -1%, +3%, +2%, -2%

今天 (t)昨天 (t-1)
-1%+2%
+3%-1%
+2%+3%
-2%+2%

观察规律:

  • 昨天涨,今天有时涨有时跌 → 自相关接近 0(随机)
  • 如果昨天涨今天大概率涨 → 自相关为正(动量)
  • 如果昨天涨今天大概率跌 → 自相关为负(均值回归)

SPY(标普 500 ETF)的日收益自相关通常接近 0(例如 2010-2020 年约为 0.02)——几乎为 0,说明美股日收益接近随机游走,短期难以预测。具体数值因样本期间而异。

解读

  • 自相关接近 0 → 过去对未来预测价值低(弱式有效市场)
  • 自相关显著为正 → 动量效应(趋势跟随可能有效)
  • 自相关显著为负 → 均值回归效应
💻 代码实现(工程师参考)
import pandas as pd

def calculate_autocorrelation(series, lag=1):
    """计算滞后 lag 期的自相关系数"""
    return series.autocorr(lag=lag)

# 示例:SPY (S&P 500 ETF) 日收益率的自相关
returns = prices_series.pct_change().dropna()

print(f"滞后1期自相关: {calculate_autocorrelation(returns, 1):.3f}")
print(f"滞后5期自相关: {calculate_autocorrelation(returns, 5):.3f}")

平稳性检验

平稳性:统计特性(均值、方差)不随时间变化。

from statsmodels.tsa.stattools import adfuller

def check_stationarity(series, name="Series"):
    """ADF 检验:判断序列是否平稳"""
    result = adfuller(series.dropna())
    print(f"{name}:")
    print(f"  ADF 统计量: {result[0]:.4f}")
    print(f"  p-value: {result[1]:.4f}")
    print(f"  结论: {'平稳 ✓' if result[1] < 0.05 else '非平稳 ✗'}")

# 价格序列通常非平稳
check_stationarity(prices_series, "价格序列")

# 收益率序列通常平稳
check_stationarity(returns_series, "收益率序列")

为什么要检验平稳性?

  • 大多数统计模型假设输入是平稳的
  • 对非平稳序列建模会产生"伪回归"
  • 解决方案:用收益率(差分)代替价格

3.2 收益的数学定义

简单收益 vs 对数收益

📝 纸上计算

假设 AAPL 从 $100 涨到 $110:

简单收益 = (110 - 100) / 100 = 10%
对数收益 = ln(110/100) = ln(1.1)  9.53%

为什么量化常用对数收益? 看下面的例子:

可加性问题(用计算器验证):

Day 1Day 2总收益
价格$100 → $110$110 → $100$100 → $100
简单收益+10%-9.09%0%
直接相加10% - 9.09% = 0.91% ❌
对数收益+9.53%-9.53%0%
直接相加9.53% - 9.53% = 0% ✅

关键洞察:涨 10% 再跌回来,简单收益不等于 0(因为基数变了),但对数收益等于 0。

结论:对数收益可以直接相加,简单收益必须连乘。当你需要计算 100 天的累计收益时,对数收益只需 100 次加法,简单收益需要 100 次乘法。

特性简单收益对数收益
可加性✗ 多期收益不能直接相加✓ 多期收益可以直接相加
对称性✗ 涨10%再跌10%≠0✓ 更接近对称
正态假设较难满足更接近正态

累计收益计算

📝 纸上计算

连续 5 天的日收益率:+1%, -2%, +3%, +1%, -1%

简单收益累计(连乘):

(1+0.01) × (1-0.02) × (1+0.03) × (1+0.01) × (1-0.01) - 1
= 1.01 × 0.98 × 1.03 × 1.01 × 0.99 - 1
= 1.0194 - 1  1.94%

对数收益累计(直接相加):

0.01 + (-0.02) + 0.03 + 0.01 + (-0.01) = 2%

两种方法结果接近,但对数收益计算更简单。

年化收益率

📝 纸上计算

假设 60 个交易日赚了 5%,年化是多少?

年化收益 = (1 + 5%)^(252/60) - 1
        = 1.05^4.2 - 1
        = 1.227 - 1
         22.7%

为什么是 252? 美股一年约 252 个交易日(365 天 - 周末 - 节假日)。

常见错误

  • ❌ 直接把月收益 × 12 当年化(忽略复利)
  • ❌ 用日历天数而非交易日(应该用 252 不是 365)
  • ❌ 忽略手续费后再年化
💻 代码实现(工程师参考)
def cumulative_return(returns, method='simple'):
    """计算累计收益"""
    if method == 'simple':
        return (1 + returns).prod() - 1  # 连乘
    else:
        return returns.sum()  # 直接相加

def annualize_return(total_return, days, trading_days_per_year=252):
    """年化收益率"""
    years = days / trading_days_per_year
    return (1 + total_return) ** (1 / years) - 1

# 示例:60 天赚了 5%
ann_return = annualize_return(0.05, 60)
print(f"年化收益率: {ann_return:.2%}")  #  23.5%

3.3 风险的数学定义

方差与标准差

📝 纸上计算

假设 5 天的日收益率:+1%, -2%, +3%, 0%, -1%

Step 1:计算均值

均值 = (1 - 2 + 3 + 0 - 1) / 5 = 0.2%

Step 2:计算方差(每个值与均值的差的平方的平均)

方差 = [(1-0.2)² + (-2-0.2)² + (3-0.2)² + (0-0.2)² + (-1-0.2)²] / 5
     = [0.64 + 4.84 + 7.84 + 0.04 + 1.44] / 5
     = 14.8 / 5 = 2.96 (%²)

Step 3:计算标准差(波动率)

日波动率 = √2.96  1.72%

Step 4:年化

年化波动率 = 日波动率 × √252  1.72% × 15.87  27.3%

波动率的直觉含义

年化波动率典型资产一年可能的波动范围(68%概率)
15%大盘股(SPY)-15% 到 +15%
30%科技股(TSLA)-30% 到 +30%
80%加密货币(BTC)-80% 到 +80%

记住这个公式:年化波动率 = 日波动率 × √252 ≈ 日波动率 × 16

💻 代码实现(工程师参考)
def calculate_volatility(returns, annualize=True, trading_days=252):
    """计算波动率(标准差)"""
    daily_vol = returns.std()
    if annualize:
        return daily_vol * np.sqrt(trading_days)
    return daily_vol

# 示例
daily_returns = pd.Series([0.01, -0.02, 0.03, 0, -0.01])
annual_vol = calculate_volatility(daily_returns)
print(f"年化波动率: {annual_vol:.2%}")

协方差与相关性

直觉理解

相关系数衡量两个资产"是否同涨同跌":

相关系数含义例子
+1完全同步:A 涨 B 必涨同行业股票(AAPL vs MSFT)
0无关:A 涨跌与 B 无关黄金 vs 科技股
-1完全相反:A 涨 B 必跌股票 vs VIX(恐慌指数)

实际市场中的相关性(参考值):

资产对正常时期相关性危机时期相关性
AAPL vs MSFT+0.7+0.9
SPY vs TLT (债券)-0.3-0.5 或 +0.8
SPY vs GLD (黄金)+0.1-0.2

危机时期的"相关性飙升":正常时期不相关的资产,危机时可能突然相关性飙到 0.9。这就是 LTCM 栽跟头的原因——他们假设相关性稳定。

多智能体视角:Portfolio Agent 的核心工作就是寻找低相关资产构建组合,但 Risk Agent 必须考虑"危机时相关性飙升"的风险。

💻 代码实现(工程师参考)
def analyze_correlation(returns_a, returns_b):
    """分析两个资产的相关性"""
    corr = returns_a.corr(returns_b)
    print(f"相关系数: {corr:.3f}")

    if corr > 0.7:
        print("→ 高度正相关:涨跌同步,分散效果差")
    elif corr < -0.3:
        print("→ 负相关:天然对冲,适合组合")
    else:
        print("→ 低相关:有分散风险的价值")

分布假设的危险性

正态分布假设会害死你。 这是 LTCM 事件的核心教训。

📝 纸上计算

假设 SPY 年化波动率 20%,日波动率约 1.26%(= 20% / √252)。

在正态分布下:

  • 日跌幅超过 1σ (1.26%) 的概率 = 16%(正常)
  • 日跌幅超过 2σ (2.52%) 的概率 = 2.3%(每月 0.5 次)
  • 日跌幅超过 3σ (3.78%) 的概率 = 0.13%(每 3 年 1 次)
  • 日跌幅超过 4σ (5.04%) 的概率 = 0.003%(每 125 年 1 次)

但实际发生了什么?

日期事件SPY 单日跌幅按正态分布的"几σ事件"理论上多少年一遇
2020-03-16COVID崩盘-12.0%9.5σ10^20 年
2008-10-15金融危机-9.0%7.1σ10^12 年
2011-08-08美国降级-6.7%5.3σ1500万年
2018-02-05波动率崩盘-4.1%3.3σ4年

结论:正态分布说"10^20 年一遇"的事件,实际上每隔几年就发生一次。

这就是"厚尾分布"的威力——极端事件发生的频率远超正态分布预测。如果你的风控模型假设正态分布,你必定会在某个"黑天鹅"事件中爆仓。


3.4 金融时间序列的特殊性

厚尾分布 (Fat Tails)

两个关键指标

  1. 偏度 (Skewness):分布是否对称

    • 偏度 = 0 → 对称(涨跌幅度差不多)
    • 偏度 < 0 → 左偏(暴跌比暴涨多)
    • 股票市场偏度通常是 -0.5 到 -1,说明暴跌风险大于暴涨机会
  2. 峰度 (Kurtosis):尾部有多"厚"

    • 峰度 = 3 → 正态分布
    • 峰度 > 3 → 厚尾(极端事件比正态分布预测的多)
    • 股票市场峰度通常是 5-10,远超正态分布的 3
指标正态分布SPY 实际含义
偏度0-0.7暴跌更剧烈
峰度38极端事件频繁

厚尾对策略的影响

  • 止损必须考虑跳空风险(隔夜暴跌可能跳过你的止损价)
  • VaR 模型会严重低估风险
  • 需要用 Expected Shortfall (CVaR) 替代 VaR
💻 代码实现(工程师参考)
def analyze_tail_risk(returns):
    """分析尾部风险"""
    skew = returns.skew()  # 偏度
    kurt = returns.kurtosis()  # 峰度(减3后的)

    print(f"偏度: {skew:.3f} {'(负偏,小心暴跌)' if skew < -0.5 else ''}")
    print(f"峰度: {kurt+3:.3f} {'(厚尾!)' if kurt > 0 else ''}")

波动聚集 (Volatility Clustering)

GARCH 效应:大波动之后往往还是大波动,小波动之后往往还是小波动。

直觉理解

回想 2020 年 3 月的 COVID 暴跌:

  • 3月9日:SPY 跌 7.6%
  • 3月12日:SPY 跌 9.5%
  • 3月16日:SPY 跌 12.0%

暴跌不是独立的"抛硬币"——一旦开始暴跌,往往会连续暴跌。这就是波动聚集。

波动率的自相关高达 0.7-0.9,远高于收益率的自相关(约 0)。这意味着:

  • 收益率几乎不可预测(随机游走)
  • 波动率是可预测的(明天的波动率很可能和今天相近)

实战意义

  • 波动率可预测性 > 收益率可预测性
  • 趋势 Agent 应该在低波动期建仓,高波动期减仓
  • Risk Agent 应该根据近期波动率动态调整止损
💻 代码实现(工程师参考)
def detect_volatility_clustering(returns, window=20):
    """检测波动聚集"""
    rolling_vol = returns.rolling(window).std()
    vol_autocorr = rolling_vol.autocorr(lag=1)
    print(f"波动率的滞后1期自相关: {vol_autocorr:.3f}")

非平稳性与结构性断裂 (Regime Shift)

市场会在不同"状态"之间切换,每个状态有不同的统计特性:

Regime特征适合策略
牛市低波动、正收益、低相关动量、买入持有
震荡中波动、收益接近0均值回归
危机高波动、负收益、高相关减仓、对冲

结构性断裂的典型案例(近似值)

注:下表为常见量级示意,具体数值会随口径、窗口与数据源变化。

时间事件波动率变化相关性变化
2008.09雷曼倒闭15% → 80%0.3 → 0.95
2020.03COVID爆发12% → 85%0.4 → 0.90
2022.01美联储加息15% → 30%0.5 → 0.70

Regime Shift 对策略的影响

  • 在旧 Regime 下训练的模型,在新 Regime 下会失效
  • 相关性突变意味着分散投资突然失效
  • 波动率突变意味着止损位置需要重新计算

这就是为什么需要多智能体——不同 Regime 需要不同策略,一个模型搞不定。Meta Agent 的核心任务就是识别当前 Regime,并将任务分发给对应的专家 Agent。

💻 代码实现(工程师参考)
def detect_regime_change(returns, window=60):
    """简单的 Regime 变化检测"""
    rolling_vol = returns.rolling(window).std()
    vol_change = rolling_vol.diff().abs()
    threshold = vol_change.quantile(0.95)
    regime_changes = vol_change > threshold
    print(f"检测到 {regime_changes.sum()} 个潜在的 Regime 变化点")
    return regime_changes

3.5 常见误区

误区一:正态分布足够描述市场

不对。真实市场是厚尾分布,极端事件发生频率远超正态分布预测。LTCM 假设正态分布,结果"百万年一遇"的事件在几周内发生。

误区二:波动率越低越安全

不完全对。低波动可能是暴风雨前的平静。更危险的是,低波动期往往伴随杠杆增加,一旦波动率突然飙升,损失会被放大。

误区三:相关性稳定可预测

危险的假设。正常时期相关性 0.3 的资产,危机时可能飙升到 0.9。分散投资在你最需要它的时候可能失效。

误区四:历史数据能预测未来

只能部分预测。市场存在 Regime Shift(结构性断裂),过去的统计规律可能突然失效。2008 年、2020 年的市场与之前完全不同。


3.6 多智能体视角

不同 Agent 可以使用不同的统计假设:

Agent统计假设适用场景
Trend Agent动量存在(正自相关)趋势市场
Mean Reversion Agent均值回归(负自相关)震荡市场
Risk Agent厚尾分布 + 波动聚集所有场景
Regime Agent非平稳 + 结构断裂状态识别

关键洞察

  • 不要让所有 Agent 用同一套统计假设
  • Risk Agent 必须用最保守的假设(厚尾、极端事件频繁)
  • Meta Agent 的职责是识别当前 Regime,分发给合适的 Agent

本课交付物

完成本课后,你将获得:

  1. 对金融数据特性的正确认知 - 知道为什么"抛硬币"模型在市场中不适用
  2. 收益率计算能力 - 掌握对数收益、年化收益的正确计算方法
  3. 风险度量的直觉 - 理解波动率、相关性、厚尾分布的实际含义
  4. 对统计假设的警惕 - 知道正态分布假设如何导致致命错误

✅ 验收标准

检查项验收标准自测方法
收益率计算能手算对数收益和年化收益给定 $100→$110→$99,计算两日对数收益和累计
波动率计算能手算标准差并年化给定 5 个日收益率,计算年化波动率
厚尾理解能解释为什么正态分布假设危险不看笔记,说出 LTCM 失败的统计原因
Regime 认知能列举 3 种市场状态及对应策略画出 Regime 切换图,标注每种状态的特征

📝 综合练习(用计算器完成):

某日内策略:

  • 10 天收益率:+1%, -0.5%, +2%, -1%, +0.5%, -2%, +1.5%, 0%, -0.5%, +1%
  • 计算:(1) 累计收益 (2) 日波动率 (3) 年化波动率 (4) 这是高波动还是低波动策略?
点击查看答案
  1. 累计收益(简单法)≈ 2.0%
  2. 日波动率 ≈ 1.2%
  3. 年化波动率 = 1.2% × √252 ≈ 19%
  4. 年化波动率 19% 属于中等波动,接近 SPY 的波动水平

本课要点回顾

  • 理解金融数据不满足 IID 假设,存在自相关和非平稳性
  • 掌握对数收益 vs 简单收益的区别,以及年化计算方法
  • 认识正态分布假设的危险性:厚尾、波动聚集、极端事件
  • 理解 Regime Shift 对策略的影响,以及多智能体如何应对

延伸阅读

  • 背景知识:Alpha 与 Beta - 收益分解的数学基础
  • 背景知识:历史著名量化事故 - 忽略厚尾的代价
  • 背景知识:夏普比率的统计陷阱 - 估计误差、多重检验与 Deflated Sharpe

下一课预告

第 04 课:技术指标的真实角色

MACD、RSI、布林带……这些指标到底有没有用?答案是:它们不是"买卖信号",而是特征工程。下一课我们揭开技术指标的真面目。

Cite this chapter
Zhang, Wayland (2026). 第03课:数学与统计基础. In AI Quantitative Trading: From Zero to One. https://waylandz.com/quant-book/第03课:数学与统计基础
@incollection{zhang2026quant_第03课:数学与统计基础,
  author = {Zhang, Wayland},
  title = {第03课:数学与统计基础},
  booktitle = {AI Quantitative Trading: From Zero to One},
  year = {2026},
  url = {https://waylandz.com/quant-book/第03课:数学与统计基础}
}