🐾

インデックスを超えていけ ~Hidden Markov Modelとマルチシグナル検出による戦術的アセットアロケーション~

に公開

はじめに

「市場には異なる状態(レジーム)が存在し、それぞれで最適な資産配分が異なる」

この直感的なアイデアを Hidden Markov Model (HMM) を用いて定量化し、S&P500を大幅に上回るポートフォリオ戦略を構築する方法を解説します。

本記事で構築する最終戦略のパフォーマンス:

指標 最終戦略 S&P500 優位性
Sharpe Ratio 0.999 0.515 +94%
累積リターン 1,148% 368% +212%
Max Drawdown -27.3% -59.6% +32pt

最終戦略のパフォーマンス


目次

  1. 理論的背景:レジームスイッチングモデル
  2. Hidden Markov Modelの基礎
  3. 実装:バイアスフリーな設計
  4. 改善1:レバレッジオーバーレイ
  5. 改善2:マルチシグナル検出
  6. 改善の相互作用分析
  7. うまくいかなかった改善とその理由
  8. さらなる改善のヒント
  9. 最終結果と考察
  10. 実装コードと再現手順

1. 理論的背景:レジームスイッチングモデル

1.1 市場レジームとは

金融市場は常に同じ確率過程に従っているわけではありません。以下のような異なる「状態」を行き来していると考えられています:

レジーム 特徴 代表的な期間
Low Volatility 安定した上昇トレンド、低VIX 2013-2014, 2017, 2021
High Volatility 急落・乱高下、高VIX 2008-2009, 2020年3月, 2022

1.2 戦略の基本アイデア

If レジーム == Low Vol:
    → リスク資産(株式)を多く保有
    → レバレッジを活用

If レジーム == High Vol:
    → 安全資産(債券・金)にシフト
    → ポジションを縮小

この単純なルールをデータドリブンで実装するのが本戦略の核心です。

1.3 なぜHMMを使うのか

レジームの判定には様々な手法がありますが、HMMには以下の利点があります:

  1. 潜在状態の推定: 観測可能な変数(VIX変化率)から、直接観測できない「市場状態」を推定
  2. 確率的遷移: レジーム間の切り替えを確率的にモデル化
  3. ノイズ耐性: 単純な閾値ルールより偽シグナルに強い

2. Hidden Markov Modelの基礎

2.1 モデルの構成要素

HMMは以下の要素で定義されます:

\lambda = (A, B, \pi)
記号 意味 本戦略での解釈
S = \{s_1, s_2\} 状態空間 Low Vol, High Vol
A 状態遷移確率行列 a_{ij} = P(q_{t+1}=s_j \mid q_t=s_i)
B 放出確率分布 各状態でのVIX変化率の分布(ガウス分布)
\pi 初期状態確率 \pi_i = P(q_1 = s_i)

2.2 ガウシアンHMM

本戦略では、各状態の放出確率分布をガウス分布でモデル化します:

b_i(o_t) = \mathcal{N}(o_t \mid \mu_i, \sigma_i^2)

ここで o_t は時刻 t のVIX変化率です。

2.3 パラメータ推定:Baum-Welchアルゴリズム

HMMのパラメータはExpectation-Maximization (EM)の一種であるBaum-Welchアルゴリズムで推定します:

from hmmlearn import hmm

model = hmm.GaussianHMM(n_components=2, covariance_type="full")
model.fit(vix_changes)  # EMアルゴリズムでパラメータ推定

2.4 状態系列の復号:Viterbiアルゴリズム

学習済みモデルから最も確からしい状態系列を求めます:

Q^* = \arg\max_Q P(Q \mid O, \lambda)
states = model.predict(vix_changes)  # Viterbiで状態系列を復号

3. 実装:バイアスフリーな設計

3.1 バックテストにおける先読みバイアス

金融バックテストで最も注意すべきは先読みバイアス(Look-Ahead Bias)です。

⚠️ 先読みバイアスとは
時刻 t の意思決定に、時刻 t+1 以降の情報を使ってしまうこと

3.2 Expanding Window方式

バイアスを除去するため、Expanding Window(拡張ウィンドウ) 方式を採用します:

def detect_regimes_expanding(vix_changes, refit_frequency=252):
    """
    Walk-forward方式でHMMをフィット
    - 時刻tでは、時刻0〜t-1のデータのみを使用
    - 年1回(252日ごと)にモデルを再学習
    """
    regimes = []
    current_model = None
    
    for t in range(len(vix_changes)):
        # 年次でモデルを再学習(過去データのみ使用)
        if t % refit_frequency == 0 and t >= 252:
            historical_data = vix_changes[:t]  # ここがポイント
            current_model = GaussianHMM(n_components=2)
            current_model.fit(historical_data)
        
        # 現在のモデルで状態を予測
        if current_model:
            state = current_model.predict(vix_changes[t:t+1])
            regimes.append(state[0])
    
    return regimes

3.3 アロケーション最適化もExpanding Window

レジームごとの最適配分も、同様にExpanding Window方式で計算します:

def calculate_allocation_expanding(regimes, returns, rebalance_freq=252):
    """
    時刻tのアロケーションは、時刻0〜t-1のデータのみで最適化
    """
    for t in range(min_history, len(returns)):
        if t % rebalance_freq == 0:
            historical_regimes = regimes[:t]
            historical_returns = returns[:t]
            
            # 過去データのみでSharpe最大化ウェイトを計算
            for regime in [0, 1]:
                mask = historical_regimes == regime
                regime_returns = historical_returns[mask]
                optimal_weights[regime] = maximize_sharpe(regime_returns)

3.4 実行ラグの適用

現実のトレーディングでは、シグナル確認から執行まで時間がかかります:

# 1日の実行ラグを適用
weights_lagged = weights.shift(1)  # t日のシグナル → t+1日に執行

3.5 ベースラインの結果

バイアスフリーな実装のベースライン結果:

指標 結果 vs SPY
Sharpe 0.753 +46%
Return 323% -12%
Max DD -27.7% +32pt

ここからさらに改善を重ねていきます。


4. 改善1:レバレッジオーバーレイ

4.1 なぜレバレッジなのか

Low Volatility期間には2つの重要な特性があります:

  1. リスク調整後リターンが高い: Sharpe比がHigh Vol期間より優れている
  2. 低いボラティリティ: 同じレバレッジでも実現リスクが低い

この特性を活用し、レジームに応じてレバレッジを動的に調整します。

r_{leveraged} = L_{regime} \times r_{base}

4.2 レバレッジ設定の選択

設定 Low Vol High Vol 理由
Conservative 1.3x 0.7x 安定志向
Moderate 1.5x 0.5x バランス良好
Aggressive 2.0x 0.3x 高リスク・高リターン

Moderate設定を選択した理由:

  • Aggressiveはドローダウンが-66%に悪化
  • Conservativeは改善幅が小さい
  • ModerateはSharpe改善とDD悪化のバランスが最適

4.3 実装

def apply_leverage_overlay(returns, regimes, low_lev=1.5, high_lev=0.5):
    leverage = pd.Series(index=returns.index)
    
    lagged_regimes = regimes.shift(1)  # 前日のレジームを使用
    
    leverage[lagged_regimes == 0] = low_lev   # Low Vol
    leverage[lagged_regimes == 1] = high_lev  # High Vol
    
    return returns * leverage

4.4 レバレッジのコストについて

実運用でのレバレッジにはコストがあります:

コスト要因 推定影響
金利(借入コスト) -0.5~1.0%/年
先物ロールコスト -0.1~0.3%/年
リバランスコスト 取引頻度に依存

重要: レバレッジなしでも、後述するマルチシグナル検出だけでSharpe 0.861を達成可能です。レバレッジはオプションです。

4.5 結果

レバレッジオーバーレイ比較

設定 Sharpe 累積リターン Max DD
Baseline (1x/1x) 0.753 323% -27.7%
Moderate (1.5x/0.5x) 0.856 897% -38.7%

Sharpe比 +13.8%の改善を達成。


5. 改善2:マルチシグナル検出

5.1 VIX単独の限界

VIXのみでレジームを判定すると、以下の問題があります:

問題 詳細
遅延 VIXは通常、株価下落の後に上昇する
ノイズ 短期的なスパイクで偽シグナル発生
非対称性 回復局面の検出が遅れる

5.2 追加シグナルの選定理由

シグナル 計算方法 なぜ効くのか
VIX HMM 前述のGaussian HMM ボラティリティクラスタリングを捕捉
SPY Momentum SPY > 200日移動平均 長期トレンドの確認、遅延が欠点
Credit Signal HYG > 50日移動平均 株式より先に動く傾向がある

5.3 なぜクレジットシグナルが効くのか

HYG(ハイイールド債ETF) は、リスクオフ時に株式より先に反応する傾向があります:

  1. 機関投資家の行動: リスク回避時、まずクレジット市場から資金を引き上げる
  2. 流動性の違い: ハイイールド債は株式より流動性が低く、売り圧力が価格に反映されやすい
  3. 先行指標性: 「炭鉱のカナリア」として機能
def create_credit_signal(hyg_prices):
    """HYGが50日MAを下回る = クレジットストレス"""
    ma50 = hyg_prices.rolling(50).mean()
    return (hyg_prices > ma50).astype(int)

5.4 VIX + Credit シグナルの組み合わせ

def create_multi_signal_regime(vix_regime, credit_signal):
    """
    VIXがLow Vol判定でも、クレジットがストレス状態なら
    High Volとしてリスクオフ
    """
    combined = vix_regime.copy()
    
    # クレジットストレス時は強制的にHigh Vol
    credit_stress = credit_signal == 0
    combined[credit_stress] = 1
    
    return combined

この「OR条件」によるリスクオフは、**偽陽性(過剰なリスク回避)を許容しつつ偽陰性(リスクオン時の急落)**を防ぐ設計です。

5.5 レバレッジなしの結果

レバレッジコストを避けたい場合、マルチシグナルだけでも十分な改善が得られます:

設定 Sharpe Return Max DD
Baseline 0.753 323% -27.7%
Multi-Signal only 0.861 642% -34.7%
SPY 0.515 368% -59.6%

レバレッジなしでもSPYをSharpe比で67%上回ります。

5.6 レバレッジ併用の結果

マルチシグナル比較

手法 Sharpe Return Max DD
VIX Only + Leverage 0.856 897% -38.7%
Multi-Signal only 0.861 642% -34.7%
Multi-Signal + Leverage 0.999 1,148% -27.3%

6. 改善の相互作用分析

6.1 改善効果は単純に積み重なるのか?

改善効果の加法性を検証しました:

改善 単独効果 (Sharpe改善率)
レバレッジのみ +13.8%
マルチシグナルのみ +14.3%
両方 +32.7%
加法的予測 +28.1%
相互作用効果 +4.7%

6.2 正の相互作用が生まれる理由

なぜ「1+1 > 2」になるのか:

  1. レバレッジ効率の向上: マルチシグナルによりLow Vol期間の判定精度が上がる → レバレッジの「当たり率」が向上
  2. High Vol時の二重防御: クレジットシグナルでの早期撤退 + 0.5xレバで損失を最小化
  3. ドローダウンの相殺: マルチシグナルでDD改善 → レバレッジによるDD悪化を打ち消す

6.3 最適な組み合わせ

         ┌─────────────────────────────────────────┐
         │ Sharpe       Return      Max DD        │
         ├─────────────────────────────────────────┤
Baseline │ 0.753        323%        -27.7%        │
         │      ↓ +13.8%                          │
+Lev     │ 0.856        897%        -38.7%        │
         │      ↓ +16.7%                          │
+Multi   │ 0.999       1,148%       -27.3% ←最適  │
         └─────────────────────────────────────────┘

7. うまくいかなかった改善とその理由

7.1 3シグナル統合(Combined)

VIX + Momentum + Credit の3シグナルを統合したケース:

手法 Sharpe 問題点
VIX + Credit 0.999 ✅ 最適
Combined (3 signals) 0.840 ❌ 低下

なぜ悪化するのか:

  1. Momentumの遅延: 200日MAは反応が遅すぎる
  2. シグナル過剰: High Vol判定が増えすぎ、リターン機会を逃す
  3. 多数決の弊害: 「2/3以上」ルールがノイズを増幅

7.2 Aggressive レバレッジ(2.0x/0.3x)

設定 Sharpe Max DD 問題点
Moderate 0.999 -27.3% ✅ バランス良好
Aggressive 1.02 -66.1% ❌ DD悪化が致命的

Sharpeはわずかに向上するが、-66%のドローダウンは実運用に耐えられません。

7.3 学んだ教訓

教訓 内容
シンプルさ 2シグナルで十分、過剰な複雑化は逆効果
リスク管理 Sharpe最大化だけでなくDD制約も重要
先行性 遅延の大きいシグナル(Momentum)は慎重に

8. さらなる改善のヒント

本戦略をさらに発展させたい方へのヒント:

8.1 シグナルの多様化

候補シグナル 理論的根拠
銅/金レシオ 景気先行指標
イールドカーブ リセッション予測
オプションスキュー テールリスク期待
資金フロー ETFへの資金流入出

8.2 アセットの拡張

現在の3アセット(SPY/TLT/GLD)から拡張:

追加アセット 期待効果
TIPS インフレヘッジ
IEMG 新興国分散
QQQ グロース傾斜
コモディティ オルタナティブ

8.3 リバランス頻度の最適化

# 現在: 日次リバランス
# 検討: 週次 or 月次でターンオーバー削減
rebalance_frequency = 5  # 週次

8.4 機械学習の活用

手法 適用箇所
Random Forest レジーム分類
LSTM シーケンス予測
強化学習 動的レバレッジ最適化

9. 最終結果と考察

9.1 最終パフォーマンス

最終戦略のパフォーマンス

指標 Baseline Final 改善率 vs SPY
Sharpe Ratio 0.753 0.999 +32.7% +94%
累積リターン 323% 1,148% +255% +212%
年間リターン 7.1% 12.8% +80% +57%
Max Drawdown -27.7% -27.3% +0.4pt +32pt

9.2 改善の貢献度

改善 Sharpe貢献 備考
バイアスフリー設計 (基盤) 全ての土台
レバレッジオーバーレイ +13.8% コストあり(オプション)
マルチシグナル検出 +14.3% コストなし(必須)
相互作用効果 +4.7% シナジー

9.3 なぜS&P500を上回れるのか

  1. 動的リスク配分: 市場状態に応じてリスクエクスポージャーを調整
  2. マルチアセット: SPY/TLT/GLDの分散効果
  3. 先行シグナル: クレジット市場の早期警戒機能
  4. レバレッジ効率: Low Vol期間のSharpe比を活用(オプション)

9.4 注意点と限界

項目 内容
取引コスト 推定0.82%/年(10bps想定)
スリッページ 未考慮(実運用では影響あり)
レジーム変化 将来のレジーム分布が変わる可能性
データ範囲 2004-2026年、他の期間での検証推奨

10. 実装コードと再現手順

10.1 環境構築

# リポジトリのクローン
git clone https://github.com/your-username/Regime-Based-Portfolio-Allocation.git
cd Regime-Based-Portfolio-Allocation

# 依存関係のインストール(uvを使用)
uv sync

10.2 戦略の実行

# 最終戦略の実行
uv run python scripts/final_strategy.py

# テストの実行(11テスト全パス)
uv run pytest tests/ -v

10.3 主要ファイル構成

├── src/
│   ├── regime_detector.py   # HMMレジーム検出(Expanding対応)
│   ├── allocator.py         # 最適配分計算
│   ├── backtest.py          # バックテストエンジン
│   └── metrics.py           # パフォーマンス指標
├── scripts/
│   ├── final_strategy.py    # 🏆 最終戦略
│   ├── test_leverage_overlay.py
│   └── test_multisignal.py

まとめ

本記事では、HMMベースのレジームスイッチング戦略を以下のステップで構築しました:

  1. 基礎実装: バイアスフリーなExpanding Window方式(Sharpe 0.753)
  2. レバレッジオーバーレイ: +13.8%のSharpe改善(コストあり、オプション)
  3. マルチシグナル検出: +14.3%のSharpe改善(コストなし、必須)
  4. 相互作用: +4.7%の追加改善

レバレッジを使わなくてもSharpe 0.861(SPY比+67%)を達成可能であり、レバレッジ併用でSharpe 0.999(SPY比+94%)まで向上します。

Discussion