English Deutsch
preview
MQL5標準ライブラリエクスプローラー(第6回):生成されたエキスパートアドバイザーの最適化

MQL5標準ライブラリエクスプローラー(第6回):生成されたエキスパートアドバイザーの最適化

MetaTrader 5 |
10 0
Clemence Benjamin
Clemence Benjamin


内容


はじめに

MQL5ウィザードを使用して、あるいはゼロから独自にエキスパートアドバイザー(EA)を開発した後、注文が問題なく実行されることを確認すると、大きな達成感を得られるかもしれません。しかし、そのEAをストラテジーテスターで検証すると、現実はしばしば厳しいものです。過大なドローダウン、過剰な売買、不安定な収益性など、期待を下回る結果が現れることは珍しくありません。まさにここで最適化が重要になります。設定値やロジック、各種制約を洗練させることで、EAが本来持つ潜在能力を引き出し、より堅牢で持続可能なパフォーマンスを実現できるようになります。

MQL5開発における最適化とは、一般的にMetaTrader 5のストラテジーテスターを利用し、EAのパラメータを調整するプロセスを指します。シグナル閾値、期間、重み付けなどの入力値の組み合わせを体系的に検証し、純利益、プロフィットファクター、シャープレシオなどを最大化しつつ、最大ドローダウンなどのリスクを最小化する設定を探索します。しかしながら、この定義は定量的なパラメータ調整に重点を置いています。本来の意味での最適化は、それだけに留まりません。本稿で取り上げる時間ベースフィルタのような構造的およびシステム的な改善も含まれます。こうした手法は、ノイズへの過剰反応といった根本的な問題を解決し、単なる過去データへのカーブフィッティングではなく、実市場への適応力を高める役割を果たします。

第5回でMQL5ウィザードを使用してマルチシグナルEAを構築した内容を直接引き継ぎ、本稿では最適化に踏み込みます。初心者の方にとって、第5回で到達した成果は、MQL5標準ライブラリを活用することで、最小限のコーディングによって完全に機能する取引システムを構築できることを示すものだったはずです。しかし、システムの組み立てから実運用に耐え得るレベルへの移行を目指すにあたり、本稿では従来のパラメータ調整から構造的な改善に至るまで、さまざまな最適化手法を検討していきます。特に本記事で主眼を置くのは、体系的かつ構造的な最適化であり、なかでも時間ベースのフィルタを利用して過剰な取引や市場ノイズへの過剰反応を抑制する手法に焦点を当てます。

こうしたコードレベルでの改善を加えたとしても、ストラテジーテスターの重要性は変わりません。ストラテジーテスターを利用することで、変更内容を厳密に検証し、取引回数の減少やエクイティカーブの安定化といった定量的な改善を観察できるだけでなく、修正前のベースラインバックテスト結果と新しい結果を比較することも可能になります。たとえば、時間フィルタの設定を変更し、高ボラティリティとなるロンドン市場とニューヨーク市場の重複時間帯に限定する場合と、比較的静かなアジア時間帯に限定する場合とでは、結果が大きく変化する可能性があります。これは、市場のダイナミクスが時間帯によって変化することを示しており、同時に、カーブフィッティングのような過剰最適化の落とし穴を回避するために、反復的な検証が必要であることを示しています。

最適化におけるその他の重要な考慮事項としては、過剰適合のリスクが挙げられます。これは、EAが過去データ上では優れた成績を示す一方で、特定データへの調整に依存しているために実運用では機能しなくなる現象です。また、ウォークフォワード分析を通じて未知のデータで検証をおこなうアウトオブサンプル検証の重要性や、スリッページ、スプレッド、ニュースイベントといった外部要因に対する感度も考慮しなければなりません。構造的な制御とテスターによるパラメータ調整を組み合わせることで、より堅牢なシステムを構築できます。そして、その過程では常に比較指標によって改善状況を検証し、本当に意味のある改善がおこなわれていることを確認する必要があります。

本記事では、診断から実践的な実装へと自然に移行しながら解説を進めていきます。これにより、ネイティブのフレームワークを捨てることなく、これらの手法を適用できるようになります。

まず最初に明確にしておきたいのは、MetaQuotesが提供しているシグナルモジュールは決して設計が不十分なものではないということです。むしろ、それらは計算効率に優れ、内部的な整合性を備え、明確に定義された市場モデルに基づいて構築されています。各モジュールは価格行動に対する明確な解釈を内包しており、標準化されたインターフェースを通じてシグナル統合プロセスに参加できるようになっています。したがって、私たちが直面している課題は実装品質の問題ではなく、どのような文脈でそれらを運用するかという問題です。

EAを組み立てることから、実運用におけるパフォーマンス改善へと目的が移行した瞬間、より深い理解が不可欠になります。この段階では、ウィザードのインターフェースだけで作業を続けることはもはや十分ではありません。ウィザードはシステム構築において非常に優れていますが、意味のある最適化をおこなうためには、生成されたソースコードを直接扱い、さまざまな市場環境においてシグナルがどのように振る舞うのかを理解する必要があります。

このセクションでは、組み立てから改善および洗練の段階へと焦点を移します。実行ロジックや資金管理をすぐに変更するのではなく、まずシグナルの評価および投票メカニズムそのものに注目します。生成されたアーキテクチャを調査すると、重要な洞察が得られます。パフォーマンス低下の主な原因はシグナルロジックそのものではなく、相場局面の認識や取引頻度の制御といった上位レベルの制約が存在しないことにあります。

デフォルトの投票システムは、シグナルの出力を効率的かつ決定論的に集約します。各シグナルモジュールは内部の市場モデルを評価し、予測の強さを数値化し、重み付き平均を通じて最終判断に寄与します。このプロセスは技術的に健全であり、計算効率の面でも優れています。しかしながら、この仕組みには暗黙の前提が存在します。それは、相場局面、ボラティリティの状態、あるいは直近の取引活動に関係なく、シグナルは継続的に投票へ参加すべきであるという前提です。

実際の運用において、この前提は問題となります。市場はトレンド相場、レンジ相場、高ボラティリティ環境、低活動環境の間を絶えず移行しています。しかし、多くのシグナルモジュールは特定の市場環境下で最も高い性能を発揮するよう設計されています。レジームフィルタが存在しない場合、ある環境では統計的に有効なシグナルが、不適切な環境においても引き続き発生し続けます。同時に、取引頻度に対する制約が存在しないため、実質的に同じ情報の繰り返し確認によって過剰なエントリーが発生することになります。たとえ市場に意味のある新しい情報がまったく現れていなかったとしてもです。

私たちが最初に構築したマルチシグナルEAによって生成されたエクイティカーブは、この制約を明確に示しています。観測された損失は、欠陥のあるインジケータや非効率なコードの結果ではありません。そうではなく、十分な状況判断の仕組みを持たないまま過剰に反応するシステムの結果です。市場ノイズが繰り返し実行可能な情報として扱われることで、過剰売買が発生し、ドローダウンが拡大し、最終的にはエクイティが徐々に損なわれていきます。

したがって、結論はネイティブのシグナルモジュールを置き換えることではありません。それらをより賢く制御し、拡張することにあります。意味のある最適化とは、シグナルがいつ意思決定プロセスへ参加できるのか、どの程度の頻度で売買を実行することができるのか、そしてどの相場局面においてその解釈が有効であり続けるのかを制御することに重点を置くものです。

また、ネイティブのソースファイルを直接変更するのではなく、これらの改善はカスタムシグナルレイヤーを導入することで実現するのが最善です。既存のシグナルロジックの挙動を外部から拡張する方法でも、新しいシグナルモジュールをゼロから開発する方法でも構いません。このアプローチによって、ネイティブライブラリの完全性と信頼性を維持しながら、シグナルの振る舞いを精密に制御できるようになります。

こうした最適化戦略には、以下のようなものがあります。

  • レジーム分類(トレンド、レンジ、ボラティリティ状態)
  • 取引頻度の抑制およびクールダウンロジック
  • 時間、セッション、イベントベースのフィルタリング
  • 適応的な重み付けと条件付きシグナル有効化
  • ネイティブロジックを重複させるのではなく補完することを目的としたカスタムシグナルモジュール

これらのコンテキストレイヤーを適用すると、既存のシグナルモジュールはデフォルトの挙動から想像される以上に優れたパフォーマンスを示すことが少なくありません。

続くセクションでは、生成されたマルチシグナルEAを詳細に検討し、シグナル内部のロジック、EAの入力パラメータ、相場局面フィルタ、そして意思決定レベルの制約に至るまで、複数のレベルで機能する体系的な最適化手法を導入していきます。シグナルを捨てるのではなく、その利用方法を改善することで、堅牢かつ持続可能なパフォーマンス向上へ向けた規律あるアプローチを確立します。ここからは実践的な実装へと進みます。まずは時間ベースのフィルタリングから始め、小規模かつ的を絞ったコード変更によって過剰売買を大幅に削減できること、そしてそれがストラテジーテスターにおけるさらなるパラメータ最適化への土台となることを示していきます。

生成されたマルチシグナルエキスパートアドバイザーの検証

あらゆる複雑な取引システムと同様に、効果的な最適化は問題を観測可能な構成要素へ分解することから始まります。私たちのEAも例外ではありません。不利なエクイティカーブ、不安定なバックテスト結果、そして大量に出力される操作ログは、偶然発生した異常ではありません。それらはすべて、EAの内部ロジックが市場データとどのように相互作用しているかによって直接的に生じる、追跡可能な結果です。実行されたすべての取引、発生したすべてのドローダウン、そして過剰売買のあらゆる事例は、コード内の特定の意思決定経路に起因しています。意味のあるパフォーマンス向上を実現するためには、まず意思決定がどこで形成されているのか、どの程度の頻度で発生しているのか、そしてどのような条件下で実行が許可されているのかを特定しなければなりません。

すべての要素を同時に最適化しようとするのではなく、今回の検証では意図的に意思決定の中核部分、すなわちシグナル評価および投票メカニズムに焦点を当てます。以下のコードスニペットは、ウィザードによって生成されたEAに組み込まれている主要なシグナルモジュールを示しています。

#include <Expert\Signal\SignalFibonacci.mqh>
#include <Expert\Signal\SignalAC.mqh>
#include <Expert\Signal\SignalMA.mqh>
#include <Expert\Signal\SignalRSI.mqh>

SignalFibonacciSignalACSignalMASignalRSIという4つのモジュールは、EAの分析エンジンを構成しています。それぞれが独自の視点から市場データを解釈し、強度を伴う方向性予測を生成し、取引を実行するかどうかを決定する集合的な投票プロセスに貢献します。トレーリングストップや資金管理モジュール(これらについては後の回で取り上げます)のようなコンポーネントは、エントリー判断がすでに下された後の取引結果に影響を与えます。しかし、シグナルそのものが過剰に発生している場合、相場局面と適合しない状況でトリガーされている場合、あるいは同じ情報を冗長に補強している場合には、その後段にある執行ロジックやポジションサイズ調整だけで問題を完全に補うことはできません。したがって、本質的な最適化はここから始めなければなりません。すなわち、シグナルそのもの、その組み合わせロジック、そしてシグナルの参加を制御する管理ルールから着手する必要があります。

この集中的な検証には二つの目的があります。第一に、なぜデフォルト設定のパフォーマンスが低いのかを明らかにすることです。その原因は多くの場合、インジケータ自体に欠陥があるからではなく、市場状況に応じた制約が欠けているためです。第二に、改善のために利用可能な具体的な調整ポイントを特定することです。具体的には、シグナルの重み付け、参加閾値、投票閾値、頻度制御、そして条件付き参加ルールなどが含まれます。これらの要素を体系的に検証し、ストラテジーテスター上で個別の変更がどのような影響を与えるのかを確認することで、改善効果を定量的に評価できます。たとえば、各改善の前後における取引頻度、エクイティカーブの滑らかさ、ドローダウン統計、プロフィットファクターなどを比較することが可能になります。さらに、取引セッションの時間帯やクールダウン期間といったパラメータを変更することで、結果が市場環境にどの程度敏感であるかも確認できます。このことは、構造的なガバナンスと反復的なテスター検証が、規律ある最適化プロセスにおいて切り離せない要素であることを改めて示しています。

以降のサブセクションでは、この意思決定コアの重要な要素を順に分析していきます。

  1. シグナル構成と、それぞれが想定している市場での役割
  2. 重み付け設定と、それがシグナルの支配力に与える影響
  3. シグナル有効化および取引実行を制御する各種閾値
  4. 投票および集約メカニズム(実際のシグナル統合がおこなわれる部分)
  5. 過剰反応の診断指標としての取引頻度の観測

1.  シグナル構成と、それぞれが想定している市場での役割

#include <Expert\Signal\SignalFibonacci.mqh>
#include <Expert\Signal\SignalAC.mqh>
#include <Expert\Signal\SignalMA.mqh>
#include <Expert\Signal\SignalRSI.mqh>

これらのシグナルモジュールは、完成済みのコンポーネントとして提供されているため内部構造が見えにくいものの、決してブラックボックスではありません。それぞれのモジュールは、対応するインジケータの挙動から導き出された特定の市場モデル群を内部に実装しています。そのモデルが何を表現しているのか、どの程度の頻度でシグナルを発生させるのか、そして最終的な投票結果にどの程度の影響力を持つのかを理解することは極めて重要です。こうした理解がないままシグナルを組み合わせると、その作業は情報に基づいたシステム設計ではなく、単なる盲目的なシグナル集約になってしまいます。したがって、最初に検討すべき重要な問いは、それぞれのシグナルがシステム内でどのような役割を担っているのかという点です。

SignalFibonacci

構造重視で、文脈依存性の高いシグナルです。既存の市場構造の中で発生するプルバック、リトレースメント、あるいは平均回帰ゾーンにおいて特に有効性を発揮します。

SignalMA

トレンド指向型のシグナルです。頻繁なエントリーシグナルとして利用するよりも、相場局面の判定や方向性バイアスの把握に適しています。

SignalAC(ACオシレーター)

モメンタムベースのシグナルです。短期的な変化に敏感であり、比較的高い頻度でシグナルを生成する傾向があります。

SignalRSI

オシレーターベースのシグナルです。レンジ相場や低い時間足環境において非常に敏感に反応します。そのため、適切な制約が設けられていない場合、過剰売買を引き起こす主要な要因となりやすいシグナルです。

重要なのは、ウィザードはこれらのシグナルに役割を割り当てているわけではないという点です。ウィザードがおこなうのは、単にそれらを集約することだけです。

2.  重み付け設定と、それがシグナルの支配力に与える影響

input double Signal_Fib_Weight = 1.0;
input double Signal_AC_Weight  = 1.0;
input double Signal_MA_Weight  = 1.0;
input double Signal_RSI_Weight = 1.0;

重みが定義するのは、シグナルの品質ではなく相対的な影響力です。すべての重みを1.0に設定することは、暗黙的に以下の前提を置いていることを意味します。

  • すべてのシグナルが同程度の情報価値を持っている
  • すべてのシグナルがあらゆる相場局面において有効である
  • すべてのシグナルが等しい割合で、かつ継続的に意思決定へ参加すべきである
  • そして、この前提は実際の運用環境ではほとんどの場合成立しない

私たちの検証戦略には、重みの配分を体系的に変更しながら、その影響を観察する作業が含まれます。具体的には、以下の変化を確認します。

  • 取引頻度の変化
  • エクイティカーブの滑らかさの変化
  • ドローダウンの縮小または拡大
  • 操作ログにおけるシグナル支配性の変化

重み付けは、最適化プロセスにおける主要な調整変数の一つとなります。特に、相場局面フィルタや取引頻度制御と組み合わせた場合、その重要性はさらに高まります。

3.  シグナル有効化および取引実行を制御する各種閾値

input int Signal_ThresholdOpen  = 10;
input int Signal_ThresholdClose = 10;

閾値は、実際にアクションを実行する前に、集約された投票結果がどの程度の強さに達していなければならないかを決定します。閾値を低く設定するとシステムの感度は高まりますが、その結果として以下のような問題が発生しやすくなります。

  • 過剰な取引頻度
  • 実際の市場情報ではなくノイズへの反応
  • 取引コストおよびドローダウンの増加

ドキュメントでも示されているように、閾値は単なる見た目上の入力パラメータではありません。閾値はシステム構造そのものを制御する要素です。そのため、私たちの検証では閾値を段階的に変更しながら、以下の項目を観察します。

  • 時間当たりの取引頻度の変化
  • 操作ログ内におけるシグナルの集中発生状況
  • 投票強度と取引結果との関係

4.  投票および集約メカニズム(実際のシグナル統合がおこなわれる部分)

この部分で定義されているのは、単なるシグナルそのものではなく、シグナルの収集および集約の仕組みです。このレベルにおいて、EAは継続的に次の重要な問いに答えています。

「現時点で、どの分析結果を投票対象とするのか。」

したがって、ここでの最適化作業は単なるパラメータ変更に限定されず、以下のような検証も含まれます。
  • 個々のシグナルを一時的に無効化する
  • エクイティおよび取引頻度の変化を観察する
  • オシレーター間に存在する冗長性を評価する
  • 非対称なシグナル構成(例:トレンド系+モメンタム系のみ)をテストする

5. 過剰反応の診断指標としての取引頻度の観測

約5.5時間(00:30~06:05)の観測期間において、このEAは60回を大きく超えるシグナル評価を実行し、6件の市場ポジションを新規にオープンしました。また、同じポジションに対してストップロスや利益目標を数十回にわたって変更しています。シグナルはほぼ5分ごとに発生しており、十分なクールダウン期間や相場局面の検証を伴わないまま、買いと売りの解釈が頻繁に切り替わっていました。このようなシグナル活動の密度は、EAがインジケータの変動を市場コンテキストの一部として扱うのではなく、直接実行すべきイベントとして扱っていることを示しています。

検証のために、市場活動の約5時間分を対象としたストラテジーテスターの操作ログから短い区間を抽出しました。以下に示すログは、その内容を簡潔にするために一部のみを抜粋したものです。

2025.12.20 01:52:26.762 2024.11.07 00:05:00 Long Signal Detected: Pattern 0: Oscillator direction confirmation | RSI: 39.64, Diff: 3.12 | Weight: 70
2025.12.20 01:52:26.767 2024.11.07 00:10:00 Short Signal Detected: Pattern 2: Failed swing | Current RSI: 35.84 < Previous Extremum: 36.52 | Weight: 90
2025.12.20 01:52:26.769 2024.11.07 00:16:00 Short Signal Detected: Pattern 2: Failed swing | Current RSI: 34.29 < Previous Extremum: 36.52 | Weight: 90
2025.12.20 01:52:26.785 2024.11.07 00:20:00 Long Signal Detected: Pattern 0: Oscillator direction confirmation | RSI: 35.99, Diff: 1.70 | Weight: 70
2025.12.20 01:52:26.801 2024.11.07 00:25:00 Long Signal Detected: Pattern 0: Oscillator direction confirmation | RSI: 36.87, Diff: 0.88 | Weight: 70
2025.12.20 01:52:26.801 2024.11.07 00:25:00 position modified [#9152 sell 0.02 EURUSDr 1.07337 sl: 1.07326 tp: 1.06837]
2025.12.20 01:52:26.815 2024.11.07 00:25:00 CTrade::OrderSend: modify position #9152 EURUSDr (sl: 1.07326, tp: 1.06837) [done]
2025.12.20 01:52:26.912 2024.11.07 00:30:00 Long Signal Detected: Pattern 0: Oscillator direction confirmation | RSI: 37.80, Diff: 0.92 | Weight: 70
2025.12.20 01:52:26.912 2024.11.07 00:30:00 position modified [#9152 sell 0.02 EURUSDr 1.07337 sl: 1.07322 tp: 1.06837]
2025.12.20 01:52:26.926 2024.11.07 00:30:00 CTrade::OrderSend: modify position #9152 EURUSDr (sl: 1.07322, tp: 1.06837) [done]
2025.12.20 01:52:26.992 2024.11.07 00:35:00 Short Signal Detected: Pattern 0: Oscillator direction confirmation | RSI: 34.54, Diff: -3.26 | Weight: 70
2025.12.20 01:52:27.022 2024.11.07 00:40:00 Long Signal Detected: Pattern 0: Oscillator direction confirmation | RSI: 36.50, Diff: 1.96 | Weight: 70
2025.12.20 01:52:27.022 2024.11.07 00:40:00 position modified [#9152 sell 0.02 EURUSDr 1.07337 sl: 1.07316 tp: 1.06837]
2025.12.20 01:52:27.038 2024.11.07 00:40:00 CTrade::OrderSend: modify position #9152 EURUSDr (sl: 1.07316, tp: 1.06837) [done]
2025.12.20 01:52:27.070 2024.11.07 00:45:00 Long Signal Detected: Pattern 2: Failed swing | Current RSI: 38.01 > Previous Extremum: 37.80 | Weight: 90
2025.12.20 01:52:27.070 2024.11.07 00:45:00 position modified [#9152 sell 0.02 EURUSDr 1.07337 sl: 1.07310 tp: 1.06837]
2025.12.20 01:52:27.085 2024.11.07 00:45:00 CTrade::OrderSend: modify position #9152 EURUSDr (sl: 1.07310, tp: 1.06837) [done]
2025.12.20 01:52:27.133 2024.11.07 00:50:00 Long Signal Detected: Pattern 2: Failed swing | Current RSI: 38.53 > Previous Extremum: 37.80 | Weight: 90
2025.12.20 01:52:27.180 2024.11.07 00:55:00 Short Signal Detected: Pattern 0: Oscillator direction confirmation | RSI: 37.18, Diff: -1.35 | Weight: 70
2025.12.20 01:52:27.277 2024.11.07 01:00:00 Long Signal Detected: Pattern 3: Divergence | Bullish divergence detected | Weight: 80
2025.12.20 01:52:27.277 2024.11.07 01:00:00 position modified [#9152 sell 0.02 EURUSDr 1.07337 sl: 1.07288 tp: 1.06837]
2025.12.20 01:52:27.308 2024.11.07 01:00:00 CTrade::OrderSend: modify position #9152 EURUSDr (sl: 1.07288, tp: 1.06837) [done]
2025.12.20 01:52:27.324 2024.11.07 01:00:01 stop loss triggered #9152 sell 0.02 EURUSDr 1.07337 sl: 1.07288 tp: 1.06837 [#9153 buy 0.02 EURUSDr at 1.07288]

さらに重要なのは、操作ログから、ポジションがすでに保有されている状態であってもシグナル評価が積極的に継続されていることが確認できる点です。その結果、ストップロスの繰り返しの引き上げや、早すぎるポジション決済が発生しています。この挙動は、損失の原因が個々の不適切なトレードにあるのではなく、過剰な意思決定頻度と制御されていないシグナル有効化にあることを示しています。実質的に、このEAは市場ノイズに対して過剰反応している状態にあります。このことは、最適化において優先すべき対象が単なるパラメータ調整ではなく、取引頻度の制限、シグナルガバナンス、相場局面の認識であるという結論をさらに裏付けています。

生成されたマルチシグナルEAによって生成されたエクイティカーブ

上図のエクイティカーブは、今回のマルチシグナルEAによって生成されたものです。そこには、単発的な損失やランダムな変動ではなく、一貫して長期間にわたる下落傾向が確認できます。この挙動は、システムが継続的に市場へ参加している一方で、市場環境との構造的な整合性を欠いていることを示しています。取引は頻繁に実行され、損失は徐々に積み上がり、短期的な回復局面が発生したとしても、全体としての下降トレンドを変えるには至っていません。このようなパターンは、シグナルが過剰に発生しているシステムに典型的なものです。すなわち、日常的な市場ノイズが繰り返し有効な取引機会として解釈されている状態を示しています。

併せて表示されている証拠金使用率も、この診断結果を裏付けています。証拠金負荷は一貫して高い水準を示してお、さらに頻繁なスパイクが確認できます。これは、エクイティが悪化しているにもかかわらず、時間的に近接した取引や重複した取引が継続的に発生していることを示唆しています。これらの観察結果を総合すると、問題の本質は執行ロジックやインジケータの故障にあるのではなく、シグナルがどのように参加し、どのように組み合わされているかにあることが明確になります。この結果は、デフォルト動作のまま利用するのではなく、シグナル発生頻度の制御、市場コンテキストに応じた有効性の管理、規律ある意思決定プロセスの導入に焦点を当てた最適化戦略へ移行する必要性を強く示しています。

エクイティカーブだけでなく、操作ログおよび取引ログもまた、重要な分析ツールとなります。以下の項目を分析することで、

  • セッションごとにどれだけの取引が発生しているか
  • レンジ状態や停滞した相場で取引が集中していないか
  • 新たな市場情報がないにもかかわらず、どの程度の頻度でシグナルが再発生しているか

投票システムが本当に市場情報へ反応しているのか、それとも単なる価格変動そのものに反応しているだけなのかを推測することができます。この洞察は、後続の実装段階で導入する以下の改善手法へ直接つながります。

  • クールダウンロジック
  • レジームゲーティング
  • 条件付きシグナル有効化
  • カスタムシグナルの調整または置換

このように、シグナルの役割、重み付けの分布、各種閾値、そして実際の取引頻度を体系的に検証することが、実装フェーズへ進むための出発点となります。推測に基づいて改善策を考えるのではなく、EAのアーキテクチャおよび公式ドキュメントによって既に提供されている具体的な調整ポイントを特定していきます。そして、これらの観察結果を基に、マルチシグナルEAを制御可能かつ測定可能で、さらに再現性のある方法で改善するための最適化戦略へと進んでいきます。

次の段階では、検証から実装へと移行し、時間フィルタリングロジックを開発することで、EAが取引を許可される時間帯を直接制御できるようにします。また、パラメータ調整については補助的な最適化手段として取り扱います。これは最小限のコーディングで実施でき、主に各種パラメータを試験的に調整しながら、より良い設定を探る補助的な手法です。その際も、ネイティブフレームワークの整合性は維持されます。


実装

この段階は極めて重要です。なぜなら、ここから分析フェーズから実行フェーズへと移行し、時間フィルタリングロジックを直接実装するためです。制御された取引ウィンドウを導入することで、不要な取引頻度を大幅に削減し、EAがいつ動作を許可されるのかを正確に制御できるようになります。これらの改善は、カスタムコードに対する最小限かつ的を絞った修正によって実装されます。これにより、コアとなるシグナルアーキテクチャを破壊することなく、EAの挙動を統制することが可能になります。最適化に関する多くの知見は結果セクションに委ねられますが、その多くは大規模なコード変更ではなく、入力パラメータの微調整に関するものです。これは、複雑さそのものよりも、規律ある制御の方が優れた結果をもたらす場合が多いという原則を強調しています。

1. コアとなる時間フィルタリングの実装

セッション管理システムはブローカー時間を直接基準として動作し、タイムゾーンに関する複雑性を排除します。アルゴリズムは現在のサーバー時間を分単位の形式へ変換し、ユーザーが定義したセッション境界との正確な比較を可能にします。このアプローチは、通常のデイセッションだけでなく、夜間セッションにも対応しています。これは、日付をまたぐ時間帯に対して条件分岐ロジックを適用することで処理されます。このシステムは、指定された取引時間外におけるすべての取引活動を完全に遮断する強力な時間フィルタとして機能します。同時に、計算コストは最小限に抑えられており、非常に軽量な実装となっています。

//--- Trading Session Parameters (using BROKER time)
input bool               EnableSessionFilter              =true;                  // Enable Session Filter
input string             Session_StartTime                ="09:00";               // Session Start (Broker time, HH:MM)
input string             Session_EndTime                  ="17:00";               // Session End (Broker time, HH:MM)
input bool               Close_Outside_Session            =false;                 // Close trades outside session?

bool IsTradingTime()
{
   if(!SessionEnabled) return true;
   
   datetime current_time = TimeCurrent();
   MqlDateTime time_struct;
   TimeToStruct(current_time, time_struct);
   
   // Get current hour and minute
   int current_hour = time_struct.hour;
   int current_minute = time_struct.min;
   int current_total_minutes = current_hour * 60 + current_minute;
   
   // Parse start time
   string start_parts[];
   int start_hour = 9, start_minute = 0;
   if(StringSplit(Session_StartTime, ':', start_parts) >= 2)
   {
      start_hour = (int)StringToInteger(start_parts[0]);
      start_minute = (int)StringToInteger(start_parts[1]);
   }
   
   // Parse end time
   string end_parts[];
   int end_hour = 17, end_minute = 0;
   if(StringSplit(Session_EndTime, ':', end_parts) >= 2)
   {
      end_hour = (int)StringToInteger(end_parts[0]);
      end_minute = (int)StringToInteger(end_parts[1]);
   }
   
   // Calculate session boundaries in minutes
   int session_start_minutes = start_hour * 60 + start_minute;
   int session_end_minutes = end_hour * 60 + end_minute;
   
   // Check if current time is within session
   if(session_end_minutes > session_start_minutes)
   {
      // Normal session within same day
      return (current_total_minutes >= session_start_minutes && 
              current_total_minutes < session_end_minutes);
   }
   else
   {
      // Session crosses midnight
      return (current_total_minutes >= session_start_minutes || 
              current_total_minutes < session_end_minutes);
   }
}

2. 取引制限管理システム

このシステムは、クォータ(枠)ベースのアプローチを採用した高度な仕組みであり、過剰売買を防ぐために2種類のカウント手法を実装しています。第一の手法である履歴ベースのアプローチでは、MQL5のヒストリー関数を使用し、現在のセッション内で発生したすべての新規ポジションを追跡します。第二の手法であるポジションベースのアプローチでは、現在保有しているオープンポジションのみを監視対象とします。システムは、各新規セッションの開始時点で取引カウントを自動的にリセットします。この処理は最適化された60秒間隔のチェックによって実行されており、精度とパフォーマンス効率のバランスを両立しています。

//--- Trade Limit Parameters
input bool               EnableTradeLimit                 =true;                  // Enable Maximum Trade Limit
input int                MaxTradesPerSession              =2;                     // Maximum trades per session (1-2)
input bool               CountAllPositions               =true;                   // Count all positions (true) or only open ones (false)

int CurrentTradeCount = 0;
datetime SessionStartTime = 0;
datetime LastResetCheck = 0;

bool CanOpenNewTrade()
{
   if(!SessionEnabled) return true;
   
   // Check if we're in trading session
   if(!IsTradingTime()) return false;
   
   // Check trade limit
   if(EnableTradeLimit)
   {
      // Update trade count
      CurrentTradeCount = CountSessionTrades();
      
      if(CurrentTradeCount >= MaxTradesPerSession)
      {
         Print("Trade limit reached: ", CurrentTradeCount, "/", MaxTradesPerSession, " trades this session");
         return false;
      }
   }
   
   return true;
}

3. 統合レイヤーアーキテクチャ

修正されたOnTick()関数は、階層的な意思決定プロセスを実装しており、シグナル処理よりも先に制御ロジックを優先する構造となっています。このアーキテクチャは、いわゆるサーキットブレーカーメカニズムを形成しており、すべてのシグナリング処理が実行される前に、取引許可の有無が必ず検証されるようになっています。この統合構造は、トレーリングストップや決済シグナルといった既存のポジション管理機能を維持しながらも、新規エントリーについては条件を満たさない場合に完全にブロックする設計となっています。この階層的アプローチにより、元々のシグナル生成ロジックの整合性を保ちながら、一貫した実行制御を追加することが可能になります。

void OnTick()
{
   // Display current status on chart
   ShowStatusInfo();
   
   // Reset trade count if new session
   if(SessionEnabled)
   {
      ResetTradeCount();
   }
   
   // Check if we can open new trades
   bool can_open_trades = true;
   
   if(SessionEnabled)
   {
      can_open_trades = CanOpenNewTrade();
   }
   
   // Process trades based on conditions
   if(can_open_trades)
   {
      // Conditions met - allow normal trading
      ExtExpert.OnTick();
   }
   else
   {
      // Conditions not met - check if we need to close positions
      if(Close_Outside_Session && !IsTradingTime())
      {
         CheckSessionClose();
      }
      
      // Do NOT process any new trades when conditions are not met
      // This blocks ALL new trading activity
      return;
   }
}

4. リアルタイム監視およびフィードバック

パフォーマンス最適化された表示システムにより、チャートコメントを通じて即時の視覚的フィードバックが提供されます。この更新は1秒ごとに実行されます。この監視レイヤーは、現在のセッション状態、トレードカウントの進行状況、システム警告などをリアルタイムで表示します。実装ではstatic変数を使用することでCPU負荷を最小限に抑えつつ、ライブトレードおよびデバッグの両方において重要な情報を提供する設計となっています。この透明性により、任意の時点において、なぜ取引が実行されたのか、あるいはブロックされたのかを正確に理解することが可能になります。

void ShowStatusInfo()
{
   static datetime last_print = 0;
   if(TimeCurrent() - last_print >= 1)  // Update every second
   {
      string current_time = TimeToString(TimeCurrent(), TIME_MINUTES);
      bool in_session = IsTradingTime();
      bool can_trade = CanOpenNewTrade();
      
      string status_text = "";
      
      if(SessionEnabled)
      {
         if(in_session)
         {
            if(EnableTradeLimit)
            {
               status_text = StringFormat("TRADING: %s-%s | Trades: %d/%d | Time: %s",
                                          Session_StartTime, Session_EndTime,
                                          CurrentTradeCount, MaxTradesPerSession,
                                          current_time);
            }
            else
            {
               status_text = StringFormat("TRADING: %s-%s | Time: %s",
                                          Session_StartTime, Session_EndTime,
                                          current_time);
            }
         }
         else
         {
            status_text = StringFormat("BLOCKED: Outside session %s-%s | Time: %s",
                                       Session_StartTime, Session_EndTime,
                                       current_time);
         }
         
         // Add trade limit warning if applicable
         if(in_session && EnableTradeLimit && CurrentTradeCount >= MaxTradesPerSession)
         {
            status_text += "\nTRADE LIMIT REACHED!";
         }
      }
      else
      {
         status_text = "TRADING 24/7: Session filter OFF | Time: " + current_time;
      }
      
      Comment(status_text);
      last_print = TimeCurrent();
   }
}

5. 技術アーキテクチャの利点

本実装は、各レイヤーが独立して動作しながらもシームレスに統合される、モジュール型フィルタリングシステムを構築しています。この設計により、将来的な拡張として、曜日制限やボラティリティベースの制御といった追加フィルタを容易に組み込むことが可能になります。本アーキテクチャは、コアとなるシグナルロジックを変更することなく、既存の取引システムにアルゴリズム的な規律を追加できることを示しています。その結果、この構造はさまざまなEA設計に対して、体系的な取引改善をおこなうためのテンプレートとして機能します。

CExpert ExtExpert;
CTrade Trade;
bool SessionEnabled = false;
int CurrentTradeCount = 0;
datetime SessionStartTime = 0;
datetime LastResetCheck = 0;

// ... Initialization in OnInit() ...
int OnInit()
{
   // ... existing initialization code ...
   
   // Initialize session parameters
   SessionEnabled = EnableSessionFilter;
   
   // Get initial trade count
   if(EnableTradeLimit)
   {
      CurrentTradeCount = CountSessionTrades();
      SessionStartTime = GetSessionStartDatetime();
      LastResetCheck = TimeCurrent();
   }
   
   // Display session info
   if(SessionEnabled)
   {
      Print("=== TRADING SESSION FILTER ENABLED ===");
      Print("Session Time: ", Session_StartTime, " to ", Session_EndTime, " (Broker Time)");
      Print("Close Outside Session: ", Close_Outside_Session ? "Yes" : "No");
      
      if(EnableTradeLimit)
      {
         Print("Maximum Trades Per Session: ", MaxTradesPerSession);
         Print("Count Method: ", CountAllPositions ? "All positions (including history)" : "Only open positions");
         Print("Current Trade Count: ", CurrentTradeCount);
      }
      
      Print("Current Broker Time: ", TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES));
      Print("=====================================");
   }
   else
   {
      Print("Session Filter Disabled - Trading 24/7");
   }
   
   return(INIT_SUCCEEDED);
}


テスト

時間ベースフィルタの実装は、私たちのEAを本質的に変化させ、規律あるトレーディングシステムへと変換しました。その結果、取引頻度は大幅に削減される一方で、取引の質は向上しています。特定のセッションに取引を制限し、さらに最大トレード数の制約を導入することで、実行タイミングとエクスポージャーを精密に制御できるようになりました。この戦略的フィルタリングは不利な市場環境を排除し、その結果として、より少ないものの高確率な取引が実現され、リスク調整後リターンの改善およびエクイティカーブのより制御された推移が確認されます。

さらなる最適化およびより均一なパフォーマンス曲線を達成するためには、シグナルの重みの組み合わせを体系的に調整し、最適な時間帯を探索し、追加のフィルタリングレイヤーを統合する必要があります。遺伝的アルゴリズムおよびウォークフォワード分析を用いたパラメータの体系的テストを通じて、異なる市場環境においても一貫したパフォーマンスを発揮するようシステムを調整することが可能になります。最終的には、滑らかで上昇傾向を示すエクイティ成長と、制御されたドローダウン特性を備えた堅牢な取引アルゴリズムの構築を目指します。

テスト

時間フィルタリングを適用した取引:  マルチシグナルEA

エクイティカーブ

時間フィルタリング条件下で生成されたエクイティカーブは、以前の滑らかで一方向的な下降傾向とは明確に対照的な挙動を示しています。連続的な悪化ではなく、回復と下落が交互に発生する周期的なエクイティ挙動が確認されます。これは、従来の損失が単なるシグナルの失敗によるものではなく、不適切な市場時間帯における無制限な実行によって生じていたことを裏付けています。すなわち、ノイズ、低流動性、またはレジームミスマッチが結果に大きな影響を与えていたことを示しています。

時間ベース制御の導入により、EAはもはやすべての有効なシグナルに対して無差別に反応することはありません。取引活動は定義されたセッションに集中し、統計的に非効率な期間におけるエクスポージャーが削減されています。その結果、時間当たりの取引頻度の低下、取引分布の改善、およびドローダウン構造の緩和が確認されます。これは基礎となるシグナルロジックを一切変更することなく達成されています。これは、「シグナルそのものと同じくらい、「シグナルの実行をいつ許可するか」を制御することが重要である」という私たちの当初の仮説を直接的に裏付ける結果となりました。

検証の観点から見ると、この結果は、生成されたEAをシグナル解釈の欠陥ではなく、構造的な問題、すなわち「過剰な取引頻度」の証拠として捉える必要性を示しています。システムの動作は、機械的な過剰反応ではなく、意図的な実行を反映するようになり、規律あるアルゴリズム制御への決定的な一歩となった。

今回の改善により、システムの挙動は機械的な過剰反応から脱却し、意図的かつ制御された執行へと変化しました。これは、規律あるアルゴリズム制御に向けた重要な一歩と言えます。今後は、このフレームワークを基盤として、取引セッションの最適化、一定期間あたりの最大取引回数の制限、相場局面に応じた参加ルールの導入など、さらなる改善を進めることが可能になります。重要なのは、こうした改良が本来のシグナルアーキテクチャの整合性を維持したまま、「シグナルの多さ」に依存するのではなく、「執行規律」によって管理された予測可能でリスク調整後の優れた取引システムという目標に近づける点です。


結論

今回、ウィザードで生成したマルチシグナルEAを大幅に改善することに成功しました。しかも、それはシステム全体を作り直すことによってではなく、「時間ベースの取引フィルタ」という単一の工夫を追加することによって実現されています。このシンプルながら強力な変更により、EAが取引を開始できる時間帯を直接制御できるようになり、ノイズを追いかける反応型のシステムから、より規律ある抑制的な戦略へと変化しました。その結果、不要な取引回数が減少し、エクイティカーブは改善され、ドローダウンも以前よりはるかに管理しやすいものとなりました。これらの結果は、コードベースを複雑化することなく、比較的小さな構造的改善でも大きな成果を生み出せることを示しています。

今回の作業を通じて、いくつかの重要な教訓が得られました。第一に、多くの場合、パフォーマンスを損なう最大の要因は、インジケーターやロジックの欠陥ではなく、不適切な市場環境で過剰に取引してしまうことにあります。第二に、特定の取引セッションに限定するといった、適切に設計された単一の制約を導入するだけでも、オーバートレードを大幅に抑制し、システム全体の挙動を改善できます。第三に、時間足の選択は非常に重要です。低い時間足ではノイズや取引回数が増加し、結果的に成績を悪化させることが多い一方で、高い時間足では取引回数は減るものの、より信頼性の高いシグナルが得られる傾向があります。最後に、このような構造的改善は、より強固な土台を構築します。EAが過剰反応しなくなったことで、その後に実施するストラテジーテスターでのパラメータ最適化も、より意味のあるものとなり、誤解を招くような「最適化結果」に振り回されにくくなります。

今回取り上げた内容は、最適化という大きなテーマの一部に過ぎません。相場局面分類、適応型シグナルウェイト、取引後のクールダウン期間、ボラティリティベースのフィルタ、経済イベントによる除外ルール、ウォークフォワード分析、モンテカルロシミュレーションなど、さらに強力な手法が数多く存在します。これらの手法はEAを次のレベルへ引き上げる可能性を持っていますが、その一方でシステムの複雑性も増加します。そのため、本シリーズではこれらのテーマを今後のパートに分けて取り上げていく予定です。基礎を固めながら、一つひとつの概念を段階的に導入し、実際に検証しながら理解を深めていきます。

記事の最後に、更新後の完全なソースコードを添付しています。ぜひ異なる取引時間帯を試したり、ご自身のアイデアと組み合わせたり、フィルタの実装方法を確認したりしてみてください。最適化は継続的なプロセスであり、まだまだ探求すべきことは数多く残されています。

最後までお読みいただき、ありがとうございました。皆様からのコメント、ご質問、テスト結果、ご提案は、今後のシリーズの方向性を決めるうえで大変貴重なものです。ぜひお気軽にお寄せください。それでは、次回お会いしましょう。Happy Coding、そして安全なトレードを。

ソースファイル バージョン 説明
SignalFibonacci.mqh 1.0 第5回で使用した標準シグナルモジュールをそのまま再利用しています。本ファイルにはEAが必要とするフィボナッチシグナルロジックが含まれているため、コンパイルエラーを回避するためにも必須です。
Multi-Signal_Expert.mq5 1.1 ウィザードで生成したEAをベースに、執行制御機能、シグナル閾値の最適化、およびセッションベースの取引制限を追加した更新版です。コアとなるシグナルロジックを変更することなく、取引頻度の削減と取引品質の向上を目的としています。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/20478

添付されたファイル |
SignalFibonacci.mqh (17.77 KB)
MQL5入門(第37回):MQL5のAPIとWebRequest関数の習得(XI) MQL5入門(第37回):MQL5のAPIとWebRequest関数の習得(XI)
MQL5を使用してBinance APIに認証付きリクエストを送信し、アカウント内の全資産の残高情報を取得する方法を解説します。APIキー、サーバー時刻、署名を利用して安全にアカウント情報へアクセスし、そのレスポンスをファイルへ保存して後で活用する方法を学びます。
データサイエンスとML(第48回):Transformerは取引において重要なのか データサイエンスとML(第48回):Transformerは取引において重要なのか
ChatGPTからGemini、そしてテキスト、画像、動画生成のための数多くのAIモデル/ツールに至るまで、TransformerはAI業界に大きな衝撃を与えてきました。しかし、この技術は金融市場や取引の分野にも応用できるのでしょうか。その可能性を検討してみましょう。
MQL5取引ツール(第14回):アンチエイリアシングと角丸スクロールバーを備えたピクセルパーフェクトなスクロール対応テキストキャンバス MQL5取引ツール(第14回):アンチエイリアシングと角丸スクロールバーを備えたピクセルパーフェクトなスクロール対応テキストキャンバス
本記事では、MQL5のCCanvasベース価格ダッシュボードを拡張し、利用ガイドを表示するためのピクセルパーフェクトなスクロール可能テキストパネルを追加します。これにより、ネイティブのスクロール機能の制限を回避しつつ、カスタムアンチエイリアス処理と角丸デザインのスクロールバーを実現します。テキストパネルは、不透明度を設定可能なテーマ対応背景をサポートし、説明文や連絡先情報などのコンテンツを動的に改行表示できます。また、上下ボタン、スライダーのドラッグ操作、本文領域内でのマウスホイール操作によるインタラクティブなナビゲーションにも対応しています。
プライスアクション分析ツールキットの開発(第57回):MQL5による市場状態分類モジュールの開発 プライスアクション分析ツールキットの開発(第57回):MQL5による市場状態分類モジュールの開発
確定済み価格データを用いて価格挙動を解釈するMQL5向けの市場状態分類モジュールを開発および解説します。ボラティリティの収縮および拡大、ならびに構造的一貫性を分析することにより、市場環境をコンプレッション、トランジション、エクスパンション、トレンドとして分類し、プライスアクション分析のための明確な文脈把握の枠組みを提供します。