Skip to content

3.1 Python数据栈

概念详解

为什么Python是量化的首选语言

十年前,量化交易的世界被C++、MATLAB和R分割。Python在金融领域的崛起绝非偶然,它提供了量化工作流所需的三项核心能力:数据处理(NumPy/Pandas)、科学计算(SciPy/Statsmodels)和机器学习(scikit-learn/TensorFlow)的无缝集成。

更关键的是,Python拥有一个庞大的开源社区,几乎每个量化需求——从获取行情数据到执行算法交易——都有现成的库和工具。这使得量化研究者可以专注于alpha的发现,而非基础设施工匠。

名词解释:NumPy

Python科学计算基础库,提供高性能多维数组对象及丰富的数学函数,通过向量化运算加速计算。

名词解释:Pandas

基于NumPy构建的数据分析库,核心数据结构DataFrame和Series,擅长处理时间序列和表格数据。

名词解释:向量化运算 (Vectorization)

使用数组操作替代显式循环,利用底层C实现并行化,大幅提升执行速度。见3.3章详细讨论。

Python量化技术栈全景图

┌─────────────────────────────────────────────────────┐
│                     策略层                           │
│  Zipline / Backtrader / VNPY / 自研回测框架         │
├─────────────────────────────────────────────────────┤
│                     模型层                           │
│  scikit-learn / LightGBM / PyTorch / statsmodels     │
├─────────────────────────────────────────────────────┤
│                     数据层                           │
│  Pandas / NumPy / Dask / PySpark                    │
├─────────────────────────────────────────────────────┤
│                     获取层                           │
│  Tushare / AKShare / yfinance / WindPy / 自定义API   │
├─────────────────────────────────────────────────────┤
│                     执行层                           │
│  QMT/XT API / CTP / 交易所API / 自定义网关           │
└─────────────────────────────────────────────────────┘

核心库深度介绍

NumPy:一切计算的基础

NumPy的ndarray是Python数据科学的基石。对于量化交易来说,理解以下NumPy特性至关重要:

  • 广播 (Broadcasting):不同形状数组间的自动对齐运算
  • 花式索引 (Fancy Indexing):基于条件的快速数据筛选
  • 通用函数 (ufunc):编译级别的逐元素运算
PYTHON9 行 · 388 B
📄此处有展示代码9 行 · 388 B展开 ▼
python
import numpy as np

# 广播:计算所有股票相对于各自均值的偏离
returns = np.random.randn(1000, 500)  # 1000天, 500只股票
stock_means = returns.mean(axis=0)    # shape (500,)
demeaned = returns - stock_means      # (1000, 500) - (500,) -> (1000, 500) 自动广播

# 花式索引:筛选满足条件的行
high_vol_days = returns[np.abs(returns.mean(axis=1)) > 0.02]
点击展开可浏览运行结果
--- demeaned (ndarray) ---
ndarray shape=(1000, 500) dtype=float64 head10=[np.float64(1.1893288339609283), np.float64(0.0728123616173192), np.float64(0.4331171380710701), np.float64(-0.1967714052375393), np.float64(0.8922976167523496), np.float64(1.536297783486719), np.float64(0.11226771247117814), np.float64(-0.7151156343396026), np.float64(1.1772743120651197), np.float64(-0.19461338912431336)]

--- high_vol_days (ndarray) ---
ndarray shape=(664, 500) dtype=float64 head10=[np.float64(1.739583411401137), np.float64(-0.034120952875441646), np.float64(-0.9176010243475826), np.float64(0.766209485300697), np.float64(1.0686862169878393), np.float64(-1.0773722468195601), np.float64(-0.5700690593425428), np.float64(-0.2938560156956932), np.float64(1.8901395528574954), np.float64(-1.3099474237899122)]

--- returns (ndarray) ---
ndarray shape=(1000, 500) dtype=float64 head10=[np.float64(1.2512111309549154), np.float64(0.0794967639423766), np.float64(0.447483693662278), np.float64(-0.16526479832528823), np.float64(0.8893388532708223), np.float64(1.4692127154570833), np.float64(0.11608329609583846), np.float64(-0.6882166397106123), np.float64(1.178022332545264), np.float64(-0.18484998793086407)]

--- stock_means (ndarray) ---
ndarray shape=(500,) dtype=float64 head10=[np.float64(0.06188229699398715), np.float64(0.006684402325057403), np.float64(0.014366555591207893), np.float64(0.031506606912251066), np.float64(-0.0029587634815273875), np.float64(-0.06708506802963586), np.float64(0.0038155836246603204), np.float64(0.026898994628990217), np.float64(0.0007480204801442208), np.float64(0.009763401193449288)]

Pandas:量化的数据处理引擎

Pandas的两大数据结构各有专长:

  • Series:一维标签数组,适合存储单只股票的数据(价格、收益率等)
  • DataFrame:二维表格,适合存储多只股票的面板数据

Pandas在量化中的核心功能包括:

  • 时间序列对齐和重采样
  • 滚动窗口计算(移动平均、滚动标准差等)
  • GroupBy操作(按行业、市值分组统计)
  • 数据合并(merge/join/concat)

SciPy与Statsmodels:统计建模

  • SciPy:优化(scipy.optimize)、插值(scipy.interpolate)、统计分布(scipy.stats)
  • Statsmodels:OLS回归、ARIMA/GARCH、协整检验、VAR模型等经典计量方法

scikit-learn:机器学习的瑞士军刀

对于量化因子建模,scikit-learn提供了:

  • 线性模型(含正则化)
  • 树模型(随机森林、GBDT)
  • 交叉验证和网格搜索
  • 特征工程(标准化、PCA、特征选择)
  • 模型评估指标

环境搭建建议

推荐使用 Miniconda 管理Python环境,避免依赖冲突:

bash
# 创建专用量化环境
conda create -n quant python=3.11
conda activate quant

# 核心科学计算
conda install numpy pandas scipy matplotlib jupyter

# 统计与计量
conda install -c conda-forge statsmodels

# 机器学习
conda install -c conda-forge scikit-learn

# 金融数据获取
pip install tushare akshare yfinance

# 高性能
conda install numba cython
pip install polars  # 新一代高性能DataFrame库

# 可选:深度学习
pip install torch torchvision  # PyTorch

Python实战

案例1:移动平均

PYTHON2 行 · 86 B
📄此处有展示代码2 行 · 86 B展开 ▼
python
df['MA5'] = df['Close'].rolling(5).mean()
df['MA20'] = df['Close'].rolling(20).mean()
点击展开可浏览运行结果
Close    MA5   MA20
2024-02-20  83.58  84.25  87.97
2024-02-21  83.00  84.12  87.45
2024-02-22  81.98  83.48  86.87
2024-02-23  82.90  82.91  86.43
2024-02-24  84.45  83.18  86.00
2024-02-25  85.84  83.63  85.73
2024-02-26  84.58  83.95  85.39
2024-02-27  84.12  84.38  85.16
2024-02-28  84.62  84.72  85.06
2024-02-29  86.08  85.05  85.02

最新收盘: 86.08
MA5: 85.05
MA20: 85.02

案例2:Pandas面板数据操作——因子计算流水线

PYTHON66 行 · 2.6 KB
📄此处有展示代码66 行 · 2.6 KB展开 ▼
python
import pandas as pd
import numpy as np

def factor_computation_pipeline(prices_df, volumes_df=None, market_cap_df=None):
    """
    一个典型的因子计算流水线,展示Pandas在量化中的核心用法
    
    prices_df: DataFrame, index=日期, columns=股票代码, values=收盘价
    volumes_df: DataFrame, 同上, values=成交量
    market_cap_df: DataFrame, 同上, values=总市值
    """
    # === 收益率计算 ===
    daily_returns = prices_df.pct_change()  # 日收益率
    
    # === 动量因子 ===
    momentum_1m = prices_df / prices_df.shift(21) - 1   # 1个月动量(~21个交易日)
    momentum_3m = prices_df / prices_df.shift(63) - 1   # 3个月动量
    momentum_12m = prices_df / prices_df.shift(252) - 1  # 12个月动量
    momentum_12_1m = momentum_12m - momentum_1m           # 12-1月动量(剔除短期反转)
    
    # === 波动率因子 ===
    volatility_1m = daily_returns.rolling(21).std() * np.sqrt(252)  # 年化波动率
    volatility_3m = daily_returns.rolling(63).std() * np.sqrt(252)
    
    # === 换手率因子 ===
    if volumes_df is not None:
        turnover_1m = volumes_df.rolling(21).mean()  # 日均成交量
        turnover_ratio = volumes_df / volumes_df.rolling(252).mean()  # 相对换手率
    
    # === 流动性因子 (Amihud) ===
    if volumes_df is not None:
        amihud = (daily_returns.abs() / (volumes_df * prices_df)).rolling(21).mean()
    
    # === 横截面标准化 ===
    # 将每个日期的所有股票因子值标准化为均值0标准差1
    def cross_sectional_zscore(factor_df):
        return factor_df.sub(factor_df.mean(axis=1), axis=0).div(factor_df.std(axis=1), axis=0)
    
    # 对动量因子做横截面标准化
    mom_1m_z = cross_sectional_zscore(momentum_1m)
    vol_1m_z = cross_sectional_zscore(volatility_1m)
    
    # === 合并多个因子(等权合成) ===
    composite = (mom_1m_z + (-vol_1m_z)) / 2  # 高动量 + 低波动
    
    # === 处理缺失值 ===
    composite = composite.replace([np.inf, -np.inf], np.nan)
    
    # 前向填充缺失值(停牌日沿用前值)
    composite = composite.ffill(limit=5)  # 最多填充5天
    
    # 极端值处理 (Winsorize at 1% and 99%)
    lower = composite.quantile(0.01, axis=1)
    upper = composite.quantile(0.99, axis=1)
    composite = composite.clip(lower, upper, axis=0)
    
    return {
        'momentum_1m': momentum_1m,
        'momentum_12_1m': momentum_12_1m,
        'volatility_1m': volatility_1m,
        'composite': composite,
        'daily_returns': daily_returns
    }

# 使用示例
# factors = factor_computation_pipeline(prices_df, volumes_df)
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `factor_computation_pipeline`(一个典型的因子计算流水线,展示Pandas在量化中的核心用法)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

案例3:高效数据管道——Pandas链式操作

PYTHON56 行 · 1.9 KB
📄此处有展示代码56 行 · 1.9 KB展开 ▼
python
import pandas as pd
import numpy as np

def efficient_data_pipeline(raw_prices):
    """
    展示使用Pandas链式操作构建高效数据处理管道
    """
    
    # 方法1: 传统的逐步操作(可读性好但效率低)
    def traditional_approach(df):
        df = df.copy()
        df['return'] = df['Close'].pct_change()
        df['MA20'] = df['Close'].rolling(20).mean()
        df['MA60'] = df['Close'].rolling(60).mean()
        df['signal'] = (df['MA20'] > df['MA60']).astype(int)
        df['signal'] = df['signal'].shift(1)
        df['strategy_return'] = df['signal'] * df['return']
        return df
    
    # 方法2: 链式操作(更优雅,Pandas推荐风格)
    def chained_approach(df):
        return (df
            .assign(
                return_=lambda d: d['Close'].pct_change(),
                MA20=lambda d: d['Close'].rolling(20).mean(),
                MA60=lambda d: d['Close'].rolling(60).mean()
            )
            .assign(
                signal=lambda d: (d['MA20'] > d['MA60']).astype(int).shift(1)
            )
            .assign(
                strategy_return=lambda d: d['signal'] * d['return_']
            )
            .dropna()
        )
    
    # 方法3: 使用Polars的惰性计算(LazyFrame)
    def polars_approach(filepath):
        import polars as pl
        
        return (pl.scan_csv(filepath)
            .with_columns([
                pl.col('Close').pct_change().alias('return_'),
                pl.col('Close').rolling_mean(20).alias('MA20'),
                pl.col('Close').rolling_mean(60).alias('MA60'),
            ])
            .with_columns([
                (pl.col('MA20') > pl.col('MA60')).cast(pl.Int64).shift(1).alias('signal')
            ])
            .with_columns([
                (pl.col('signal') * pl.col('return_')).alias('strategy_return')
            ])
            .collect()  # 在此刻执行所有惰性计算
        )
    
    return chained_approach(raw_prices)
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `efficient_data_pipeline`(展示使用Pandas链式操作构建高效数据处理管道)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

常见误区

误区一:用SQL的思维写Pandas

事实:虽然Pandas提供了类似SQL的操作(merge、groupby),但这种思维模式会导致效率低下。Pandas的向量化操作、transform和rolling窗口函数提供了远超SQL的表达能力。用Pythonic的方式思考——先做列级变换,再做聚合。

误区二:忽视索引的对齐行为

事实:Pandas的自动索引对齐是其最强大的特性之一,也是最容易引发隐蔽bug的地方。两个DataFrame相加时,Pandas会按行索引和列名对齐,不对应的位置会产生NaN。在做多股票面板数据操作时,时刻注意索引结构。

误区三:所有数据都用Pandas

事实:当数据量超过内存容量时,应考虑替代方案:

  • Dask:类Pandas API的分布式计算
  • Polars:新一代高性能DataFrame,惰性计算+多线程
  • PySpark:大规模集群计算
  • SQL + Parquet:列式存储,适合TB级数据

误区四:一个环境包打天下

事实:建议为不同项目维护独立的conda环境。量化项目的依赖往往很特定(特定版本的numpy、特定的数据库驱动、特定的交易API),混合在一起很快就会陷入"依赖地狱"。

实战练习

  1. 面板数据操作:使用AkShare或Tushare获取沪深300成分股的日线数据(至少10只股票、1年数据),构建一个价格面板DataFrame(index=日期,columns=股票代码)。计算每只股票的累计收益率,找出表现最好和最差的3只。

  2. 因子计算:在上一题的面板数据基础上,计算以下因子:(a) 20日动量,(b) 20日波动率,(c) 20日日均换手率(如果有成交量数据)。对每个因子在每月末做横截面排名,将排名转换为因子分位数(0到1),然后计算下个月的收益与本月因子分位数的相关性。

  3. Pandas vs Polars:用Pandas和Polars分别实现相同的因子计算流水线(至少包含移动平均、滚动相关系数和横截面标准化),用较大的数据集(如500只股票x1000天)测试两者的运行速度差异。

延伸阅读

  • 《Python for Data Analysis》—— Wes McKinney (Pandas作者),Python数据分析的必读书
  • 《Effective Pandas》—— Matt Harrison,Pandas最佳实践
  • Polars官方文档 (pola.rs) —— 新一代高性能DataFrame
  • 《High Performance Python》—— Gorelick and Ozsvald,Python性能优化指南
  • NumPy官方教程 —— 向量化计算的深入讲解

本章要点

  • Python的量化优势在于NumPy/Pandas/SciPy/scikit-learn的无缝集成
  • NumPy的广播和向量化运算是高效数值计算的核心
  • Pandas是量化数据处理的中枢,掌握索引对齐、滚动窗口和链式操作是必备技能
  • 为不同项目维护独立的conda环境,避免依赖冲突
  • 数据量超内存时考虑Polars、Dask或分布式方案