インデックスを超えていけ ~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 |

目次
- 理論的背景:レジームスイッチングモデル
- Hidden Markov Modelの基礎
- 実装:バイアスフリーな設計
- 改善1:レバレッジオーバーレイ
- 改善2:マルチシグナル検出
- 改善の相互作用分析
- うまくいかなかった改善とその理由
- さらなる改善のヒント
- 最終結果と考察
- 実装コードと再現手順
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には以下の利点があります:
- 潜在状態の推定: 観測可能な変数(VIX変化率)から、直接観測できない「市場状態」を推定
- 確率的遷移: レジーム間の切り替えを確率的にモデル化
- ノイズ耐性: 単純な閾値ルールより偽シグナルに強い
2. Hidden Markov Modelの基礎
2.1 モデルの構成要素
HMMは以下の要素で定義されます:
| 記号 | 意味 | 本戦略での解釈 |
|---|---|---|
| 状態空間 | Low Vol, High Vol | |
| 状態遷移確率行列 | ||
| 放出確率分布 | 各状態でのVIX変化率の分布(ガウス分布) | |
| 初期状態確率 |
2.2 ガウシアンHMM
本戦略では、各状態の放出確率分布をガウス分布でモデル化します:
ここで
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アルゴリズム
学習済みモデルから最も確からしい状態系列を求めます:
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つの重要な特性があります:
- リスク調整後リターンが高い: Sharpe比がHigh Vol期間より優れている
- 低いボラティリティ: 同じレバレッジでも実現リスクが低い
この特性を活用し、レジームに応じてレバレッジを動的に調整します。
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) は、リスクオフ時に株式より先に反応する傾向があります:
- 機関投資家の行動: リスク回避時、まずクレジット市場から資金を引き上げる
- 流動性の違い: ハイイールド債は株式より流動性が低く、売り圧力が価格に反映されやすい
- 先行指標性: 「炭鉱のカナリア」として機能
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」になるのか:
- レバレッジ効率の向上: マルチシグナルによりLow Vol期間の判定精度が上がる → レバレッジの「当たり率」が向上
- High Vol時の二重防御: クレジットシグナルでの早期撤退 + 0.5xレバで損失を最小化
- ドローダウンの相殺: マルチシグナルで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 | ❌ 低下 |
なぜ悪化するのか:
- Momentumの遅延: 200日MAは反応が遅すぎる
- シグナル過剰: High Vol判定が増えすぎ、リターン機会を逃す
- 多数決の弊害: 「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を上回れるのか
- 動的リスク配分: 市場状態に応じてリスクエクスポージャーを調整
- マルチアセット: SPY/TLT/GLDの分散効果
- 先行シグナル: クレジット市場の早期警戒機能
- レバレッジ効率: 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ベースのレジームスイッチング戦略を以下のステップで構築しました:
- 基礎実装: バイアスフリーなExpanding Window方式(Sharpe 0.753)
- レバレッジオーバーレイ: +13.8%のSharpe改善(コストあり、オプション)
- マルチシグナル検出: +14.3%のSharpe改善(コストなし、必須)
- 相互作用: +4.7%の追加改善
レバレッジを使わなくてもSharpe 0.861(SPY比+67%)を達成可能であり、レバレッジ併用でSharpe 0.999(SPY比+94%)まで向上します。
Discussion