别怕数学!用Python的NumPy和Pandas,手把手带你搞定量化交易里的线性代数与统计
·
别怕数学!用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 策略逻辑
- 计算短期(20日)和长期(60日)均线
- 当短期均线上穿长期均线时买入
- 当短期均线下穿长期均线时卖出
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 市场环境变化
应对方法:
- 定期重新评估策略
- 设置最大回撤止损
- 采用多策略组合
更多推荐
所有评论(0)