别怕数学!用Python的NumPy和Pandas,手把手带你搞定量化交易里的线性代数与统计

量化交易听起来高大上,但核心不过是数学+编程的结合。很多开发者一听到"线性代数"、"概率统计"就头疼,其实这些概念用Python实现起来比你想象中简单得多。本文将用NumPy和Pandas这两个Python利器,带你用代码理解量化交易中的关键数学概念,从矩阵运算到时间序列分析,全程实操,零基础也能跟上。

1. 量化交易中的线性代数实战

金融数据本质上就是数字的集合,而处理数字集合最高效的工具就是矩阵。NumPy的ndarray就是为矩阵运算而生的数据结构。

1.1 投资组合优化:用矩阵求解最优权重

假设我们有四只股票的历史收益率数据:

import numpy as np

# 年化收益率 (%)
returns = np.array([12.5, 9.8, 15.2, 7.4])  

# 协方差矩阵
cov_matrix = np.array([
    [0.025, 0.012, 0.018, 0.009],
    [0.012, 0.022, 0.015, 0.008],
    [0.018, 0.015, 0.028, 0.011],
    [0.009, 0.008, 0.011, 0.017]
])

要找到最优投资组合权重,我们需要解以下线性方程组:

# 构建方程组
n = len(returns)
A = np.vstack((cov_matrix, np.ones(n), returns)).T
b = np.append(np.append(np.zeros(n), [1]), [0.1])  # 目标收益率10%

# 最小二乘解
weights = np.linalg.lstsq(A, b, rcond=None)[0]
print(f"最优权重: {weights.round(4)}")

1.2 特征值分解:发现市场风险因子

金融数据中常常隐藏着几个主导的风险因子。用SVD可以提取这些潜在因子:

# 假设daily_returns是形状为(交易日数, 股票数量)的矩阵
U, s, Vh = np.linalg.svd(daily_returns - daily_returns.mean(axis=0))

# 前三个主成分解释的方差比例
explained_variance = s**2 / np.sum(s**2)
print(f"前三个主成分解释方差: {explained_variance[:3].round(3)}")

2. 统计学在量化交易中的应用

统计学是量化交易的基石,从简单的假设检验到复杂的机器学习模型都离不开它。

2.1 用Pandas进行描述性统计

金融数据分析第一步永远是了解数据的基本特征:

import pandas as pd

# 加载股票数据
df = pd.read_csv('stock_data.csv', parse_dates=['Date'], index_col='Date')

# 计算关键统计量
stats = df.pct_change().describe()
print(stats.loc[['mean', 'std', 'min', 'max']])

2.2 假设检验:验证策略有效性

当我们开发出一个交易策略,如何知道它不是靠运气?t检验可以给出答案:

from scipy import stats

# strategy_returns是策略收益率序列
t_stat, p_value = stats.ttest_1samp(strategy_returns, 0)
print(f"p值为{p_value:.4f}, {'显著' if p_value < 0.05 else '不显著'}")

3. 时间序列分析的Python实现

金融数据本质上是时间序列,Pandas提供了强大的时间序列处理功能。

3.1 滚动窗口计算技术指标

移动平均是最基础的技术指标:

# 计算20日、50日、200日均线
df['MA20'] = df['Close'].rolling(20).mean()
df['MA50'] = df['Close'].rolling(50).mean()
df['MA200'] = df['Close'].rolling(200).mean()

3.2 用statsmodels进行ARIMA建模

ARIMA模型是时间序列预测的经典方法:

from statsmodels.tsa.arima.model import ARIMA

# 拟合ARIMA(1,1,1)模型
model = ARIMA(df['Close'], order=(1,1,1))
results = model.fit()

# 预测未来5天
forecast = results.get_forecast(steps=5)
print(forecast.predicted_mean)

4. 从数学公式到Python代码的转换技巧

很多数学公式看起来复杂,转换成代码后其实非常直观。

4.1 矩阵求导的代码实现

比如投资组合优化中常用的马科维茨模型:

数学公式: min w^T Σ w s.t. w^T μ = r w^T 1 = 1

Python实现:

def portfolio_optimization(expected_returns, cov_matrix, target_return):
    n = len(expected_returns)
    A = np.vstack((cov_matrix, expected_returns, np.ones(n))).T
    b = np.append(np.append(np.zeros(n), target_return), 1)
    weights = np.linalg.lstsq(A, b, rcond=None)[0]
    return weights

4.2 蒙特卡洛模拟的向量化实现

模拟股票价格路径:

def monte_carlo_simulation(S0, mu, sigma, T, N, num_simulations):
    dt = T/N
    # 向量化实现
    returns = np.exp((mu - 0.5*sigma**2)*dt + sigma*np.sqrt(dt)*np.random.normal(size=(num_simulations, N)))
    paths = S0 * np.cumprod(returns, axis=1)
    return paths

5. 实战案例:构建简单的量化策略

让我们把前面学到的知识综合起来,构建一个双均线策略。

5.1 策略逻辑

  1. 计算短期(20日)和长期(60日)均线
  2. 当短期均线上穿长期均线时买入
  3. 当短期均线下穿长期均线时卖出
def dual_moving_average_strategy(prices, short_window=20, long_window=60):
    signals = pd.DataFrame(index=prices.index)
    signals['price'] = prices
    signals['short_ma'] = prices.rolling(short_window).mean()
    signals['long_ma'] = prices.rolling(long_window).mean()
    signals['signal'] = 0
    signals['signal'][short_window:] = np.where(
        signals['short_ma'][short_window:] > signals['long_ma'][short_window:], 1, 0)
    signals['positions'] = signals['signal'].diff()
    return signals

5.2 策略回测

def backtest(signals, initial_capital=10000):
    positions = pd.DataFrame(index=signals.index).fillna(0)
    positions['stock'] = 100 * signals['signal']  # 假设每次交易100股
    portfolio = positions.multiply(signals['price'], axis=0)
    pos_diff = positions.diff()
    portfolio['holdings'] = (positions.multiply(signals['price'], axis=0)).sum(axis=1)
    portfolio['cash'] = initial_capital - (pos_diff.multiply(signals['price'], axis=0)).sum(axis=1).cumsum()
    portfolio['total'] = portfolio['cash'] + portfolio['holdings']
    portfolio['returns'] = portfolio['total'].pct_change()
    return portfolio

6. 量化交易中的常见陷阱与解决方案

即使数学上完美的策略,在实际应用中也可能遇到各种问题。

6.1 过拟合问题

解决方案:

  • 使用Walk-Forward优化
  • 保持样本外测试
  • 简化策略参数

6.2 交易成本的影响

示例代码计算交易成本对收益的影响:

def calculate_net_returns(gross_returns, positions, cost_per_trade):
    trades = positions.diff().abs().sum(axis=1)
    costs = trades * cost_per_trade
    net_returns = gross_returns - costs / portfolio['total'].shift(1)
    return net_returns

6.3 市场环境变化

应对方法:

  • 定期重新评估策略
  • 设置最大回撤止损
  • 采用多策略组合

更多推荐