问“如果……会怎样”,而不是“概率多大”
VaR 和预期损失是根据过去的收益率估计的,所以看不到从未发生过的事。压力测试抛开概率,直接套用你选定的情景:股市暴跌 20%、利率跳升 2 个点、重演 2008 年危机、货币贬值。组合在该情景下的损失是风险委员会可以讨论的数字,并且能揭示统计平均值所掩盖的集中度风险。
import numpy as np
values = np.array([500000.0, 300000.0, -200000.0]) # two longs and a short
shocks = np.array([-0.20, -0.10, 0.15]) # one scenario: stocks -20%, bonds -10%, the shorted stock +15%
pnl = values * shocks # per position
print(pnl) # [-100000. -30000. -30000.] the short loses when its stock rises
print(float(pnl.sum())) # -160000.0情景表
风险团队会保有一份常设的情景清单,既有历史情景(1987、2008、2020 年 3 月),也有假设情景。把它们放进一个矩阵,每行一个情景、每列一个头寸:各情景下的总亏损就是一次矩阵乘向量,scenarios @ values。取这个向量的最小值就得到最坏情形,而哪个情景伤害最大本身就是信息,它指出组合暴露在哪里。
import numpy as np
values = np.array([500000.0, 300000.0, -200000.0])
scenarios = np.array([[-0.20, -0.10, 0.15], # equity crash
[-0.05, 0.02, 0.00], # mild dip
[ 0.10, 0.05, -0.20]]) # the shorted stock falls 20%: the short gains
names = ["equity crash", "mild dip", "rally and short gain"]
pnl = scenarios @ values
for name, p in zip(names, pnl):
print(name, round(float(p)))
worst = int(np.argmin(pnl))
print("worst:", names[worst], round(float(pnl[worst])))# A shock does not have to be a price move: a rate jump hits a bond through its duration
duration = 7.5 # years, from the duration topic
bond_value = 1_000_000.0
rate_jump = 0.02 # +2 percentage points
print(round(bond_value * (-duration * rate_jump))) # -150000 the shock expressed as a price return of -15%反向压力测试
把问题倒过来:多大的冲击会让我们亏掉给定金额(比如资本缓冲)?取一个冲击方向(比如所有资产一起下跌),再乘以倍数 k。亏损是 -k * (values @ direction),对 k 线性,所以恰好亏 loss_limit 的倍数是 loss_limit / -(values @ direction)。如果这个方向不亏钱,任何倍数都达不到限额。
import numpy as np
def reverse_stress(values, direction, loss_limit):
change = float(values @ direction)
if change >= 0:
return float("inf")
return loss_limit / -change
values = np.array([500000.0, 300000.0, -200000.0])
direction = np.array([-1.0, -1.0, 0.0]) # the two longs fall by the same percentage
k = reverse_stress(values, direction, 100000.0)
print(round(k, 4)) # 0.125 a 12.5% fall in both longs loses 100,000
print(round(float(-(values @ (k * direction))), 2)) # 100000.0情景的价值取决于你的想象力难点在于选出严峻却合理的情景,并让相关资产像危机中那样一起变动。结果还是一个没有概率的点估计:数字难看是审视头寸的理由,数字好看并不能证明你没想到的情景也没事。压力测试是对 VaR 的补充,而不是替代。
- 压力测试施加选定的冲击:头寸盈亏为
values * shocks,亏损为负,获利的空头为正。 - 多个情景只是一次乘积
scenarios @ values;最小值指出最坏情形,并显示组合的暴露所在。 - 反向压力测试:恰好亏掉限额的冲击倍数为
loss_limit / -(values @ direction),若该方向从不亏损则为无穷大。
下一节:ARIMA 模型,用序列自身的过去来预测它。
实验:评分内容
- 用
shocked_pnl冲击每个头寸25 分 - 用
scenario_pnl一次运行多个情景25 分 - 用
worst_scenario找出最坏情形25 分 - 用
reverse_stress由亏损倒推25 分