风险管理:波动率、VaR与仓位管理
每一个投资决策都携带风险。理解如何衡量风险——波动率、VaR、回撤和仓位管理——是保护资本的基础。
投资的第一条规则是不亏钱。第二条规则是记住第一条。风险管理是理解、衡量和控制风险的工作。
什么是风险?
在金融中,风险是实际回报与预期回报不同的可能性。通常,我们关心的是下行风险——亏损的可能性。
两类风险:
- 系统性(市场)风险: 影响所有资产(衰退、战争)
- 特质性(特定)风险: 影响个别公司或行业
分散化可以消除特质性风险但不能消除系统性风险。
波动率:主要风险衡量指标
波动率是回报的标准差——衡量回报通常偏离均值的程度。
年化波动率: 日波动率或月波动率折算为年化:
- 日波动率 × √252(每年252个交易日)
- 月波动率 × √12
高波动率: 组合价值波动较大。 低波动率: 组合价值更稳定。
Python计算波动率
import numpy as np
import pandas as pd
def annualized_volatility(returns, periods_per_year=252):
"""
Calculate annualized volatility from return series.
"""
return np.std(returns, ddof=1) * np.sqrt(periods_per_year)
def rolling_volatility(returns, window=20, periods_per_year=252):
"""
Calculate rolling volatility.
"""
return returns.rolling(window).std() * np.sqrt(periods_per_year)
def downside_volatility(returns, target=0, periods_per_year=252):
"""
Calculate downside (semi) volatility—only negative deviations from target.
"""
downside_returns = returns[returns < target]
return np.std(downside_returns - target, ddof=1) * np.sqrt(periods_per_year)
提示词
用 numpy 和 pandas 写一组波动率函数:基于 std 的年化波动率、用 rolling 算的滚动波动率、只算负偏离的下行波动率。
风险价值(VaR)
VaR是在给定时间窗口内、仅以 (1 - 置信度) 的概率被突破的损失阈值。形式上:在置信度 α 与时间窗口 h 下,VaR 是损失分布的 α-分位数,使得
VaR 不是最坏情况或”最大”损失,而是损失分布的一个分位数。剩余的 (1 - α) 尾部包含比 VaR 更糟的结果;VaR 完全不描述这部分损失的幅度(可参考 Expected Shortfall / CVaR)。
示例: “我们的1天95% VaR是100万美元。” 解读:一天内有95%的概率损失不超过100万美元,有5%的概率(约每20个交易日一次)会超过该值。VaR 并不说明那些坏日子里损失会大多少。
VaR计算方法
1. 历史VaR: 构造历史多期损失的实证分布,然后读出 (1 - α) 分位数。每条路径是 periods 个采样日度回报的求和/复合,而非按比例放大的单期回报。
2. 参数(方差-协方差)VaR: 假设损失服从正态分布。当时间窗口 h 与回报单位一致时(如 h 天),μ_h = h · μ、σ_h = σ · √h,损失分位数为
对于95%置信度,z_{0.05} ≈ -1.645,所以 -z_{0.05} ≈ 1.645。
3. 蒙特卡洛VaR: 从拟合的回报分布(或直接从经验分布)采样长度为 h 的回报路径。每条路径的损失为该窗口内的复合回报。VaR 即这些路径损失的 (1 - α) 百分位数。
from scipy import stats
def historical_var(returns, confidence=0.95, periods=1, n_scenarios=10000):
"""
Historical VaR via path-based aggregation: build multi-period returns by
summing/compounding sampled daily returns, then take the loss percentile.
"""
if len(returns) < periods:
raise ValueError("Not enough returns to build paths of length `periods`.")
rng = np.random.default_rng()
n_paths = n_scenarios
sampled = rng.choice(returns, size=(n_paths, periods), replace=True)
multi_period_returns = sampled.sum(axis=1) # arithmetic aggregation
# For a buy-and-hold P&L: wealth_path = prod(1 + r_t); loss = V * (1 - prod(1+r_t))
# We report the return quantile; multiply by portfolio_value to get $ VaR externally.
return np.percentile(multi_period_returns, (1 - confidence) * 100)
def parametric_var(returns, confidence=0.95, periods=1):
"""
Parametric VaR assuming normal returns over an h-period horizon.
VaR (as a positive loss) = -(mu_h + z_{1-alpha} * sigma_h), where
mu_h = periods * mu
sigma_h = sigma * sqrt(periods)
and z_{1-alpha} is the (1-alpha) standard-normal quantile (negative).
"""
mu = np.mean(returns)
sigma = np.std(returns, ddof=1)
mu_h = periods * mu
sigma_h = sigma * np.sqrt(periods)
z = stats.norm.ppf(1 - confidence) # negative, e.g. -1.645 at 95%
# VaR expressed as the negative quantile return (positive number = loss)
return -(mu_h + z * sigma_h)
def monte_carlo_var(returns, n_simulations=10000, confidence=0.95, periods=1):
"""
Monte Carlo VaR: build multi-period return paths by resampling from the
empirical distribution, then take the loss percentile of the path returns.
"""
rng = np.random.default_rng()
paths = rng.choice(returns, size=(n_simulations, periods), replace=True)
multi_period_returns = paths.sum(axis=1)
return np.percentile(multi_period_returns, (1 - confidence) * 100)
提示词
用 numpy 和 scipy.stats 写三种 VaR 函数:多期路径重采样的历史 VaR、基于正态分布的参数 VaR、蒙特卡洛路径模拟 VaR。
最大回撤
回撤是组合价值从峰到谷的下降:
最大回撤(MDD): 观察期间内最大的回撤。
最大回撤特别重要,因为:
- 它代表了历史上最坏的情况
- 恢复需要等于损失比例的收益(亏损50%需要100%收益才能恢复)
- 心理上,大回撤会导致投资者在最坏时机放弃策略
def max_drawdown(prices):
"""
Calculate maximum drawdown from a price series.
"""
wealth_index = prices / prices.iloc[0]
previous_peaks = wealth_index.cummax()
drawdowns = (wealth_index - previous_peaks) / previous_peaks
return drawdowns.min()
def drawdown_series(prices):
"""
Calculate the drawdown series.
"""
wealth_index = prices / prices.iloc[0]
previous_peaks = wealth_index.cummax()
return (wealth_index - previous_peaks) / previous_peaks
提示词
用 pandas 写两个回撤函数:用 cummax 计算的最大回撤和完整的回撤时间序列。
仓位管理
在任何给定交易中应该下多少注?这是组合管理中最重要的决策之一。
固定比例仓位管理: 每笔交易风险组合的固定百分比。
示例: 10万美元组合,每笔交易愿意承担1%风险,入场价50美元,止损价48美元。
凯利公式
凯利公式最大化预期对数财富(几何增长率):
其中:
- = 投入组合的 fraction
- = 赌注的赔率(盈利 / 亏损)
- = 获胜概率
- = 亏损概率(= 1 - p)
大多数实践者使用半凯利或四分之一凯利,因为估计误差和风险厌恶。
def kelly_fraction(win_prob, win_loss_ratio):
"""
Calculate Kelly fraction for position sizing.
win_prob: probability of winning
win_loss_ratio: average win / average loss
"""
q = 1 - win_prob
f = (win_loss_ratio * win_prob - q) / win_loss_ratio
return max(0, f)
def half_kelly(win_prob, win_loss_ratio):
"""Half Kelly: more conservative than full Kelly."""
return kelly_fraction(win_prob, win_loss_ratio) / 2
提示词
写两个仓位管理函数:凯利分数(输入胜率和盈亏比,结果不超过 0)和保守的半凯利。
风险预算
机构组合通常在以下方面分配风险预算:
- 资产类别(股票、债券、另类资产)
- 地理区域
- 因子(市场贝塔、规模、价值)
- 个别仓位
目标是:确保没有单个仓位或因子主导组合风险。
核心要点
- 风险 = 亏损的可能性(主要是下行)
- 波动率(回报标准差)是主要风险衡量指标
- VaR总结给定置信水平下的最坏情况损失
- 最大回撤衡量峰到谷的下降
- 仓位管理是最可控的风险决策
- 凯利公式最大化几何增长但对大多数投资者来说过于激进
参考文献
- Taleb, Dynamic Hedging. Wiley, 1996. ISBN: 978-0-471-15253-2.
- Ang, Asset Management. Oxford University Press, 2014. ISBN: 978-0-19-995932-3.
- Hull, Risk Management and Financial Institutions. Wiley, 2018. ISBN: 978-1-119-48238-2.