【FX自動売買開発ログ #15】流動性フィルターを作ったら、また「該当件数が少なすぎ」問題にぶつかった話
前回のおさらい
前回、regime_filterにクロスアセット情報(DXY・US10Y)を追加したv2を作り、v1と比較しました。除外数は減ったのに勝率はむしろ上がるという、「穏やかで的確なフィルター」になったことが確認できています。
今回は方向を変えて、2つの新しい施策を並行で実装します。時間帯・曜日に基づく機械的な流動性フィルターと、上位足(4時間足)の環境認識を行うマルチタイムフレーム理論(theory_mtf.py)です。
実装は並行、検証は個別に
2つの施策を同時に作るにあたって、あらかじめ指定した条件が一つありました。実装(コードを書く作業)は並行で進めて構わないが、検証(バックテストで効果を見る作業)は必ず個別に行うこと、という条件です。
- まず流動性フィルターのみ適用した場合の効果を確認する
- 次にtheory_mtfのみ追加した場合の効果を確認する
- 両方が個別に効果を確認できてから、初めて両方同時に使った場合を試す
2つを同時に組み込んで「なんとなく良くなった」という結果を見ても、どちらが効いているのか切り分けられなくなってしまいます。この順番を守れば実装のスピード自体は落とさなくて大丈夫、という前提で進めました。

2つの設計方針
- liquidity_filter.py:時間帯・曜日に基づく機械的フィルター(AIを使わない固定ルール)。NY引け後〜アジア立ち上がり前(UTC 21-23時)や金曜深夜など、流動性が薄い時間帯の新規エントリーを見送る設計です。「リスク管理はAIに判断させない」という既存の方針とも整合します。API呼び出しが不要なので、実装後すぐに検証できます。
- theory_mtf.py:4時間足を使った上位足トレンド判定の新理論。1h側の合成シグナルが上位足トレンドと逆行する場合にエントリーを見送る、regime_filterと同様の「拒否権」方式で統合します。投票方式(案A)はすでに拒否権として機能しないことが分かっているため、最初から拒否権方式(案B)で組みます。
両方のコードを実装し、まず流動性フィルターの検証から進めました。
流動性フィルターの効果、ほぼ横ばい
ダウ理論+プライスアクションのみ(regime_filterなし)の素の2理論アンサンブルに対して、流動性フィルターを適用した結果です。API呼び出しは不要なので、これも0回で確認できています。
| 設定 | 収益%(な→あ) | 勝率%(な→あ) | DD%(な→あ) | n(な→あ) |
|---|---|---|---|---|
| (1,≥50) | 5.29→5.28 | 35.53→35.06 | -6.61→-6.79 | 76→77 |
| (1,≥60) | 1.72→1.68 | 35.06→34.62 | -5.68→-5.86 | 77→78 |
| (1,≥70) | 1.52→1.64 | 38.89→33.33 | -2.07→-2.07(不変) | 18→18 |
| (2,≥50) | 4.32→4.26 | 34.25→33.78 | -5.97→-6.15 | 73→74 |
| (2,≥60) | 2.95→2.89 | 34.72→34.25 | -5.45→-5.63 | 72→73 |
| (2,≥70) | 1.52→1.64 | 38.89→33.33 | -2.07→-2.07(不変) | 18→18 |
ほぼ全設定で横ばい、というより微妙に悪化している設定の方が多いくらいで、期待していたような効果は見られませんでした。

またしても「該当件数が少なすぎる」
結果を見て、まずトリガー件数のうちどれくらいがこの時間帯に該当していたかを確認しました。216件中わずか15件(6.9%)しか該当時間帯に入っておらず、ADX<20フィルターのときと同じ構造的な問題が起きていることが分かりました。フィルターがほとんど発動する機会がなかったため、効果がほぼ横ばいになるのは当然の結果だった、というわけです。

理論的に選んだ除外時間帯(UTC 21-23時、NY引け後〜アジア立ち上がり前)が、実際のトリガー発生パターンとあまり重なっていなかった、ということになります。一方で、以前の事後分析コーチのレビューでは「03:00〜06:00台のエントリーで損切り決済になっている例が複数ある」という、実データに基づいた具体的な時間帯の指摘がありました。理論的な時間帯ではなく、実際の負けトレードで観察された時間帯を除外時間帯として試す方が、データドリブンで筋が良いのではないか、という案も浮かびました。
ただし、これは慎重に扱うべき提案でした。事後分析コーチが同じデータから抽出した時間帯を、同じデータへのフィルター条件として使うのは、いわば「答えを見てから問題を作る」ような循環リスクがあります。見かけ上の効果は出るかもしれませんが、それが本当に汎化する規則性なのか、単にこのデータセットにたまたま存在したパターンをなぞっているだけなのかを区別できません。
この03-06時UTCでの検証は行わないことにし、「単純な時間帯・閾値フィルター(ADX<20、UTC21-23時)は、これまで2回とも該当件数が少なすぎて効果を測れないという結果に終わっている。これはトリガー自体の発生条件(SMAクロス・ブレイクアウト)が、既にある程度これらの極端な状況を避ける形になっている可能性を示唆する」という総括をCLAUDE.mdに記録し、流動性フィルターはいったん保留としました。
次回予告
流動性フィルターは保留になりましたが、もう一つの施策であるMTF理論(theory_mtf.py)はまだ検証していません。次回は、こちらの拒否権の発動頻度をシミュレーションし、実際にAPIを呼んで効果を確認します。
※本シリーズは個人の技術検証・学習を目的とした開発記録であり、特定の投資手法や金融商品を推奨するものではありません。自動売買には元本割れのリスクがあり、掲載する内容を参考にした取引の結果について一切の責任を負いかねます。投資判断はご自身の責任で行ってください。

