σμ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 ロードマップ›モジュール 3 · 確率とモンテカルロ・シミュレーション›トピック 3.7·~40 分中級

シャープレシオ

ロードマップ上の位置モジュール 3/11 · トピック 7/12
3.7 シャープレシオ
—ラボスコア— / 100合計XP—連続日数—

リスク1単位あたりの報酬

ボラティリティ20%でリターン12%の戦略は、ボラティリティ5%でリターン6%の戦略より優れているとは限りません。シャープレシオは両者を同じ尺度に乗せます。無リスク金利を上回る平均リターンをボラティリティで割り、sqrt(期間数) で年率換算した (mean - rf) / std です。式は平均と分散のトピックで学びました。このトピックは、その使い方、つまりシャープレシオの読み方、改善の仕方、そして何より、どこまで信頼できるかを扱います。シャープ0.5は平凡、1は良好、2は優秀で疑わしい水準です。

ボラティリティは上昇も下落も同じに数えますが、思わぬ利益に文句を言う人はいません。ソルティノレシオは悪い側だけを残します。標準偏差を下方偏差 sqrt(mean(min(r - mar, 0)²)) に置き換えます(mar は最低許容リターン)。mar を上回った日は寄与が0ですが、平均には含まれます。大きなプラスの跳ねと小さな損失を持つ戦略は、シャープよりソルティノではるかに高く評価されます。

import math
import numpy as np
import pandas as pd

returns = np.array([0.004, -0.002, 0.001, 0.003, -0.004, 0.002, 0.006, -0.001, -0.010, 0.004, 0.002, -0.003])

sharpe = returns.mean() / returns.std(ddof=1) * math.sqrt(252)
print(round(sharpe, 3))                                  # 0.598

mar = 0.0                                                # a day below zero is a bad day
downside = math.sqrt(np.mean(np.minimum(returns - mar, 0) ** 2))
sortino = (returns.mean() - mar) / downside * math.sqrt(252)
print(round(downside, 5), round(sortino, 3))             # 0.00329 0.804   the up days no longer count as risk

変化を見る

全期間で1つのシャープレシオでは経緯が見えません。ローリング・シャープレシオは直近 window 個のリターンで再計算するので、戦略の良い局面と悪い局面が見えます。pandas ではローリング平均をローリング標準偏差で割り、年率換算します。短い窓がいかに激しく跳ねるかに注目してください。1か月分のデータでは戦略の順位付けにまったく足りません。

series = pd.Series(returns)
rolling = series.rolling(5)
rolling_sharpe = rolling.mean() / rolling.std() * math.sqrt(252)
print(rolling_sharpe.round(2).tolist())
# [nan, nan, nan, nan, 1.89, 0.0, 6.96, 4.97, -3.66, 0.51, 0.51, -4.69]   a 5-day Sharpe ratio is mostly noise

どれだけが運か

シャープレシオは推定値であり、推定には誤差があります。n 個のリターンで測った期間あたりのシャープ sr の標準誤差は約 sqrt((1 + 0.5 * sr²) / n) です。ここでの12日では、シャープ0.04に対して標準誤差が日次0.29あり、誤差は推定値の7倍です。年率換算でも同じ12日で 0.6 ± 4.6 になります。years 年にわたって観測した年率シャープ S のt統計量は S * sqrt(years) なので、0でないと95%確信するには (1.96 / S)² 年が必要です。シャープ0.5なら15年、シャープ1なら4年です。控えめな戦略の短いバックテストは何も証明しません。

per_period = returns.mean() / returns.std(ddof=1)            # the per-day Sharpe ratio
std_error = math.sqrt((1 + 0.5 * per_period ** 2) / len(returns))
print(round(per_period, 4), round(std_error, 4))            # 0.0376 0.2888   the error is 7 times the estimate
print(round(std_error * math.sqrt(252), 3))                 # 4.584           annualised: 0.6 +/- 4.6

# Years needed for an annual Sharpe ratio to reach t = 1.96
for annual in (0.5, 1.0, 2.0):
    print(annual, round((1.96 / annual) ** 2, 1))
# 0.5 15.4
# 1.0 3.8
# 2.0 1.0
# A yearly Sharpe of 1.0 observed over 4 years (1,008 days): how precise is it?
per_day = 1.0 / math.sqrt(252)
error_per_day = math.sqrt((1 + 0.5 * per_day ** 2) / 1008)
print(round(per_day, 4), round(error_per_day, 4), round(error_per_day * math.sqrt(252), 3))   # 0.063 0.0315 0.5   so 1.0 +/- 0.5
最良のバックテストが最も信頼できない戦略の変種を100個試して最もシャープレシオの高いものを残せば、勝者の数字は選別によって膨らみます。優位性のない戦略でも運だけでシャープ1以上が出ます。試した変種の数だけ期待を割り引き、選別が見ていないデータで検証し、経済的な理由のあるアイデアを選びましょう。
  • シャープ = (mean - rf) / std * sqrt(期間数)。ソルティノは標準偏差を下方偏差 sqrt(mean(min(r - mar, 0)²)) に置き換える
  • ローリング・シャープ(rolling.mean() / rolling.std())で変化を見る。短い窓はほぼノイズ
  • 標準誤差は期間あたり sqrt((1 + 0.5 * sr²) / n)。年率シャープのt統計量は S * sqrt(years) で、シャープ1には約4年が必要

次はドローダウンです。投資家が実際に痛みを感じる、高値からの損失を扱います。

ラボ:採点される内容

  • sortino_ratio で悪い日だけをペナルティにする25点
  • rolling_sharpe でレシオの時間変化を追う25点
  • sharpe_standard_error でシャープレシオに含まれる運の大きさを測る25点
  • sharpe_t_stat でそれが本物かを問う25点
エクスプローラー · lab-60-1
▾ lab-60-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-60-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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