σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyロードマップ
Ctrl K
AO
+1.2k 人の学習者
ログイン参加する ↗
ロードマップ
AO
+1.2k 人の学習者
ログイン
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python ロードマップ›モジュール 7 · アルファ研究とリスク›トピック 7.6·~50 分上級

期待ショートフォール

ロードマップ上の位置モジュール 7/11 · トピック 6/9
7.6 期待ショートフォール
—ラボスコア— / 100合計XP—連続日数—

VaRが言わないこと

信頼水準99%のVaRが3%なら、100日のうち99日は損失が3%未満です。100日目については何も言わず、3.1%かもしれず30%かもしれません。期待ショートフォール(ES、CVaR)がこの穴を埋めます。VaRを超えた日の平均損失なので、裾の形を表します。平均を取るため滑らかに変化し、VaRと違って常に分散を評価します。バーゼルが市場リスクの指標をVaRからESへ移したのはそのためです。

import numpy as np

rng = np.random.default_rng(5)
returns = rng.standard_t(4, size=1000) * 0.01

cutoff = np.quantile(returns, 0.05)                   # the 95% VaR is minus this
tail = np.sort(returns[returns <= cutoff])            # the worst 5% of the days, lowest first
print(len(tail), round(float(-cutoff), 5))            # 50 days; the VaR
print(np.round(tail[:4], 4))                          # the four worst days

裾を平均する

ヒストリカル法では、ESは単純です。VaRの閾値以下のリターンを選んで平均し、符号を反転します。裾のどのリターンも閾値と同じかそれ以下なので、結果がVaRより小さくなることはありません。比率 ES / VaR は裾の重さを示します。正規分布では95%でおよそ1.2で、ファットテールのデータでは通常もっと大きくなります。

import numpy as np

def tail_returns(returns, confidence):
    cutoff = np.quantile(returns, 1 - confidence)
    return np.sort(returns[returns <= cutoff])

def historical_es(returns, confidence):
    return float(-tail_returns(returns, confidence).mean())

rng = np.random.default_rng(5)
returns = rng.standard_t(4, size=1000) * 0.01
for confidence in (0.95, 0.99):
    var = -np.quantile(returns, 1 - confidence)
    es = historical_es(returns, confidence)
    print(confidence, round(float(var), 5), round(es, 5), round(es / float(var), 3))

正規分布の場合の公式

正規分布のリターンでは、裾の平均に閉じた式があります:ES = sigma * pdf(z) / (1 - confidence) - mu。z はVaRに使う分位点、pdf は z での標準正規密度です。計算は2行の関数になりますが、正確なのはデータが正規のときだけなので、ヒストリカルESとの比較は、データが正規性からどれだけ外れているかの手早い検査になります。

from statistics import NormalDist

def normal_es(mu, sigma, confidence):
    z = NormalDist().inv_cdf(confidence)
    return sigma * NormalDist().pdf(z) / (1 - confidence) - mu

for confidence in (0.95, 0.975, 0.99):
    var = NormalDist().inv_cdf(confidence)                        # in standard deviations, mu = 0
    es = normal_es(0.0, 1.0, confidence)
    print(confidence, round(var, 3), round(es, 3), round(es / var, 3))       # ES/VaR: 1.254, 1.193, 1.146
# The formula against a simulated tail
import numpy as np
from statistics import NormalDist

rng = np.random.default_rng(0)
sample = rng.normal(0.0, 0.01, size=1_000_000)
tail = sample[sample <= np.quantile(sample, 0.01)]
simulated = -tail.mean()
z = NormalDist().inv_cdf(0.99)
formula = 0.01 * NormalDist().pdf(z) / 0.01
print(round(float(simulated), 5), round(formula, 5))         # both close to 0.02665
ESはバックテストも難しいVaRは超過日を数えて検証できます。ESは裾にあるわずかな観測に依存し、99%・250日なら2〜3個のリターンです。推定のノイズが大きく、より多くのデータかモデルが必要です。実務では両方を併せて報告し、VaRは閾値、ESはそれを超えた先の深刻さを示します。
  • ESはVaRを超えた裾の平均損失。(1 - confidence) 分位点以下のリターンの平均にマイナスを付けたもの
  • VaRを下回ることはない。ES / VaR は裾の重さを測り、正規分布の公式は sigma * pdf(z) / (1 - confidence) - mu
  • VaRは閾値、ESは深刻さとして報告する。ESは裾の観測が少ないためノイズが大きい

次はストレステストです。特定の極端なシナリオでポートフォリオがいくら失うかを問います。

ラボ:採点される内容

  • tail_returns で最悪の日々を取り出す25点
  • historical_es で裾の平均を取る25点
  • normal_es で公式から求める25点
  • es_var_ratio で裾と閾値を比べる25点
エクスプローラー · lab-98-1
▾ lab-98-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-98-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

このトピックをリセットしますか?

lab-98-1 の内容はすべてスターターファイルに戻り、ターミナルも消去されます。現在の解答は失われ、元に戻せません。

リセットされるもの
  • main.py → スターターコード
  • ターミナル履歴とテスト出力
  • 未提出の変更
保持されるもの
  • ラボの最高スコア
  • XPと連続日数
  • 講義の進捗とメモ

コードを実行するにはログインしてください。

レクチャーはすべて無料で読めます。コードの実行、テスト、ラボの提出にはアカウントの作成かログインが必要です。

  • ブラウザ内IDEとbashターミナル。インストール不要
  • 即時採点、XP、ロードマップでの現在地
アカウントを作成ログイン
または
GitHubで続ける