Python 量化金融基础
Python 量化金融基础全面指南
量化金融(Quantitative Finance)是金融工程的核心,结合数学、统计学和计算机科学,通过模型和算法进行投资决策。Python 因其科学计算能力和金融库生态,成为量化金融的首选工具。
1. 核心数学与统计基础
时间价值与复利计算
import numpy as np
import numpy_financial as npf
# 现值(PV)、未来值(FV)计算
principal = 10000 # 本金
rate = 0.05 # 年化利率
periods = 10 # 年数
# 未来值
fv = principal * (1 + rate) ** periods
fv_continuous = principal * np.exp(rate * periods)
# 年金现值
pmt = 1000 # 每年支付
pv_annuity = npf.pv(rate, periods, -pmt)
print(f"单利未来值: {fv:.2f}")
print(f"连续复利: {fv_continuous:.2f}")
print(f"年金现值: {pv_annuity:.2f}")
随机过程与布朗运动
import matplotlib.pyplot as plt
import numpy as np
# 几何布朗运动(股票价格模型)
def geometric_brownian_motion(S0, mu, sigma, T, dt, n_paths=1):
"""生成几何布朗运动路径"""
N = int(T / dt)
t = np.linspace(0, T, N)
W = np.random.standard_normal(size=(N, n_paths))
W = np.cumsum(W * np.sqrt(dt), axis=0)
# 伊藤积分解
paths = S0 * np.exp((mu - 0.5 * sigma**2) * t[:, np.newaxis] +
sigma * W)
return t, paths
# 参数设置
S0, mu, sigma, T, dt = 100, 0.1, 0.2, 1.0, 1/252
t, paths = geometric_brownian_motion(S0, mu, sigma, T, dt, n_paths=100)
plt.figure(figsize=(10, 6))
plt.plot(t, paths, alpha=0.3)
plt.plot(t, paths.mean(axis=1), 'r-', linewidth=2, label='平均路径')
plt.title('几何布朗运动 - 股票价格模拟')
plt.xlabel('时间')
plt.ylabel('价格')
plt.legend()
plt.show()
2. 资产定价基础
Black-Scholes 期权定价模型
from scipy.stats import norm
import numpy as np
def black_scholes(S, K, T, r, sigma, option_type='call'):
"""Black-Scholes 期权定价"""
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if option_type == 'call':
price = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
else: # put
price = K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
return price
# Greeks 计算
def greeks(S, K, T, r, sigma, option_type='call'):
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
delta = norm.cdf(d1) if option_type == 'call' else -norm.cdf(-d1)
gamma = norm.pdf(d1) / (S * sigma * np.sqrt(T))
theta = -(S * norm.pdf(d1) * sigma) / (2 * np.sqrt(T))
if option_type == 'call':
theta -= r * K * np.exp(-r * T) * norm.cdf(d2)
else:
theta -= r * K * np.exp(-r * T) * norm.cdf(-d2)
theta /= 365 # 日Theta
vega = S * norm.pdf(d1) * np.sqrt(T) / 100 # 1%波动率变化
return {'Delta': delta, 'Gamma': gamma, 'Theta': theta, 'Vega': vega}
# 示例
S, K, T, r, sigma = 100, 100, 0.25, 0.05, 0.2
call_price = black_scholes(S, K, T, r, sigma, 'call')
print(f"看涨期权价格: {call_price:.2f}")
print("Greeks:", greeks(S, K, T, r, sigma))
二叉树期权定价
def binomial_tree(S, K, T, r, sigma, n, option_type='call'):
"""Cox-Ross-Rubinstein 二项树期权定价"""
dt = T / n
u = np.exp(sigma * np.sqrt(dt))
d = 1 / u
p = (np.exp(r * dt) - d) / (u - d)
# 构建价格树
stock_tree = np.zeros((n+1, n+1))
for i in range(n+1):
for j in range(i+1):
stock_tree[j, i] = S * (u ** (i-j)) * (d ** j)
# 期权价值向后递推
option_tree = np.zeros((n+1, n+1))
option_tree[:, n] = np.maximum(K - stock_tree[:, n], 0) if option_type == 'put' else \
np.maximum(stock_tree[:, n] - K, 0)
for i in range(n-1, -1, -1):
for j in range(i+1):
option_tree[j, i] = np.exp(-r * dt) * (
p * option_tree[j, i+1] + (1-p) * option_tree[j+1, i+1])
return option_tree[0, 0]
# 验证与Black-Scholes对比
bs_price = black_scholes(S, K, T, r, sigma)
bin_price = binomial_tree(S, K, T, r, sigma, n=100)
print(f"Black-Scholes: {bs_price:.4f}, 二项树: {bin_price:.4f}")
3. 风险管理与VaR
历史模拟法 VaR
import pandas as pd
import numpy as np
from scipy import stats
def historical_var(returns, confidence=0.95, portfolio_value=1000000):
"""历史模拟法VaR"""
sorted_returns = np.sort(returns)
var_index = int((1 - confidence) * len(sorted_returns))
var_return = sorted_returns[var_index]
var_amount = -var_return * portfolio_value
return var_return, var_amount
# 示例:多资产组合
tickers = ['AAPL', 'MSFT', 'SPY']
data = yf.download(tickers, start='2020-01-01')['Adj Close']
returns = data.pct_change().dropna()
# 组合权重
weights = np.array([0.4, 0.3, 0.3])
portfolio_returns = (returns * weights).sum(axis=1)
var_ret, var_amt = historical_var(portfolio_returns, confidence=0.99)
print(f"99% VaR: {var_ret:.4f} ({var_amt:,.0f})")
参数法 VaR(正态分布假设)
def parametric_var(returns, confidence=0.95, portfolio_value=1000000):
"""参数法VaR(正态分布)"""
mu = np.mean(returns)
sigma = np.std(returns)
z_score = stats.norm.ppf(1 - confidence)
var_return = mu + z_score * sigma
var_amount = -var_return * portfolio_value
return var_return, var_amount, z_score
# 计算并绘制VaR
var_ret, var_amt, z = parametric_var(portfolio_returns, 0.99)
print(f"参数法99% VaR: {var_ret:.4f} ({var_amt:,.0f}), Z-score: {z:.2f}")
# 可视化
plt.figure(figsize=(12, 6))
plt.hist(portfolio_returns, bins=100, density=True, alpha=0.7, label='历史收益率')
x = np.linspace(portfolio_returns.min(), portfolio_returns.max(), 100)
plt.plot(x, stats.norm.pdf(x, np.mean(portfolio_returns),
np.std(portfolio_returns)), 'r-', lw=2, label='正态拟合')
plt.axvline(var_ret, color='red', linestyle='--', label=f'99% VaR: {var_ret:.4f}')
plt.title('组合VaR分析')
plt.legend()
plt.show()
4. 投资组合优化
均值-方差优化(Markowitz 模型)
from scipy.optimize import minimize
import numpy as np
def portfolio_optimization(returns, cov_matrix, target_return=None):
"""均值-方差优化"""
n_assets = returns.shape[1]
def portfolio_variance(weights):
return np.dot(weights.T, np.dot(cov_matrix * 252, weights))
def portfolio_return(weights):
return np.sum(returns.mean() * 252 * weights)
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) # 权重和为1
if target_return:
constraints.append({'type': 'eq', 'fun': lambda x: portfolio_return(x) - target_return})
bounds = tuple((0, 1) for _ in range(n_assets)) # 无空头约束
# 最小方差优化
result_mv = minimize(portfolio_variance, 0.5 * np.ones(n_assets),
method='SLSQP', bounds=bounds, constraints=constraints)
# 最大夏普比率
def neg_sharpe(weights):
r = portfolio_return(weights)
vol = np.sqrt(portfolio_variance(weights))
return -r / vol
result_sr = minimize(neg_sharpe, 0.5 * np.ones(n_assets),
method='SLSQP', bounds=bounds, constraints=constraints)
return result_mv, result_sr
# 示例优化
ret_annual = returns.mean() * 252
cov_annual = returns.cov() * 252
mv_weights, sr_weights = portfolio_optimization(returns, cov_annual)
print("最小方差权重:", dict(zip(tickers, mv_weights.x.round(4))))
print("最大夏普权重:", dict(zip(tickers, sr_weights.x.round(4))))
# 有效前沿
target_returns = np.linspace(ret_annual.min(), ret_annual.max(), 20)
frontier_vols = []
for tr in target_returns:
_, result = portfolio_optimization(returns, cov_annual, tr)
frontier_vols.append(np.sqrt(result.fun))
plt.figure(figsize=(10, 6))
plt.plot(frontier_vols, target_returns, 'b-', label='有效前沿')
plt.scatter(np.sqrt(cov_annual.diagonal()), ret_annual, c='red', label='单资产')
plt.xlabel('波动率')
plt.ylabel('预期收益')
plt.title('Markowitz 有效前沿')
plt.legend()
plt.show()
5. 因子模型与风险分解
Fama-French 三因子模型
from sklearn.linear_model import LinearRegression
import statsmodels.api as sm
# 获取因子数据(示例)
def get_fama_french_factors():
"""获取Fama-French因子数据"""
# 实际使用时从Ken French网站下载或使用量化平台API
# 这里模拟数据
np.random.seed(42)
dates = pd.date_range('2020-01-01', '2024-01-01', freq='M')
factors = pd.DataFrame({
'MKT': np.random.normal(0.008, 0.04, len(dates)),
'SMB': np.random.normal(0.002, 0.03, len(dates)),
'HML': np.random.normal(0.001, 0.025, len(dates))
}, index=dates)
return factors
factors = get_fama_french_factors()
stock_returns = portfolio_returns.resample('M').apply(lambda x: (1+x).prod()-1).dropna()
# 回归分析
X = sm.add_constant(factors)
model = sm.OLS(stock_returns, X).fit()
print(model.summary())
# 因子暴露
factor_exposures = model.params
print("因子Beta:", factor_exposures[1:])
6. 蒙特卡洛模拟与情景分析
投资组合蒙特卡洛模拟
def monte_carlo_portfolio(returns, weights, n_simulations=10000, periods=252):
"""投资组合蒙特卡洛模拟"""
mu = returns.mean() * 252
cov = returns.cov() * 252
portfolio_mu = np.dot(weights, mu)
portfolio_sigma = np.sqrt(np.dot(weights.T, np.dot(cov, weights)))
sim_returns = np.random.multivariate_normal(mu, cov, (periods, n_simulations))
portfolio_returns = np.dot(sim_returns, weights)
# 年化指标
final_values = (1 + portfolio_returns).prod(axis=0)
annual_returns = final_values ** (1/periods) - 1
annual_vol = np.std(portfolio_returns, axis=0) * np.sqrt(252)
return annual_returns, annual_vol, final_values
annual_ret, annual_vol, final_values = monte_carlo_portfolio(returns, weights)
# 置信区间
ci_lower = np.percentile(annual_ret, 5)
ci_upper = np.percentile(annual_ret, 95)
print(f"年化收益95%置信区间: [{ci_lower:.2%}, {ci_upper:.2%}]")
# 可视化
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.hist(annual_ret * 100, bins=50, alpha=0.7)
plt.axvline(np.mean(annual_ret)*100, color='red', linestyle='--')
plt.title('年化收益分布')
plt.xlabel('年化收益 (%)')
plt.subplot(1, 2, 2)
plt.hist(final_values, bins=50, alpha=0.7)
plt.axvline(np.percentile(final_values, [5, 95]), color='red', linestyle='--', alpha=0.7)
plt.title('最终组合价值分布')
plt.ylabel('频次')
plt.tight_layout()
plt.show()
7. 固定收益与利率模型
债券定价与久期
def bond_price(face_value, coupon_rate, ytm, years, freq=2):
"""债券定价"""
coupon = face_value * coupon_rate / freq
periods = years * freq
dt = 1 / freq
# 现金流现值
pv_coupons = sum([coupon / (1 + ytm/freq)**(t+1) for t in range(int(periods))])
pv_face = face_value / (1 + ytm/freq)**periods
return pv_coupons + pv_face
def macaulay_duration(face_value, coupon_rate, ytm, years, freq=2):
"""麦考利久期"""
price = bond_price(face_value, coupon_rate, ytm, years, freq)
coupon = face_value * coupon_rate / freq
periods = years * freq
weighted_cf = 0
for t in range(1, int(periods)+1):
if t == periods:
cf = coupon + face_value
else:
cf = coupon
weighted_cf += cf * t / freq / (1 + ytm/freq)**t
duration = weighted_cf / price
return duration
# 示例:10年期债券
price = bond_price(1000, 0.05, 0.04, 10)
duration = macaulay_duration(1000, 0.05, 0.04, 10)
print(f"债券价格: {price:.2f}")
print(f"麦考利久期: {duration:.2f}年")
8. 关键库与工具
库名 | 功能 | 安装命令 |
---|---|---|
QuantLib | 专业金融计算库(期权、债券、风险) | pip install QuantLib |
numpy-financial | 金融函数(NPV、IRR、债券) | pip install numpy-financial |
pyfolio | 绩效分析与风险指标 | pip install pyfolio |
empyrical | 金融绩效指标计算 | pip install empyrical |
cvxpy | 凸优化(组合优化) | pip install cvxpy |
安装专业库示例:
# QuantLib 高级期权定价
import QuantLib as ql
# 设置计算日期
calculation_date = ql.Date(17, 10, 2025)
ql.Settings.instance().evaluationDate = calculation_date
# 欧洲期权
option = ql.VanillaOption(ql.PlainVanillaPayoff(ql.Option.Call, 100),
ql.EuropeanExercise(ql.Date(17, 10, 2026)))
9. 学习路径与实践建议
- 理论基础:
- 《期权、期货及其他衍生品》(Hull)
- 《量化投资策略》(Grinold & Kahn)
- 《金融时间序列分析》(Tsay)
- Python实践:
- 从简单定价模型开始
- 实现经典策略回测
- 构建风险管理系统
- 进阶应用:
- 机器学习在量化金融中的应用
- 高频交易系统开发
- 另类数据处理
- 实盘注意事项:
- 滑点与交易成本建模
- 实时期货与保证金管理
- 监管合规与风控
10. 常见陷阱与最佳实践
- 模型风险:定期验证模型假设
- 数据偏差:注意幸存者偏差、回测过度拟合
- 计算精度:使用双精度浮点,避免数值不稳定
- 并发处理:蒙特卡洛模拟使用向量化或并行计算
需要深入某个特定主题(如随机波动率模型、信用风险建模)或完整策略实现,请告诉我具体需求!