σμ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.4·~45 分中級

仮説検定:t検定

ロードマップ上の位置モジュール 3/11 · トピック 4/12
3.4 仮説検定:t検定
—ラボスコア— / 100合計XP—連続日数—

平均リターンは本物か

バックテストで平均リターンが日次 +0.14% と出ました。その戦略は優れているのか、運が良かっただけか。リターンはノイズを含むので、どの標本にも平均があり、コイン投げの戦略でも半分の確率で正の平均になります。仮説検定は明確な問いを立てます。真の平均が mu0(通常0)だとして、mu0 からこれだけ離れた標本平均はどれほど珍しいか。その答えが p値です。p値が小さいことは、「何も起きていない」という仮説の下ではそのデータが非常に起こりにくいことを意味します。

t = (mean - mu0) / (s / sqrt(n)) p = P(|Z| > |t|)

t統計量は、平均をその不確かさを単位として測ります。平均の不確かさは標準誤差 s / sqrt(n) で、標本が大きくなると小さくなるため、データが多いほど同じ平均が説得力を持ちます。すべてのリターンを定数倍しても平均と標準誤差が同じだけ変わるので t は変わりません。経験則として、|t| が2を超えれば偶然とは考えにくくなります。

import math
import numpy as np

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

n = len(returns)
mean = returns.mean()
std_error = returns.std(ddof=1) / math.sqrt(n)         # the uncertainty of the mean
t = mean / std_error                                   # testing against mu0 = 0

print(round(mean, 5), round(std_error, 6))             # 0.00142 0.000892   the mean is only 1.6 standard errors from 0
print(round(t, 3))                                     # 1.589

t から p 値へ

帰無仮説の下で、標本が大きければ t は標準正規分布のように振る舞うので、両側p値は0から |t| より離れる確率(どちら向きでも)で、erfc(|t| / sqrt(2)) です。t = 1.59 なら11%で、これほど良い結果は偶然でも9回に1回起こり、本物の優位性があるとは言えません。通常の基準は5%(|t| = 1.96)です。小さな標本の本来の基準は裾の厚いスチューデントのt分布なので、正規分布のp値はやや小さすぎます。30点未満なら本物のt表を使いましょう。

p_value = math.erfc(abs(t) / math.sqrt(2))
print(round(p_value, 4))                      # 0.1121   an outcome this good happens by chance about 1 time in 9

print(round(math.erfc(1.96 / math.sqrt(2)), 4))   # 0.05     |t| = 1.96 is the usual 5% limit

# Testing against another value: is the mean different from 0.2% a day?
t_other = (mean - 0.002) / std_error
print(round(t_other, 3), round(math.erfc(abs(t_other) / math.sqrt(2)), 3))   # -0.654 0.513

信頼区間と対応のある標本

信頼区間は、はい/いいえの検定より多くを語ります。平均 -/+ 1.96 * 標準誤差 は真の平均を約95%の確率で含む範囲です。区間に0が含まれれば、平均は5%水準で有意ではありません。ここでの区間は日次 -0.03%〜+0.32% で、ゼロをまたぎ、平均に比べて広くなっています。同じ日に測った2つの戦略を比べるには、日次の差を0と検定します。対にすることで、両者が共有するノイズ(市場の良い日と悪い日)が消え、別々に2回検定するよりずっと鋭く優位性を検出できます。

low, high = mean - 1.96 * std_error, mean + 1.96 * std_error
print(round(low, 5), round(high, 5))           # -0.00033 0.00316   the interval contains 0: not significant at 5%

# Paired: the same six days for two strategies
a = np.array([0.004, -0.002, 0.001, 0.003, -0.004, 0.002])
b = np.array([0.002, -0.003, 0.000, 0.001, -0.002, 0.0])
d = a - b
t_paired = d.mean() / (d.std(ddof=1) / math.sqrt(len(d)))
print(round(d.mean(), 5), round(t_paired, 3))   # 0.001 1.581   a daily edge of 0.1%, but only 6 days
# Same mean and spread, four times the data: t doubles and the p-value collapses
spread = returns.std(ddof=1)
for n in (12, 48):
    t_n = mean / (spread / math.sqrt(n))
    print(n, round(t_n, 3), round(math.erfc(abs(t_n) / math.sqrt(2)), 4))
# 12 1.589 0.1121
# 48 3.178 0.0015
有意であることは重要を意味せず、多くの検定は不正になるごくわずかな優位性でもデータが十分あれば非常に有意になり、大きな優位性でもデータが少なければ有意になりません。p値と並べて効果の大きさを必ず読みましょう。また100個の戦略を検定すれば、運だけで約5個が5%水準を通過します。同じデータで試す変種が多いほど、単独のp値の意味は薄れます。
  • t = (mean - mu0) / (s / sqrt(n)):平均を標準誤差 s / sqrt(n) 単位で表す。データが多いほど |t| は大きい
  • 両側p値は大標本で erfc(|t| / sqrt(2))。|t| > 1.96 なら p < 5%、区間 mean -/+ 1.96 * se が0を含めば有意でない
  • 同じ日の戦略は日次の差のt統計量で比べる。多くの変種を検定することには注意

次は線形回帰(OLS)です。あるリターンを別のリターンで説明する直線をあてはめます。

ラボ:採点される内容

  • t_statistic で平均をそのノイズ単位で測る25点
  • two_sided_p で t を p 値に変換する25点
  • confidence_interval で真の平均を区間で囲む25点
  • paired_t_statistic で2つの戦略を日ごとに比べる25点
エクスプローラー · lab-57-1
▾ lab-57-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-57-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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