English Deutsch
preview
プライスアクション分析ツールキットの開発(第25回):Dual EMA Fractal Breaker

プライスアクション分析ツールキットの開発(第25回):Dual EMA Fractal Breaker

MetaTrader 5インディケータ |
129 3
Christian Benjamin
Christian Benjamin

内容



はじめに

本記事の目的は、フラクタル(Fractals)インジケーター(ビル・ウィリアムズによって開発)を活用し、プライスアクション分析を支援するツールの開発を紹介することです。このツールは、より深く洞察に富んだ評価を提供します。

ビル・M・ウィリアムズ (1932–2019)は、米国の著名なトレーダー兼著述家で、取引心理学、テクニカル分析、金融市場におけるカオス理論への貢献で知られています。彼は株式、コモディティ、外国為替(FX)市場を研究し、トレンドや潜在的な反転ポイントを特定するための革新的なテクニカル分析ツールを多数開発しました。代表的なインジケーターには、Accelerator/Decelerator OscillatorAlligator indicatorAwesome OscillatorFractals indicatorGator OscillatorMarket Facilitation Indexなどがあります。これらのインジケーターは、現在でもFXや株式市場などで広く活用され、市場動向の分析に高い効果を発揮しています。

ウィリアムズの手法の重要な要素であるフラクタルインジケーターは、本アプローチにおいて、14期間および200期間の指数移動平均(EMA: Exponential Moving Averages)と組み合わせて使用されます。フラクタルパターンをこれらの動的トレンドフィルターと統合することで、このエキスパートアドバイザー(EA)は市場の潜在的な反転を正確に特定しつつ、全体的なトレンド方向との整合性も確保します。この組み合わせにより、反転シグナルの早期検出とトレンドの強さの確認が可能となり、信頼性が高く、成功確率の高いエントリーポイントを提供します。フラクタル分析と移動平均線の相乗効果により、トレーダーはプライスアクションをより深く解釈でき、エントリータイミングの最適化や取引成果の向上に役立ちます。


戦略の理解

私たちのEAは、フラクタルインジケーター、EMA 14EMA 200という3つの主要なテクニカル指標を利用します。ビル・ウィリアムズによって開発されたフラクタルインジケーターは、潜在的なトレンド反転を特定するために広く使用されるテクニカル分析ツールです。特定の価格パターン(フラクタルと呼ばれる)を検出し、それがローカルの高値または安値として現れることで、市場の転換点を示唆します。これらのフラクタルはサポートまたはレジスタンスレベルとして機能し、トレーダーに視覚的な手掛かりを与えて、エントリーやイグジットのタイミングをより正確に判断できるようにします。

指数移動平均(EMA)は、単純移動平均(SMA)とは根本的に異なり、直近の価格データにより大きな重みを与えることで、より反応性の高いインジケーターとなります。この加重は、直近の価格を指数的に強調する平滑化係数によって実現され、EMAは市場の変化に迅速に反応できるようになります。その結果、特に短期的には、EMAは新たなトレンドを捉えたり、トレンド転換の初期シグナルを提供するのに非常に有効です。

本戦略において、EMA 14は短期的な市場モメンタムを反映し、最近の価格変動に素早く反応するため、タイムリーなエントリーに適しています。一方、EMA 200は長期的なトレンド指標であり、短期的なノイズをならして市場全体の方向性を示します。価格がEMA 200の上にある場合は長期的な上昇トレンドを示し、下にある場合は下降トレンドを示唆します。さらに、EMA 200は動的なサポートやレジスタンスとして機能することが多く、トレーダーが騙しシグナルを排除し、トレンドの有効性を確認する助けとなります。

買いシグナル(強気のブレイクアウト):

複数の条件が同時に満たされた場合、強い上昇の動きを示す買いシグナルが発生します。まずEAは直近のフラクタル安値(サポートレベル)を監視します。市場価格がこのフラクタルサポートを上抜けした場合、ブレイクアウトの可能性を示唆します。さらに上昇トレンドを確認するために、EAは現在の価格がEMA 14とEMA 200の両方より上にあり、かつEMA 14がEMA 200の上に位置していることを確認します。これらの条件が揃ったとき、買いシグナルが生成されます。チャート上には上向きの矢印やラベルが表示され、トレーダーに通知するアラートを発することもできます。

  • 価格が直近のフラクタル安値(サポート)を上抜ける。
  • 現在の価格がEMA 14およびEMA 200の上にある。
  • EMA 14がEMA 200の上にあり、上昇トレンドを確認。

図1:強気のブレイク

売りシグナル(弱気のブレイクダウン)

逆に、価格が直近のフラクタル高値(レジスタンス)を下抜けた場合、下降の動きを示唆する売りシグナルが生成されます。EAは直近のフラクタル高値を観察し、市場価格がこれを下抜けるのを待ちます。さらに下降トレンドを確認するために、現在の価格がEMA 14およびEMA 200の下にあり、かつEMA 14がEMA 200の下に位置していることを確認します。これらの条件が揃ったとき、売りシグナルが生成されます。チャート上には下向きの矢印やラベルが表示され、必要に応じてアラートも発動されます。

  • 価格が直近のフラクタル高値(レジスタンス)を下抜ける。
  • 現在の価格がEMA 14およびEMA 200の下にある。
  • EMA 14がEMA 200の下にあり、下降トレンドを確認。

図2:弱気のブレイク


コード構成の解説

本EAは、フラクタル分析と移動平均によるトレンドフィルターを統合し、市場における潜在的なブレイクアウトポイントを特定・可視化します。直近のフラクタル高値および安値に水平ラインを描画することで、重要なサポートおよびレジスタンスゾーンを明確化します。価格がこれらのレベルを、EMAによって確認されたトレンド方向に沿って突破した場合、EAは視覚的シグナル(矢印やラベル)および音声アラートを生成し、トレーダーの意思決定を簡略化します。本EAはモジュール設計を採用しており、描画、シグナル生成、データ管理といった機能をそれぞれ専用の関数に分割しています。そのため、さまざまな取引スタイルや好みに柔軟に適応可能です。さらに、リソース管理や後処理(クリーンアップ)を重視することで、稼働中の安定性と視覚的な明瞭さを確保しています。総合的に見ると、このインジケーターと視覚的補助の高度な組み合わせは、トレンド環境下におけるフラクタルブレイクアウトの機会を活用しようとするトレーダーにとって非常に有効なツールとなります

ヘッダとメタデータ

コードの冒頭部分には、スクリプトの著作権、バージョン、ライセンス情報などのメタデータが含まれています。//+------------------------------------------------------------------+で囲まれたコメントは、スクリプトの目的を識別し、著者情報を明示する役割を果たします。#propertyディレクティブは著作権者の情報、MetaTrader コミュニティ上の著者プロフィールへのリンク、バージョン番号、厳格なコンパイル規則の適用を指定します。特に #property strict ディレクティブは重要です。これはコンパイラに対し、未宣言変数や型の不一致といった潜在的なエラーを厳格に検出するよう指示します。これらのメタデータやディレクティブは、実行時のロジックには影響を与えませんが、コードの文書化とコンパイル時の品質保証に役立ちます。

//+------------------------------------------------------------------+
//|                              Fractal Breakout, EMA 14 and EMA 200|
//|                                   Copyright 2025, MetaQuotes Ltd.|
//|                           https://www.mql5.com/ja/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/ja/users/lynnchris"
#property version   "1.0"
#property strict

入力パラメータ

このセクションでは、ユーザーがコアコードを変更せずに調整できる設定可能なパラメータを定義します。設定項目には、分析対象とする時間足(InpTimeframe)、検証するバーの本数(InpHistoryBars)、およびトレンドフィルターとして機能する2本のEMAの期間(InpEMA14Period、InpEMA200Period)が含まれます。

また、色指定パラメータ(InpBullColor、InpBearColor)により、ブレイクアウトを示す矢印やラインの色をカスタマイズできます。テキストラベル(InpBullText、InpBearText)はシグナルに説明的な注釈を追加し、チャートをより見やすくします。矢印のオフセット(InpArrowOffset)やフォントサイズ(InpArrowFontSize)によって表示位置や文字サイズを調整でき、トレーダーはラベルを見やすい位置に配置できます。

アラートシステムはInpAlertsEnabledによってポップアップ通知の有効・無効を切り替え、InpAlertSoundFileによって検出時に再生されるサウンドファイルを指定します。これらのパラメータにより、EAはさまざまなトレードスタイルや視覚的な好みに柔軟に対応し、ユーザーが自分のニーズに合わせて最適化できるようになっています。

input ENUM_TIMEFRAMES InpTimeframe      = PERIOD_CURRENT;  // chart TF
input int             InpHistoryBars    = 200;             // bars back to scan
input int             InpEMA14Period    = 14;              // fast EMA
input int             InpEMA200Period   = 200;             // slow EMA
input color           InpBullColor      = clrLime;         // bullish arrow color
input color           InpBearColor      = clrRed;          // bearish arrow color
input string          InpBullText       = "BULL Break";    // bullish label
input string          InpBearText       = "BEAR Break";    // bearish label
input int             InpArrowOffset    = 20;              // offset in points for label
input int             InpArrowFontSize  = 12;              // size of the arrow glyph
input bool            InpAlertsEnabled  = true;            // show pop-up alerts
input string          InpAlertSoundFile = "alert.wav";     // sound file in /Sounds/

グローバル変数とインジケーターハンドル

関数外で宣言された変数は、インジケーターハンドルやフラクタルデータ配列を保持するためのストレージとして機能します。ハンドル(hFractals、hEMA14、hEMA200)は、初期化時に生成されるインジケータインスタンスへの参照です。これらはEAがインジケーターのバッファとやり取りし、リアルタイムおよび過去のデータを取得するために不可欠です。配列fractalUp[]fractalDown[]は、それぞれフラクタルの高点と低点を保持する動的に割り当てられたバッファです。これらをグローバル変数として管理すると、スクリプト全体、特にリアルタイム分析がおこなわれるOnTick処理中に、それらにアクセスできるようになります。

int  hFractals, hEMA14, hEMA200;
double fractalUp[], fractalDown[];

初期化(OnInit)

起動時に、OnInit関数が呼び出され、必要なリソースが準備されます。この関数は、iFractalsiMAといった関数を用いてフラクタルおよびEMAのインジケーターハンドルを作成し、銘柄や時間枠を指定します。これらのハンドルの作成が成功することは極めて重要です。もしパラメータの誤りや利用可能なデータが存在しないといった理由でハンドルが無効になる場合、初期化は失敗し、EAが不適切に動作するのを防ぎます。

次に、フラクタルデータ配列が系列として動作するように設定されます。これにより、最新のデータがインデックス0に配置され、過去のデータを遡って解析する際に簡便になります。さらに、指定されたバー数に応じてこれらの配列をリサイズし、データバッファが効率的に処理できるように適切なサイズに調整します。全体として、このステップは信頼性の高いデータ取得の基盤を確立するものであり、正確なブレイクアウト検出にとって不可欠です。

int OnInit()
  {
   hFractals = iFractals(_Symbol, InpTimeframe);
   hEMA14    = iMA(_Symbol, InpTimeframe, InpEMA14Period, 0, MODE_EMA, PRICE_CLOSE);
   hEMA200   = iMA(_Symbol, InpTimeframe, InpEMA200Period,0, MODE_EMA, PRICE_CLOSE);
   if(hFractals==INVALID_HANDLE || hEMA14==INVALID_HANDLE || hEMA200==INVALID_HANDLE)
      return(INIT_FAILED);

   ArraySetAsSeries(fractalUp,   true);
   ArraySetAsSeries(fractalDown, true);
   ArrayResize(fractalUp,   InpHistoryBars);
   ArrayResize(fractalDown, InpHistoryBars);
   return(INIT_SUCCEEDED);
  }

初期化解除(OnDeinit)

EAがチャートから削除される、またはターミナルが終了する際には、OnDeinitが実行され、リソースのクリーンアップがおこなわれます。この関数はIndicatorReleaseを使用してインジケーターハンドルを解放し、関連するメモリを開放してリークを防ぎます。さらに、チャート上に存在するすべてのオブジェクトを走査し、接頭辞「FB_」を持つものを特定して削除します。これらは稼働中に生成された視覚的シグナル(矢印、ラベル、ライン)です。このクリーンアップにより、EAの停止後に残存オブジェクトがチャートを散らかすことを防ぎ、クリーンなチャート環境を維持するとともに、後続の分析における潜在的な衝突や混乱を回避します。

void OnDeinit(const int reason)
  {
   if(hFractals!=INVALID_HANDLE)
      IndicatorRelease(hFractals);
   if(hEMA14   !=INVALID_HANDLE)
      IndicatorRelease(hEMA14);
   if(hEMA200  !=INVALID_HANDLE)
      IndicatorRelease(hEMA200);

   for(int i=ObjectsTotal(0)-1; i>=0; i--)
     {
      string n = ObjectName(0,i);
      if(StringFind(n,"FB_")>=0)
         ObjectDelete(0,n);
     }
  }

メイン処理(OnTick)

コアロジックはOnTick関数内にあり、新しいマーケットティックが到着するたびに実行されます。処理は、まずCopyBufferを使用して2本のEMAの最新値を取得することから始まります。これらのEMA値はトレンドフィルターとして機能し、その相対的な位置によって市場が上昇トレンドか下降トレンドかを示し、ブレイクアウトの判断を補助します。もしEMAデータの取得に失敗した場合、騙しシグナルを防ぐために関数は早期終了します。次に、関数は直近の高値および安値フラクタルのデータバッファを取得し、ここでもエラーチェックをおこないます。その後、コードはこれらのバッファを後方に走査し、プレースホルダーであるEMPTY_VALUEを無視しつつ、直近の有効なフラクタルを探索します。これにより、直近の重要なフラクタルポイントを特定し、EAはブレイクアウトを引き起こす可能性のある重要なサポートまたはレジスタンス水準を決定します。そして、ヘルパー関数を使用してこれらの水準に水平線を描画し、視覚的な参照を提供します。ターミナルのデバッグ出力は、レベル、価格、EMAの状態についてリアルタイムの洞察を提供し、トレーダーがロジックを検証するのに役立ちます。

最後に、EAはブレイクアウト条件をチェックします。弱気のブレイクアウトは、前回のクローズがダウンレベルの上にあり、現在のクローズがそれを下抜け、さらに価格が両方のEMAを下回り下降トレンドにある場合に発生します。逆に、強気のブレイクアウトは、前回のクローズがアップレベルの下にあり、現在のクローズがそれを上抜け、かつ価格が両方のEMAを上回り上昇トレンドにある場合に認識されます。これらの条件が検出されると、シグナル関数がトリガーされます。

void OnTick()
  {
   // 1) Read current EMAs
   double ema14Arr[1], ema200Arr[1];
   if(CopyBuffer(hEMA14,0,0,1,ema14Arr)<=0 || CopyBuffer(hEMA200,0,0,1,ema200Arr)<=0)
      return;
   double ema14_now  = ema14Arr[0];
   double ema200_now = ema200Arr[0];

   // 2) Read fractal history (skip current bar)
   if(CopyBuffer(hFractals,0,1,InpHistoryBars,fractalUp)<=0 ||
      CopyBuffer(hFractals,1,1,InpHistoryBars,fractalDown)<=0)
      return;

   // 3) Find most recent valid fractals (ignore EMPTY_VALUE)
   int upShift=-1, downShift=-1;
   for(int i=1; i<InpHistoryBars; i++)
     {
      if(fractalUp[i]   != EMPTY_VALUE && upShift<0)
         upShift   = i+1;
      if(fractalDown[i] != EMPTY_VALUE && downShift<0)
         downShift = i+1;
      if(upShift>0 && downShift>0)
         break;
     }

   // 4) Levels
   double lvlUp   = (upShift>0)   ? fractalUp[upShift-1]     : 0.0;
   double lvlDown = (downShift>0) ? fractalDown[downShift-1] : 0.0;

   // 5) Draw level lines
   DrawHLine("FB_LevelUp",   lvlUp,   InpBullColor);
   DrawHLine("FB_LevelDown", lvlDown, InpBearColor);

   // 6) DEBUG print
   double prevC = iClose(_Symbol,InpTimeframe,1);
   double currC = iClose(_Symbol,InpTimeframe,0);
   PrintFormat(
      "DBG lvlUp=%.5f lvlDown=%.5f prevC=%.5f currC=%.5f EMA14=%.5f EMA200=%.5f",
      lvlUp, lvlDown, prevC, currC, ema14_now, ema200_now
   );

   // 7) Breakouts on the last closed candle (shift=1)

   // Bearish breakout detection
   if(lvlDown>0
      && prevC>=lvlDown && currC<lvlDown
      && currC<ema14_now && currC<ema200_now
      && ema200_now>ema14_now)
     {
      Print(">>> Bear breakout triggered");
      Signal(false, 1, lvlDown, ema14_now, ema200_now);
     }

   // Bullish breakout detection
   if(lvlUp>0
      && prevC<=lvlUp && currC>lvlUp
      && currC>ema14_now && currC>ema200_now
      && ema14_now>ema200_now)
     {
      Print(">>> Bull breakout triggered");
      Signal(true, 1, lvlUp, ema14_now, ema200_now);
     }
  }

水平線描画(DrawHLine)

このユーティリティ関数は、チャート上の水平線の作成と更新を管理します。呼び出されると、まず指定された名前のラインが存在するかを確認し、存在しない場合は指定された価格レベルに新しい点線を指定色で作成します。既にラインが存在する場合は、その位置を更新するだけです。このアプローチにより、複数のラインが重なって表示されることを防ぎ、視覚的な水準が最新のフラクタル分析に合わせて維持されるようにします。点線スタイルは、他のチャートオブジェクトと区別しやすく、サポートまたはレジスタンスレベルとしての役割を強調します。このような視覚的手がかりはトレーダーにとって非常に有用であり、ブレイクアウトゾーンの迅速な認識を可能にし、手動または自動の意思決定を支援します。

void DrawHLine(string name, double price, color clr)
  {
   if(price<=0)
      return;
   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_HLINE,0,0,price);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
     }
   else
      ObjectSetDouble(0,name,OBJPROP_PRICE,price);
  }

シグナリングと可視化(Signal)

Signal関数は、ブレイクアウトイベントのシグナルに関するすべての処理をカプセル化しています。処理は、まずシグナルが発生したバーのタイムスタンプを取得し、視覚的オブジェクトを正確に配置できるようにします。次に、ブレイクアウト水準に矢印オブジェクトを作成し、ブルかベアかに応じて上向きまたは下向きに設定し、トレンドに一致した色を適用します。矢印の外観は、明瞭さを確保するために幅やサイズのパラメータでカスタマイズされます。さらに、矢印の近くにテキストラベルがわずかに縦方向にオフセットされて追加され、「BULL Break」や「BEAR Break」といった説明的なメッセージを表示し、視覚的な手がかりを補強します。

この関数はまた、[エキスパート]タブに詳細なメッセージをログとして出力し、正確な時刻、水準、終値、EMAの値を含む包括的なシグナル記録を提供します。アラートが有効になっている場合、ポップアップメッセージが表示され、サウンドファイルが再生されてトレーダーに即時通知されます。視覚、聴覚、ログに基づくこの組み合わせにより、トレーダーは潜在的なブレイクアウトの機会を迅速に把握でき、タイムリーな行動が可能となります。

void Signal(bool isBull, int shift, double level, double ema14, double ema200)
  {
   datetime t     = iTime(_Symbol,InpTimeframe,shift);
   double   price = level;
   string   side  = isBull ? "Bull" : "Bear";

   // Arrow
   string arrowName = StringFormat("FB_%sArrow_%d", side, (int)t);
   ObjectCreate(0, arrowName, OBJ_ARROW, 0, t, price);
   ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE,    isBull?233:234);
   ObjectSetInteger(0, arrowName, OBJPROP_COLOR,        isBull?InpBullColor:InpBearColor);
   ObjectSetInteger(0, arrowName, OBJPROP_WIDTH,        2);
   ObjectSetInteger(0, arrowName, OBJPROP_FONTSIZE,     InpArrowFontSize);

   // Label
   string lab = arrowName + "_L";
   double offset = (isBull ? InpArrowOffset : -InpArrowOffset) * _Point;
   ObjectCreate(0, lab, OBJ_TEXT, 0, t, price + offset);
   ObjectSetString(0, lab, OBJPROP_TEXT,    isBull?InpBullText:InpBearText);
   ObjectSetInteger(0, lab, OBJPROP_COLOR,  isBull?InpBullColor:InpBearColor);
   ObjectSetInteger(0, lab, OBJPROP_FONTSIZE, 11);

   // Log message
   string msg = StringFormat(
                   "%s breakout at %s | Level=%.5f | Close=%.5f | EMA14=%.5f | EMA200=%.5f",
                   side, TimeToString(t, TIME_DATE|TIME_SECONDS),
                   level, iClose(_Symbol,InpTimeframe,shift),
                   ema14, ema200
                );
   Print(msg);

   // Alert and sound
   if(InpAlertsEnabled)
     {
      Alert(msg);
      if(StringLen(InpAlertSoundFile)>0)
         PlaySound(InpAlertSoundFile);
     }
  }

MQL5コード

//+------------------------------------------------------------------+
//|                              Fractal Breakout, EMA 14 and EMA 200|
//|                                   Copyright 2025, MetaQuotes Ltd.|
//|                           https://www.mql5.com/ja/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/ja/users/lynnchris"
#property version   "1.0"
#property strict

//---inputs
input ENUM_TIMEFRAMES InpTimeframe      = PERIOD_CURRENT;  // chart TF
input int             InpHistoryBars    = 200;             // bars back to scan
input int             InpEMA14Period    = 14;              // fast EMA
input int             InpEMA200Period   = 200;             // slow EMA
input color           InpBullColor      = clrLime;         // bullish arrow color
input color           InpBearColor      = clrRed;          // bearish arrow color
input string          InpBullText       = "BULL Break";    // bullish label
input string          InpBearText       = "BEAR Break";    // bearish label
input int             InpArrowOffset    = 20;              // offset in points for label
input int             InpArrowFontSize  = 12;              // size of the arrow glyph
input bool            InpAlertsEnabled  = true;            // show pop-up alerts
input string          InpAlertSoundFile = "alert.wav";     // sound file in /Sounds/

//---indicator handles & buffers
int  hFractals, hEMA14, hEMA200;
double fractalUp[], fractalDown[];

//+------------------------------------------------------------------+
//| Expert initialization                                            |
//+------------------------------------------------------------------+
int OnInit()
  {
   hFractals = iFractals(_Symbol, InpTimeframe);
   hEMA14    = iMA(_Symbol, InpTimeframe, InpEMA14Period, 0, MODE_EMA, PRICE_CLOSE);
   hEMA200   = iMA(_Symbol, InpTimeframe, InpEMA200Period,0, MODE_EMA, PRICE_CLOSE);
   if(hFractals==INVALID_HANDLE || hEMA14==INVALID_HANDLE || hEMA200==INVALID_HANDLE)
      return(INIT_FAILED);

   ArraySetAsSeries(fractalUp,   true);
   ArraySetAsSeries(fractalDown, true);
   ArrayResize(fractalUp,   InpHistoryBars);
   ArrayResize(fractalDown, InpHistoryBars);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(hFractals!=INVALID_HANDLE)
      IndicatorRelease(hFractals);
   if(hEMA14   !=INVALID_HANDLE)
      IndicatorRelease(hEMA14);
   if(hEMA200  !=INVALID_HANDLE)
      IndicatorRelease(hEMA200);

   for(int i=ObjectsTotal(0)-1; i>=0; i--)
     {
      string n = ObjectName(0,i);
      if(StringFind(n,"FB_")>=0)
         ObjectDelete(0,n);
     }
  }

//+------------------------------------------------------------------+
//| Tick handler                                                     |
//+------------------------------------------------------------------+
void OnTick()
  {
// 1) Read current EMAs
   double ema14Arr[1], ema200Arr[1];
   if(CopyBuffer(hEMA14,0,0,1,ema14Arr)<=0 || CopyBuffer(hEMA200,0,0,1,ema200Arr)<=0)
      return;
   double ema14_now  = ema14Arr[0];
   double ema200_now = ema200Arr[0];

// 2) Read fractal history (skip current bar)
   if(CopyBuffer(hFractals,0,1,InpHistoryBars,fractalUp)<=0 ||
      CopyBuffer(hFractals,1,1,InpHistoryBars,fractalDown)<=0)
      return;

// 3) Find most recent valid fractals (ignore EMPTY_VALUE)
   int upShift=-1, downShift=-1;
   for(int i=1; i<InpHistoryBars; i++)
     {
      if(fractalUp[i]   != EMPTY_VALUE && upShift<0)
         upShift   = i+1;
      if(fractalDown[i] != EMPTY_VALUE && downShift<0)
         downShift = i+1;
      if(upShift>0 && downShift>0)
         break;
     }

// 4) Levels
   double lvlUp   = (upShift>0)   ? fractalUp[upShift-1]     : 0.0;
   double lvlDown = (downShift>0) ? fractalDown[downShift-1] : 0.0;

// 5) Draw level lines
   DrawHLine("FB_LevelUp",   lvlUp,   InpBullColor);
   DrawHLine("FB_LevelDown", lvlDown, InpBearColor);

// 6) DEBUG print
   double prevC = iClose(_Symbol,InpTimeframe,1);
   double currC = iClose(_Symbol,InpTimeframe,0);
   PrintFormat(
      "DBG lvlUp=%.5f lvlDown=%.5f prevC=%.5f currC=%.5f EMA14=%.5f EMA200=%.5f",
      lvlUp, lvlDown, prevC, currC, ema14_now, ema200_now
   );

// 7) Breakouts on the last closed candle (shift=1)

// Bearish breakout
   if(lvlDown>0
      && prevC>=lvlDown && currC<lvlDown
      && currC<ema14_now && currC<ema200_now
      && ema200_now>ema14_now)
     {
      Print(">>> Bear breakout triggered");
      Signal(false, 1, lvlDown, ema14_now, ema200_now);
     }
// Bullish breakout
   if(lvlUp>0
      && prevC<=lvlUp && currC>lvlUp
      && currC>ema14_now && currC>ema200_now
      && ema14_now>ema200_now)
     {
      Print(">>> Bull breakout triggered");
      Signal(true, 1, lvlUp, ema14_now, ema200_now);
     }
  }

//+------------------------------------------------------------------+
//| Draw or update a dotted HLine                                    |
//+------------------------------------------------------------------+
void DrawHLine(string name, double price, color clr)
  {
   if(price<=0)
      return;
   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_HLINE,0,0,price);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
     }
   else
      ObjectSetDouble(0,name,OBJPROP_PRICE,price);
  }

//+------------------------------------------------------------------+
//| Plot arrow, label, log & alert                                   |
//+------------------------------------------------------------------+
void Signal(bool isBull, int shift, double level, double ema14, double ema200)
  {
   datetime t     = iTime(_Symbol,InpTimeframe,shift);
   double   price = level;
   string   side  = isBull ? "Bull" : "Bear";

// Arrow
   string arrowName = StringFormat("FB_%sArrow_%d", side, (int)t);
   ObjectCreate(0, arrowName, OBJ_ARROW, 0, t, price);
   ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE,    isBull?233:234);
   ObjectSetInteger(0, arrowName, OBJPROP_COLOR,        isBull?InpBullColor:InpBearColor);
   ObjectSetInteger(0, arrowName, OBJPROP_WIDTH,        2);
   ObjectSetInteger(0, arrowName, OBJPROP_FONTSIZE,     InpArrowFontSize);

// Label
   string lab = arrowName + "_L";
   double offset = (isBull ? InpArrowOffset : -InpArrowOffset) * _Point;
   ObjectCreate(0, lab, OBJ_TEXT, 0, t, price + offset);
   ObjectSetString(0, lab, OBJPROP_TEXT,    isBull?InpBullText:InpBearText);
   ObjectSetInteger(0, lab, OBJPROP_COLOR,  isBull?InpBullColor:InpBearColor);
   ObjectSetInteger(0, lab, OBJPROP_FONTSIZE, 11);

// Expert log
   string msg = StringFormat(
                   "%s breakout at %s | Level=%.5f | Close=%.5f | EMA14=%.5f | EMA200=%.5f",
                   side, TimeToString(t, TIME_DATE|TIME_SECONDS),
                   level, iClose(_Symbol,InpTimeframe,shift),
                   ema14, ema200
                );
   Print(msg);

// Pop-up alert + optional sound
   if(InpAlertsEnabled)
     {
      Alert(msg);
      if(StringLen(InpAlertSoundFile)>0)
         PlaySound(InpAlertSoundFile);
     }
  }
//+------------------------------------------------------------------+


結果

EAをテストするには、まずMetaEditorを使用してコードをコンパイルします。コンパイルが完了したら、MetaTrader 5のチャートに適用してライブテストをおこなうか、ストラテジーテスターを使って直接バックテストを実行できます。私はこのEAを実際の市場環境と過去のバックテストの両方でテストしました。このプロセスは、EAのパラメータを微調整し、望ましい取引動作を実現するとともに、そのパフォーマンスを最適化するために不可欠です。

以下の画像に示されるチャートは、EAがフラクタルとEMAインジケーターを用いて重要な市場の反転を検出する方法を示しています。具体的には、EAは主要なサポート水準でベアリッシュフラクタルのブレイクを検出し、それがチャート上に視覚的にマークされます。その後の価格動向は反転を確認するものであり、市場は下降を続け、EMAトレンドに沿ってEMA 14がEMA 200を下抜けし、ベアリッシュトレンドへの転換を示しています。「BEAR Break」マーカーのような視覚的手がかりは、規律あるエントリーやイグジットの判断をサポートします。この結果は、EAがトレンド反転の初期兆候を認識し、トレーダーが高確率の機会を捉えつつ騙しシグナルを回避できることを示しています。

図3:Step Indexにおける弱気のブレイク

以下のGIFは、EAによるトレンド反転のリアルタイム検出と確認プロセスを示しています。インジケーターシステムがフラクタルのサポートまたはレジスタンス水準を特定し、潜在的なブレイクアウトをシグナルとして提示し、トレーダーにポジションを検討させる様子が強調されています。市場が予測された方向に動くにつれて、EAのシグナルはEMAの整合性によって確認されます。EMA 14がEMA 200を下抜けすることでベアリッシュトレンドが裏付けられます。矢印やアラートといった視覚的手がかりは、EAがタイムリーな意思決定をどのように支援するかを示しています。この例は、トレンド確認と組み合わせた早期検出の重要性を強調しており、取引の自信を高めると同時に誤ったエントリーの可能性を減少させます。

図4: V75 (1s)でのバックテスト


結論

このEAは、ビル・ウィリアムズのフラクタルインジケーターと短期・長期の指数平滑移動平均線を組み合わせることで、高確率のエントリーポイントを特定します。これらのツールを組み合わせることにより、支配的な市場トレンドと照らし合わせて確認される初期の反転シグナルを捉え、トレード執行の精度と一貫性を向上させます。厳密なバックテストとライブトライアルにより、多様な市場環境における柔軟性が確認されており、パラメータを微調整することで最適なパフォーマンスに適応できます。直感的なチャート上の矢印やラベルに加え、完全自動の注文実行機能を備えるこのEAは、取引ルーチンに規律とスピードをもたらします。要するに、本EAはプライスアクション分析のための体系的かつルールベースのフレームワークを提供し、テクニカルな厳密性と自動化を融合させたいトレーダーに最適です。

以下の表で、取り上げたツールをご確認ください。





   
ChartProjector
Analytical Comment
Analytics Master
Analytics Forecaster 
Volatility Navigator
Mean Reversion Signal Reaper
Signal Pulse 
Metrics Board 
External Flow
VWAP
Heikin Ashi   FibVWAP  
RSI DIVERGENCE
Parabolic Stop and Reverse (PSAR) 
Quarters Drawerスクリプト
Intrusion Detector
TrendLoom Tool  Quarters Board 
ZigZag Analyzer  Correlation Pathfinder  Market Structure Flip Detector Tool
Correlation Dashboard   Currency Strength Meter 
PAQ Analysis Tool 
ピンバー、包み足、RSIダイバージェンス
Dual EMA Fractal Breaker        

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

添付されたファイル |
最後のコメント | ディスカッションに移動 (3)
Delly
Delly | 4 6月 2025 において 09:17
興味深い記事だ。EAのソースコードも ありがとう。試してみて、フィードバックします。
Christian Benjamin
Christian Benjamin | 9 6月 2025 において 19:54
Delly Kabongo #:
興味深い記事だ。EAのソースコードもありがとう。試してみて、フィードバックします。
ご連絡ありがとうございます。あなたのフィードバックはとてもありがたく、いつでも歓迎します。
ABEL OLUFEMI FAMODU
ABEL OLUFEMI FAMODU | 11 6月 2025 において 20:29
とても興味深い記事だ。取引戦略を 単純化するために大いに役立つだろう。
MQL5取引ツール(第3回):戦略的取引のための多時間軸スキャナーダッシュボードの構築 MQL5取引ツール(第3回):戦略的取引のための多時間軸スキャナーダッシュボードの構築
本記事では、MQL5で多時間軸スキャナーダッシュボードを構築し、リアルタイムの取引シグナルを表示する方法を解説します。インタラクティブなグリッドインターフェースの設計、複数のインジケーターによるシグナル計算の実装、そしてクローズボタンの追加を計画しています。記事はバックテストと戦略的取引の利点で締めくくられます。
ログレコードをマスターする(第7回):チャートにログを表示する方法 ログレコードをマスターする(第7回):チャートにログを表示する方法
MetaTraderのチャート上に、フレームやタイトル、自動スクロール機能を備えたログ表示エリアを構築し、整理された形でログを確認する方法を解説します。本記事では、MQL5を用いてビジュアルログシステムを実装する手順を紹介します。これにより、ロボットの動作をリアルタイムで効率的に監視することが可能になります。
MQL5入門(第17回):トレンド反転のためのエキスパートアドバイザーの構築 MQL5入門(第17回):トレンド反転のためのエキスパートアドバイザーの構築
この記事では、トレンドラインのブレイクアウトや反転を利用したチャートパターン認識に基づいて取引をおこなうMQL5のエキスパートアドバイザー(EA)の構築方法を初心者向けに解説します。トレンドラインの値を動的に取得し、プライスアクションと比較する方法を学ぶことで、読者は上昇・下降トレンドライン、チャネル、ウェッジ、トライアングルなどのチャートパターンを識別し取引できるEAを開発できるようになります。
知っておくべきMQL5ウィザードのテクニック(第67回):TRIXパターンとWilliams Percent Rangeの使用 知っておくべきMQL5ウィザードのテクニック(第67回):TRIXパターンとWilliams Percent Rangeの使用
三重指数移動平均オシレーター(TRIX: Triple Exponential Moving Average Oscillator)とウィリアムズパーセントレンジオシレーター(WPR: Williams Percent Range)は、MQL5のエキスパートアドバイザー(EA)において併用できるもう一組のインジケーターです。このインジケーターペアは、これまで取り上げたものと同様に補完関係にあり、TRIXがトレンドを定義し、ウィリアムズパーセントレンジがサポートおよびレジスタンス水準を確認します。いつものように、MQL5ウィザードを使用して、この2つが持つ可能性をプロトタイピングします。