Skip to content
Go back

市場レジーム自動識別:ADXとVIXのマトリクスでエントリー閾値を動的制御する

Edit page

「勝率65%のストラテジーが、ある月だけ30%に急落する」——この現象の原因は、市場レジーム(相場環境の状態)の変化にある。トレンドフォロー戦略はレンジ相場で機能しないし、レンジ逆張りはトレンド相場で大損する。

固定の閾値でエントリー判定を続けると、相場環境に合わない局面でも同じ頻度で取引してしまう。これを解決するために、ADX(Average Directional Index)とVIX(恐怖指数)を組み合わせた「VIXフェーズマトリクス」を実装し、相場環境に応じてエントリー閾値を動的に変化させる仕組みを構築した。143テスト全PASSで本番稼働中だ。


市場レジームとは何か

市場レジーム(Market Regime)とは、相場がどのような「状態」にあるかを分類したものだ。大きく分けると以下の4つに分類できる。

レジーム特徴トレンドフォローの有効性
強トレンドADX > 30、方向が明確非常に高い
弱トレンドADX 20〜30、方向が曖昧中程度
レンジADX < 20、方向感なし低い(逆効果の場合も)
高ボラティリティVIX > 30、急激な値動き予測困難(リスク過大)

同じ「RSIが30以下で買い」というシグナルでも、強トレンド中のRSI30は押し目買いのチャンスだが、高ボラティリティ環境のRSI30はさらなる暴落の入口かもしれない。


ADXベースのフェーズ分類

ADX(Average Directional Index)とは

ADXはトレンドの「強さ」を0〜100で数値化する指標だ。方向(上昇か下降か)は示さず、純粋にトレンドの強度だけを測る。

3フェーズ分類

ADXの値に基づいて相場を3フェーズに分類した。

def classify_market_phase(adx: float) -> str:
    if adx >= 30:
        return "TRENDING"        # トレンド相場
    elif adx >= 20:
        return "TRANSITIONING"   # 過渡期
    else:
        return "RANGING"         # レンジ相場

各フェーズに対して min_total_score(エントリーに必要な最低スコア)の乗数を設定する。

PHASE_SCORE_MULTIPLIERS = {
    "TRENDING":      1.0,   # 通常通り(トレンドフォローが有効)
    "TRANSITIONING": 1.3,   # 30%引き上げ(慎重に)
    "RANGING":       1.8,   # 80%引き上げ(非常に強いシグナルのみ)
}

VIXとの組み合わせ:VIXフェーズマトリクス

ADXだけでは「ボラティリティの水準」が分からない。ADXが30(トレンド中)でも、VIXが50(極端な恐怖)の局面ではリスクが全く違う。

VIX(Volatility Index、恐怖指数)は、S&P500オプションの予想変動率から算出される指標で、市場参加者の「恐怖度」を数値化したものだ。

マトリクス設計

ADX(3段階)× VIX(4段階)= 12通りの相場状態を定義し、それぞれにスコア乗数を割り当てた。

              VIX Low    VIX Normal   VIX High    VIX Extreme
             (<20)       (20-30)      (30-50)     (>50)
TRENDING     1.0 ★       1.0          1.5         999.9
TRANSITION   1.3          1.5          2.0         999.9
RANGING      1.8          2.0          999.9       999.9

VIX取得の3層フォールバック

VIX値の取得は外部API依存のため、経済指標フィルター(FX-ADD-D2)と同じ設計思想で3層フォールバックを実装した。

Layer 1: Alpha Vantage API(15分キャッシュ)
    ↓ 失敗
Layer 2: Yahoo Finance API
    ↓ 失敗
Layer 3: ATR推定値(ローカルParquetファイルから計算)

VIX取得に全層失敗した場合は「VIX Normal」(20〜30)をデフォルト値として使用し、フィルターの動作を継続する。


シグナル評価フローへの統合

既存のエントリー判定フローへの変更は最小限に抑えた。

変更前:
  min_total_score = config["min_total_score"]  # 固定値(例: 1.9)
  → should_entry(indicators, min_total_score)

変更後:
  base_score = config["min_total_score"]        # ベース値(例: 1.9)
  phase = classify_market_phase(adx_value)       # ADXでフェーズ判定
  vix_profile = get_vix_profile(current_vix)     # VIXプロファイル取得
  multiplier = VIX_PHASE_MATRIX[phase][vix_profile]  # マトリクスから乗数
  dynamic_min_score = base_score * multiplier    # 動的閾値
  → should_entry(indicators, dynamic_min_score)

追加したのは「動的乗数の取得と適用」だけ。UnifiedSignalEvaluator(シグナル評価器)本体のコードは変更していない。


バックテストでの検証

マトリクスのパラメータは勘ではなく、バックテストのグリッドサーチで最適化した。

ADXの閾値(20/25/30)、VIXの閾値区分、各セルの乗数を変化させて、以下の指標を最適化対象とした。

結果

マトリクス適用前後で、EUR_JPY + GBP_JPYの2ペアにおいて:

トレード数は減るが、1トレードあたりの質が上がる。これは意図した挙動だ。


学んだこと

1. 相場環境を無視した固定閾値は時限爆弾

「勝率65%」はあくまで全期間の平均だ。レンジ相場だけを切り出すと30%以下ということもある。固定閾値は「良い環境でも悪い環境でも同じ基準でトレードする」ことを意味し、これは自ら不利な状況に飛び込む行為だ。

2. マトリクスは直感的で保守しやすい

「ADX×VIX」の2軸マトリクスは、12セルの表として一覧できる。機械学習モデルのブラックボックスと違い、「なぜこの局面でエントリーしなかったか」が即座に説明できる。運用中のチューニングも、セルの値を変えるだけで済む。

3. VIX取得のフォールバックは必須

VIXは外部APIでしか取得できない。APIが落ちたら市場レジーム判定ができなくなるのは致命的だ。ローカルデータからのATR推定値を最終手段として持っておくことで、完全なオフライン耐性を確保した。


まとめ

市場レジーム自動識別の設計で重要なのは以下の3点だ。

  1. ADX×VIXの2軸マトリクス: 12通りの相場状態に対して個別にエントリー閾値を設定。直感的で保守しやすい
  2. 乗数方式での統合: 既存のシグナル評価器を変更せず、閾値に乗数を掛けるだけで動的制御を実現
  3. 3層フォールバック: VIX取得の信頼性を確保し、API障害時もフィルターが機能し続ける

「相場環境に合わせてトレード頻度を変える」のは、裁量トレーダーが自然にやっていることだ。それをルールベースでシステムに組み込むことが、市場レジームフィルターの本質だ。


Edit page
Share this post on:

Previous Post
日本株の倒産リスクをシステマティックに管理する:定量的アプローチ
Next Post
月次目標逆算型ロット最適化:scipyの2段階最適化で全ペアのロットを自動配分