English Deutsch
preview
プライスアクション分析ツールキットの開発(第26回):Pin Bar, Engulfing Patterns and RSI Divergence (Multi-Pattern) Tool

プライスアクション分析ツールキットの開発(第26回):Pin Bar, Engulfing Patterns and RSI Divergence (Multi-Pattern) Tool

MetaTrader 5 |
102 0
Christian Benjamin
Christian Benjamin

はじめに

前回の記事では、ピンバー、同時線、包み足、丸坊主の4つのローソク足の形成を識別し、それらを基に認識と同時に買いまたは売りのシグナルを生成する手法に焦点を当てました。しかし、このアプローチは確認がパターン認識のみに依存していたため、誤ったシグナルが発生することがありました。

本記事では、2つの主要パターン(ピンバーと包み足)に絞った新しいツールを紹介します。これらのパターンは、RSIダイバージェンスを用いて各シグナルを確認します。RSIダイバージェンスは、以前私がプライスアクションを基に単独インジケーターとして開発したものです。パターン認識とRSIダイバージェンスを統合することで、より堅牢で強力な分析手法を構築でき、包括的なプライスアクション分析を通じて取引精度の向上と、より深い洞察を得ることができます。

まず、2つのパターンを詳しく検討し、次に戦略の概要、コード構成の詳細、バックテスト結果と分析を示します。最後に、重要なポイントをまとめます。下記の目次をご覧ください。


ローソク足パターンの理解

ローソク足パターンは、金融市場における価格変動を分析するためのテクニカル分析チャートの一種です。一定期間の市場の始値、高値、安値、終値を視覚的に表現することで、市場の方向性や心理を把握する手がかりを提供します。 ローソク足パターンには多くの種類がありますが、本記事ではピンバーと包み足の2つに焦点を当てます。これらのパターンは、上位時間足では1~2本のローソク足で現れることもあれば、下位時間足では複数本で形成されることもあります。以下の図で詳しく説明します。

最初の図(図1)は、M30時間足における弱気の包み足を示しています。このパターンは2本のローソク足で構成され、最初のローソク足は小さな実体の陽線、続くローソク足は前の陽線を包み込む大きな陰線です。

図1:M30弱気の包み足

同じパターンでも、下位時間足で表示すると複数のローソク足で表現されます。次の図(図2)は、先ほどと同じパターンをM5時間足で表示したもので、数本のローソク足で構成されていることが確認できます。

図2:M5弱気の包み足

では、本記事で焦点を当てるピンバーと包み足、およびRSIダイバージェンスについて説明を進めます。ここでは詳細には立ち入りませんが、これらの内容は前回の記事で詳しく解説しています。前回の記事はリンクから参照可能です。

ピンバー

ピンバーは、実体が小さく、ヒゲが長いローソク足の一種で、特定の価格レベルで価格が強く押し戻されたことを示します。単独のローソク足として現れることが多く、市場の反転や重要な転換点を示唆します。長いヒゲは、価格が一方向に急激に動いたものの、すぐに押し戻されたことを示しており、市場心理の変化やモメンタムの転換を意味します。

包み足

包み足は、テクニカル分析でよく使われるローソク足パターンで、市場の方向性が反転する可能性を示します。このパターンは2本の連続するローソク足で構成され、2本目の実体が1本目の実体を完全に「包み込む」ことで、市場心理の変化を示します。このパターンは反転のシグナルとして機能し、前のトレンドが終了し、新しいトレンドが始まる可能性を示唆します。大きな陽線が小さな陰線を包み込む場合は強気の反転を示し、大きな陰線が小さな陽線を包み込む場合は弱気の反転を示します。

RSIダイバージェンス

RSI(Relative Strength Index、相対力指数)のダイバージェンスは、資産価格とRSI指標が逆方向に動くときに発生し、モメンタムの変化やトレンド反転の可能性を示します。このダイバージェンスは、価格が新たな高値または安値を形成しても、RSIがそれに対応する高値や安値を形成しない場合に確認されます。ダイバージェンスには主に2つのタイプがあります。弱気ダイバージェンスは、価格が新高値を付ける一方でRSIがより低い高値を形成するときに発生し、上昇モメンタムの弱まりと今後の下落の可能性を示唆します。強気ダイバージェンスは、価格が新安値を付ける一方でRSIがより高い安値を示すときに発生し、下落モメンタムの弱まりと今後の上昇の可能性を示唆します。

RSIはモメンタムオシレーターとして価格変動の速度と変化を測定し、過買いや過売りの状況を判断するのに役立つだけでなく、ダイバージェンスを通じてモメンタムの変化やトレンド反転のシグナルも提供します。RSIが対応する動きをせずに価格が新たな極値に達した場合、勢いの潜在的な変化とトレンドの反転が示されます。

弱気のダイバージェンス

図3:弱気のRSIダイバージェンス

強気のRSIダイバージェンス

図4:強気のRSIダイバージェンス


戦略の概要

私たちのツールは、ピンバーおよび包み足パターンを徹底的に検索し、認識すると同時に、買いまたは売りのシグナルに対してRSIダイバージェンスを確認して各シグナルを検証します。言い換えると、ピンバーまたは包み足パターンが検出された場合、EAはシグナルを有効とする前にRSIダイバージェンスを確認します。RSIがパターンを確認した場合にのみ、ツールは取引シグナルを表示します。 以下の図は、ピンバーが強気のRSIダイバージェンスによって確認される様子を示しています。

図5:ピンバーの確認


コード構成の詳細

1. メタデータと初期化プロパティ

EAの最初のセクションでは、MetaTrader環境内でスクリプトを識別し、管理するために必要なメタデータが定義されます。著作権表記、リンク、およびバージョン番号は帰属とバージョン管理を提供し、ユーザーがスクリプトの出所や更新状況を把握できるようにします。#property strictディレクティブは、より厳密なコンパイルルールを適用し、潜在的なエラーを早期に検出するとともに、より適切なコーディング慣行を促進します。この設定により、EAが規定の標準に従うことが保証され、複数のスクリプトが同時に実行されている場合でも、保守、トラブルシューティング、および識別が容易になります。

//+------------------------------------------------------------------+
//|                                           Multi-Pattern Signal EA|
//|                                   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

2. ライブラリの追加とユーザー入力の定義

EAは、<Trade/Trade.mqh>ライブラリを読み込むことで、注文の操作(取引のオープン、クローズ、管理など)を可能にしています。このバージョンでは主にパターン検出とアラートに焦点を当てていますが、取引ライブラリを統合しておくことで、将来的に自動取引への拡張も可能になります。入力パラメータはカスタマイズにおいて重要です。トレーダーは、RSI期間を調整して感度を変更したり、ダイバージェンス検出用の過買い・過売りの閾値を設定したり、ストップロスやテイクプロフィットのレベルをポイント(pips)単位で設定したりできます。

EntryBufferは、直近の高値・安値に近すぎるエントリーを防ぐバッファゾーンとして機能し、誤ったシグナルを減らします。通知フラグは、サウンドアラート、プッシュ通知、メールの有効・無効を切り替えることができ、トレーダーがアラート受信方法を制御できます。これらのパラメータにより、EAはさまざまな取引スタイルや市場状況に柔軟に対応可能となります。

#include <Trade/Trade.mqh>

input int    RSI_Period     = 14;      // RSI calculation period
input double RSI_Overbought = 70.0;    // RSI level indicating overbought
input double RSI_Oversold   = 30.0;    // RSI level indicating oversold
input double SL_Pips        = 20.0;    // Default stop loss in pips
input double TP_Pips        = 20.0;    // Default take profit in pips
input double EntryBuffer    = 5.0;     // Buffer in points for entry price
input bool   EnableSound    = true;    // Enable sound alerts
input bool   EnablePush     = true;    // Enable push notifications
input bool   EnableEmail    = false;   // Enable email alerts

3. 初期化:インジケーターハンドルとバッファの作成

初期設定の段階で、EAはiRSI()を使用してRSIインジケーターのハンドルを作成します。ここでは、銘柄、期間、RSIパラメータが指定されます。このハンドルは、各ティックごとにリアルタイムのRSI値を取得するために不可欠であり、ダイバージェンス検出の基盤となります。配列は系列として設定されており、常に最新のデータがインデックス0に格納される仕様です。時間、始値、高値、安値、終値の内部バッファも初期化され、分析用の過去データを格納できるようになっています。lastBarTime変数は、最後に処理されたローソク足のタイムスタンプを追跡し、同じローソク足内で複数のシグナルが生成されるのを防ぎます。これにより、冗長なアラートを避けつつ、シグナルの正確性が確保されます。

int OnInit()
{
    rsiHandle = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE);
    if(rsiHandle == INVALID_HANDLE)
        return INIT_FAILED;

    // Set arrays as series for easier access to recent data
    ArraySetAsSeries(rsiBuffer,   true);
    ArraySetAsSeries(timeBuffer,  true);
    ArraySetAsSeries(openBuffer,  true);
    ArraySetAsSeries(highBuffer,  true);
    ArraySetAsSeries(lowBuffer,   true);
    ArraySetAsSeries(closeBuffer, true);

    return INIT_SUCCEEDED;
}

4. OnTick()における継続的なデータ監視と処理

OnTick()関数は、市場の各ティックごとに実行され、EAのコアループとして機能します。まず、少なくとも20本のローソク足が利用可能であることを確認し、パターン認識に十分な過去データがあることを保証します。その後、最新の20本のタイムスタンプおよび価格データ(始値、高値、安値、終値)を内部バッファにコピーします。このステップは、市場データが常に更新されており、分析が最近かつ正確なデータに依存しているため非常に重要です。コピー操作が失敗した場合、エラーや誤ったシグナルを防ぐために処理を停止します。

同じローソク足内で複数のシグナルが生成されるのを防ぐために、前回のローソク足のタイムスタンプがlastBarTimeと一致するかどうかを確認します。一致する場合は処理をスキップし、一致しない場合はlastBarTimeを新しいローソク足のタイムスタンプで更新します。その後、RSIデータを更新します。データが準備できたら、FindSignalBar()を呼び出し、直近のローソク足を解析してダイバージェンスパターンやローソク足シグナルを検出し、アラート生成の基礎とします。

void OnTick()
{
    // Ensure enough data is available
    if(Bars(_Symbol, _Period) < 20)
        return;

    // Copy recent market data
    if(CopyTime(_Symbol, _Period, 0, 20, timeBuffer)   <= 0 ||
       CopyOpen(_Symbol, _Period, 0, 20, openBuffer)   <= 0 ||
       CopyHigh(_Symbol, _Period, 0, 20, highBuffer)   <= 0 ||
       CopyLow(_Symbol, _Period, 0, 20, lowBuffer)     <= 0 ||
       CopyClose(_Symbol, _Period, 0, 20, closeBuffer) <= 0)
       return;

    // Prevent multiple signals in the same candle
    if(timeBuffer[1] == lastBarTime)
        return;
    lastBarTime = timeBuffer[1];

    // Update RSI data
    if(CopyBuffer(rsiHandle, 0, 0, 20, rsiBuffer) <= 0)
        return;

    // Detect potential divergence and pattern
    int dir = FindSignalBar();
    if(dir == 0)
        return;

    // Determine direction and compute entry/stop levels
    bool isBullish = (dir > 0);
    int idx = 1; // most recent completed bar
    double entry = isBullish
                   ? highBuffer[idx] + EntryBuffer * _Point
                   : lowBuffer[idx] - EntryBuffer * _Point;
    double stopL = isBullish
                   ? lowBuffer[idx] - SL_Pips * _Point
                   : highBuffer[idx] + SL_Pips * _Point;

    // Visualize and notify
    DrawSignal(idx, isBullish, entry, stopL);
}

5. ダイバージェンスおよびローソク足分析によるパターン認識

FindSignalBar()関数は、潜在的な反転シグナルを特定する上で重要な役割を果たします。直近のローソク足(過去5~15本)をスキャンして、ダイバージェンスパターンを検出します。強気のダイバージェンスは、安値が上昇している一方でRSIが売られすぎレベルを下回る場合に確認され、上方への反転の可能性を示唆します。逆に弱気のダイバージェンスは、高値が下落している一方でRSIが買われすぎレベルを超える場合に発生し、下方への動きの可能性を示します。

この関数はまた、最新のローソク足に対して、反転のサインとして知られるピンバーや包み足といった補助的なローソク足パターンも確認します。ダイバージェンス条件とパターン条件の両方が満たされる場合、強気シグナルでは+1、弱気シグナルでは-1を返します。条件が満たされない場合は0を返し、その時点では有効なセットアップがないことを示します。この階層的なアプローチにより、モメンタムのダイバージェンスと価格変動のパターンを組み合わせ、シグナルの信頼性を向上させています。

int FindSignalBar()
{
    bool bullDiv = false, bearDiv = false;
    for(int i = 5; i <= 15; i++)
    {
        // Bullish divergence condition
        if(lowBuffer[i] > lowBuffer[1] && rsiBuffer[i] < rsiBuffer[1] && rsiBuffer[1] < RSI_Oversold)
            bullDiv = true;
        // Bearish divergence condition
        if(highBuffer[i] < highBuffer[1] && rsiBuffer[i] > rsiBuffer[1] && rsiBuffer[1] > RSI_Overbought)
            bearDiv = true;
    }

    // No divergence detected
    if(!bullDiv && !bearDiv)
        return 0;

    // Check for candlestick patterns supporting divergence
    bool bullPat = IsBullishPinBar(1) || IsBullishEngulfing(1);
    bool bearPat = IsBearishPinBar(1) || IsBearishEngulfing(1);

    // Confirmed signals
    if(bullDiv && bullPat)
        return +1;
    if(bearDiv && bearPat)
        return -1;

    return 0; // No valid signal
}

6. 反転確認のためのローソク足パターン検出

これらの関数は、個々のローソク足を分析して反転シグナルを確認します。IsBullishPinBar()は、ローソク足の実体が小さく下ヒゲが長い場合を確認し、安値が拒絶されたことを示す強気の反転の可能性を示唆します。IsBearishPinBar()はその逆を確認します。IsBullishEngulfing()は、現在のローソク足の実体が前のローソク足を包み込む場合を確認し、強い買い圧力を示します。一方IsBearishEngulfing()は強い売り圧力を示します。これらのパターン検出関数は、ローソク足の実体とヒゲの比率を高値と安値の範囲に対して測定することで、形の整ったパターンのみを判定対象とし、誤検知を減らしてシグナルの信頼性を向上させています。

// Bullish Pin Bar Pattern
bool IsBullishPinBar(int i)
{
    double body = MathAbs(openBuffer[i] - closeBuffer[i]);
    double rng  = highBuffer[i] - lowBuffer[i];
    double lw   = MathMin(openBuffer[i], closeBuffer[i]) - lowBuffer[i];
    double uw   = highBuffer[i] - MathMax(openBuffer[i], closeBuffer[i]);
    return closeBuffer[i] > openBuffer[i]
           && lw > 2.0 * body
           && uw < 0.5 * body
           && body > 0.1 * rng;
}

// Bearish Pin Bar Pattern
bool IsBearishPinBar(int i)
{
    double body = MathAbs(openBuffer[i] - closeBuffer[i]);
    double rng  = highBuffer[i] - lowBuffer[i];
    double uw   = highBuffer[i] - MathMax(openBuffer[i], closeBuffer[i]);
    double lw   = MathMin(openBuffer[i], closeBuffer[i]) - lowBuffer[i];
    return closeBuffer[i] < openBuffer[i]
           && uw > 2.0 * body
           && lw < 0.5 * body
           && body > 0.1 * rng;
}

// Bullish Engulfing Pattern
bool IsBullishEngulfing(int i)
{
    if(closeBuffer[i] <= openBuffer[i])
        return false;
    if(openBuffer[i] > closeBuffer[i+1])
        return false;
    if(closeBuffer[i] < openBuffer[i+1])
        return false;
    return true;
}

// Bearish Engulfing Pattern
bool IsBearishEngulfing(int i)
{
    if(closeBuffer[i] >= openBuffer[i])
        return false;
    if(openBuffer[i] < closeBuffer[i+1])
        return false;
    if(closeBuffer[i] > openBuffer[i+1])
        return false;
    return true;
}

7. 可視化とアラート生成

有効なパターンとダイバージェンスが確認されると、DrawSignal()はエントリーポイントに矢印を描画し、エントリーおよびストップロスレベルに水平線を引き、ダイバージェンスパターンを示すトレンドラインを描画してセットアップを可視化します。矢印の色とコードは方向を反映しており、緑系は強気、赤系は弱気を示します。トレンドラインは直近の安値または高値を結び、ダイバージェンスを視覚的に確認できるようにします。

また、この関数は、パターンの種類、方向、銘柄、時間、エントリーおよびストップロスレベルを含む詳細なアラートメッセージを作成します。その後、ユーザーの設定に応じて、サウンドの再生、プッシュ通知、メール送信をトリガーし、トレーダーが迅速に情報を受け取り、すぐに対応できるようにします。この包括的な可視化およびアラートシステムにより、状況認識と意思決定の精度が向上します。

void DrawSignal(int i, bool isBullish, double entry, double stopL)
{
    string tag = TimeToString(timeBuffer[i], TIME_SECONDS);
    string nameA = "Arr_" + tag;
    string nameE = "Ent_" + tag;
    string nameS = "SL_" + tag;
    string nameL = "Div_" + tag;

    color clrArr = isBullish ? clrLime : clrRed;
    int code = isBullish ? 233 : 234;

    // Arrow at entry point
    ObjectCreate(0, nameA, OBJ_ARROW, 0, timeBuffer[i], entry);
    ObjectSetInteger(0, nameA, OBJPROP_COLOR, clrArr);
    ObjectSetInteger(0, nameA, OBJPROP_ARROWCODE, code);
    ObjectSetInteger(0, nameA, OBJPROP_WIDTH, 2);

    // Horizontal lines for entry and stop-loss
    ObjectCreate(0, nameE, OBJ_HLINE, 0, 0, entry);
    ObjectSetInteger(0, nameE, OBJPROP_COLOR, clrAqua);
    ObjectCreate(0, nameS, OBJ_HLINE, 0, 0, stopL);
    ObjectSetInteger(0, nameS, OBJPROP_COLOR, clrOrangeRed);
    ObjectSetInteger(0, nameS, OBJPROP_STYLE, STYLE_DASH);

    // Divergence trend line for visual confirmation
    for(int j = i + 5; j < i + 15; j++)
    {
        if(isBullish && lowBuffer[j] > lowBuffer[i])
        {
            ObjectCreate(0, nameL, OBJ_TREND, 0,
                         timeBuffer[j], lowBuffer[j],
                         timeBuffer[i], lowBuffer[i]);
            ObjectSetInteger(0, nameL, OBJPROP_COLOR, clrDodgerBlue);
            break;
        }
        if(!isBullish && highBuffer[j] < highBuffer[i])
        {
            ObjectCreate(0, nameL, OBJ_TREND, 0,
                         timeBuffer[j], highBuffer[j],
                         timeBuffer[i], highBuffer[i]);
            ObjectSetInteger(0, nameL, OBJPROP_COLOR, clrOrange);
            break;
        }
    }

    // Construct alert message
    string pattern = isBullish
                     ? (IsBullishEngulfing(i) ? "Engulfing" : "PinBar")
                     : (IsBearishEngulfing(i) ? "Engulfing" : "PinBar");
    string side = isBullish ? "Buy" : "Sell";
    string txt = StringFormat(
                     "%s + RSI Divergence %s Signal\nSymbol: %s\nTime: %s\nEntry: %.5f\nSL: %.5f",
                     pattern, side, _Symbol,
                     TimeToString(timeBuffer[i], TIME_MINUTES),
                     entry, stopL
                 );

    // Notify trader
    Alert(txt);
    if(EnableSound)
        PlaySound("alert.wav");
    if(EnablePush)
        SendNotification(txt);
    if(EnableEmail)
        SendMail("Signal EA Alert", txt);

    Print(txt);
}

完全なMQL5 EA

//+------------------------------------------------------------------+
//|                                           Multi-Pattern Signal EA|
//|                                   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

#include <Trade/Trade.mqh>

input int    RSI_Period     = 14;
input double RSI_Overbought = 70.0;
input double RSI_Oversold   = 30.0;
input double SL_Pips        = 20.0;  // in pips
input double TP_Pips        = 20.0;  // in pips
input double EntryBuffer    = 5.0;   // in points
input bool   EnableSound    = true;
input bool   EnablePush     = true;
input bool   EnableEmail    = false;

CTrade   trade;

// internal buffers
double   rsiBuffer[];
datetime timeBuffer[];
double   openBuffer[], highBuffer[], lowBuffer[], closeBuffer[];
int      rsiHandle;
datetime lastBarTime = 0;

//+------------------------------------------------------------------+
int OnInit()
  {
   rsiHandle = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE);
   if(rsiHandle == INVALID_HANDLE)
      return INIT_FAILED;

   ArraySetAsSeries(rsiBuffer,   true);
   ArraySetAsSeries(timeBuffer,  true);
   ArraySetAsSeries(openBuffer,  true);
   ArraySetAsSeries(highBuffer,  true);
   ArraySetAsSeries(lowBuffer,   true);
   ArraySetAsSeries(closeBuffer, true);

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
void OnTick()
  {
   if(Bars(_Symbol,_Period) < 20)
      return;

   if(CopyTime(_Symbol,_Period,0,20,timeBuffer)   <= 0 ||
      CopyOpen(_Symbol,_Period,0,20,openBuffer)   <= 0 ||
      CopyHigh(_Symbol,_Period,0,20,highBuffer)   <= 0 ||
      CopyLow(_Symbol,_Period,0,20,lowBuffer)     <= 0 ||
      CopyClose(_Symbol,_Period,0,20,closeBuffer) <= 0)
      return;

   if(timeBuffer[1] == lastBarTime)
      return;
   lastBarTime = timeBuffer[1];

   if(CopyBuffer(rsiHandle,0,0,20,rsiBuffer) <= 0)
      return;

   int dir = FindSignalBar();
   if(dir == 0)
      return;

   int idx = 1;
   bool isBullish = (dir > 0);

   double entry = isBullish
                  ? highBuffer[idx] + EntryBuffer * _Point
                  : lowBuffer[idx]  - EntryBuffer * _Point;
   double stopL = isBullish
                  ? lowBuffer[idx]  - SL_Pips * _Point
                  : highBuffer[idx] + SL_Pips * _Point;

   DrawSignal(idx, isBullish, entry, stopL);
  }

//+------------------------------------------------------------------+
int FindSignalBar()
  {
   bool bullDiv = false, bearDiv = false;
   for(int i = 5; i <= 15; i++)
     {
      if(lowBuffer[i] > lowBuffer[1] && rsiBuffer[i] < rsiBuffer[1] && rsiBuffer[1] < RSI_Oversold)
         bullDiv = true;
      if(highBuffer[i] < highBuffer[1] && rsiBuffer[i] > rsiBuffer[1] && rsiBuffer[1] > RSI_Overbought)
         bearDiv = true;
     }
   if(!bullDiv && !bearDiv)
      return 0;

   bool bullPat = IsBullishPinBar(1) || IsBullishEngulfing(1);
   bool bearPat = IsBearishPinBar(1) || IsBearishEngulfing(1);

   if(bullDiv && bullPat)
      return +1;
   if(bearDiv && bearPat)
      return -1;
   return 0;
  }

//+------------------------------------------------------------------+
bool IsBullishPinBar(int i)
  {
   double body = MathAbs(openBuffer[i] - closeBuffer[i]);
   double rng  = highBuffer[i] - lowBuffer[i];
   double lw   = MathMin(openBuffer[i], closeBuffer[i]) - lowBuffer[i];
   double uw   = highBuffer[i] - MathMax(openBuffer[i], closeBuffer[i]);
   return closeBuffer[i] > openBuffer[i]
          && lw > 2.0 * body
          && uw < 0.5 * body
          && body > 0.1 * rng;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsBearishPinBar(int i)
  {
   double body = MathAbs(openBuffer[i] - closeBuffer[i]);
   double rng  = highBuffer[i] - lowBuffer[i];
   double uw   = highBuffer[i] - MathMax(openBuffer[i], closeBuffer[i]);
   double lw   = MathMin(openBuffer[i], closeBuffer[i]) - lowBuffer[i];
   return closeBuffer[i] < openBuffer[i]
          && uw > 2.0 * body
          && lw < 0.5 * body
          && body > 0.1 * rng;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsBullishEngulfing(int i)
  {
   if(closeBuffer[i] <= openBuffer[i])
      return false;
   if(openBuffer[i]  > closeBuffer[i+1])
      return false;
   if(closeBuffer[i] < openBuffer[i+1])
      return false;
   return true;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsBearishEngulfing(int i)
  {
   if(closeBuffer[i] >= openBuffer[i])
      return false;
   if(openBuffer[i]  < closeBuffer[i+1])
      return false;
   if(closeBuffer[i] > openBuffer[i+1])
      return false;
   return true;
  }

//+------------------------------------------------------------------+
void DrawSignal(int i, bool isBullish, double entry, double stopL)
  {
   string tag   = TimeToString(timeBuffer[i], TIME_SECONDS);
   string nameA = "Arr_" + tag;
   string nameE = "Ent_" + tag;
   string nameS = "SL_"  + tag;
   string nameL = "Div_" + tag;

   color clrArr = isBullish ? clrLime : clrRed;
   int   code   = isBullish ? 233 : 234;

   ObjectCreate(0, nameA, OBJ_ARROW, 0, timeBuffer[i], entry);
   ObjectSetInteger(0, nameA, OBJPROP_COLOR, clrArr);
   ObjectSetInteger(0, nameA, OBJPROP_ARROWCODE, code);
   ObjectSetInteger(0, nameA, OBJPROP_WIDTH, 2);

   ObjectCreate(0, nameE, OBJ_HLINE, 0, 0, entry);
   ObjectSetInteger(0, nameE, OBJPROP_COLOR, clrAqua);
   ObjectCreate(0, nameS, OBJ_HLINE, 0, 0, stopL);
   ObjectSetInteger(0, nameS, OBJPROP_COLOR, clrOrangeRed);
   ObjectSetInteger(0, nameS, OBJPROP_STYLE, STYLE_DASH);

   for(int j = i + 5; j < i + 15; j++)
     {
      if(isBullish && lowBuffer[j] > lowBuffer[i])
        {
         ObjectCreate(0, nameL, OBJ_TREND, 0,
                      timeBuffer[j], lowBuffer[j],
                      timeBuffer[i], lowBuffer[i]);
         ObjectSetInteger(0, nameL, OBJPROP_COLOR, clrDodgerBlue);
         break;
        }
      if(!isBullish && highBuffer[j] < highBuffer[i])
        {
         ObjectCreate(0, nameL, OBJ_TREND, 0,
                      timeBuffer[j], highBuffer[j],
                      timeBuffer[i], highBuffer[i]);
         ObjectSetInteger(0, nameL, OBJPROP_COLOR, clrOrange);
         break;
        }
     }

   string pattern = isBullish
                    ? (IsBullishEngulfing(i) ? "Engulfing" : "PinBar")
                    : (IsBearishEngulfing(i) ? "Engulfing" : "PinBar");
   string side    = isBullish ? "Buy" : "Sell";
   string txt     = StringFormat(
                       "%s + RSI Divergence %s Signal\nSymbol: %s\nTime: %s\nEntry: %.5f\nSL: %.5f",
                       pattern, side, _Symbol,
                       TimeToString(timeBuffer[i], TIME_MINUTES),
                       entry, stopL
                    );

   Alert(txt);
   if(EnableSound)
      PlaySound("alert.wav");
   if(EnablePush)
      SendNotification(txt);
   if(EnableEmail)
      SendMail("Signal EA Alert", txt);
   Print(txt);
  }
//+------------------------------------------------------------------+


バックテストと結果

バックテストは、過去の市場データを用いて取引戦略を評価し、過去にどのように機能したかを推定するプロセスです。このシミュレーションにより、トレーダーは事前に定義したルールが実際の市場条件下でどのように機能したかを確認でき、潜在的な収益性やリスクについての洞察を得ることができます。シミュレーション取引の結果を分析することで、トレーダーはその戦略を実際の取引に適用するかどうかを判断するための情報を得られます。

バックテストの最初のステップは、取引戦略を明確に定義することです。これには、エントリーおよびエグジットのルールを具体的に設定することが含まれます。使用するインディケーター、価格パターン、その他の条件が買いまたは売りのシグナルを引き起こすかを明確にする必要があります。明確に定義された戦略は、一貫したテストと正確な結果を保証します。次に、トレーダーは分析対象の期間に対応する過去の価格チャート、出来高、その他の関連情報など、関連する履歴データを収集する必要があります。正確かつ包括的なデータは、信頼性の高いバックテスト結果を得るために不可欠です。

適切なバックテストプラットフォームを選択することも重要です。手動分析が可能なツールや、完全自動テストをサポートするツールなど、さまざまなソフトウェアが存在します。選択するプラットフォームは、戦略ルールに基づいて正確に取引をシミュレートでき、詳細なパフォーマンス指標を提供できるものである必要があります。プラットフォームを選択したら、バックテスト環境を設定します。これには、時間軸、取引コスト、スリッページ、その他のパフォーマンスに影響する要素の設定が含まれ、シミュレーションが実際の取引条件を可能な限り反映するようにします。

設定が完了したら、次に戦略を適用してバックテストを実行します。プラットフォームは、事前に定義したルールと過去の市場データに従ってシミュレーション取引を生成します。このプロセス中、結果を詳細に分析することが重要です。総利益・損失、勝率、最大ドローダウン、リスクリワード比率などの主要指標は、戦略の有効性と堅牢性を評価する上で有益な情報を提供します。

分析に基づき、トレーダーは戦略を改善・最適化すべきです。パラメータやルールの調整によってパフォーマンスを向上させ、テスト中に特定された弱点に対処できます。戦略の信頼性を確保し、過学習を避けるためには、サンプル外データでの検証が不可欠です。別の過去データセットで改善した戦略を実行することで、その堅牢性と実際の市場での有効性を確認できます。

以下は私がおこなったバックテストの結果です。

図6:強気包み足の確認

上図(図6)は、EURUSDのM30時間足でバックテストを行ったスクリーンショットを示しており、強気の包み足パターンが強気のダイバージェンスによって確認されている様子を表しています。

図7:USDCHFバックテスト

上図(図7)は、EURUSDのM30時間足でバックテストを行ったスクリーンショットを示しており、強気の包み足パターンが強気のダイバージェンスによって確認されています。さらに、下に示すGIFはUSDCHFペアでのバックテストの様子を示しており、複数のシグナルがどのように特定されたかをハイライトしています。


結論

このEAは、取引戦略におけるパターン認識およびダイバージェンス検出の高度なアプローチの例を示しています。RSIのようなテクニカル指標と、ピンバーや包み足といったローソク足パターン分析を組み合わせることで、高確率の反転シグナルを効果的に特定します。EAのモジュール設計により、直近の市場データをリアルタイムで分析し、チャート上に視覚的シグナルを生成し、タイムリーなアラートを送信できるため、体系的かつ規律あるエントリーを目指すトレーダーにとって有用なツールとなります。 

バックテストの結果から、このEAは特に複数の条件でシグナルが確認された場合に高い勝率を達成できることが示されています。しかし、すべての自動取引戦略と同様に、異なる通貨ペアや市場状況での堅牢性をサンプル外データで検証することが重要です。適切なパラメータ最適化とリスク管理は、収益性を最大化しドローダウンを軽減するために不可欠です。総じて、このEAはパターン認識とダイバージェンス分析を組み合わせる可能性を示しており、今後の機械学習統合や、取引システムにおける高度な意思決定の基盤として有望であることを示しています。


日付 ツール名  詳細 バージョン  アップデート  備考
01/10/24 ChartProjector 前日のプライスアクションをゴースト効果でオーバーレイするスクリプト 1.0 初回リリース ツール番号1
18/11/24 Analytical Comment 前日の情報を表形式で提供し、市場の将来の方向性を予測する 1.0 初回リリース ツール番号2
27/11/24 Analytics Master 2時間ごとに市場指標を定期的に更新  1.01 v.2 ツール番号3
02/12/24 Analytics Forecaster  Telegram統合により、2時間ごとに市場指標を定期的に更新 1.1 v.3 ツール番号4
09/12/24 Volatility Navigator ボリンジャーバンド、RSI、ATR指標を使用して市場の状況を分析するEA 1.0 初回リリース ツール番号5
19/12/24 Mean Reversion Signal Reaper  平均回帰戦略を用いて市場を分析し、シグナルを提供する  1.0  初回リリース  ツール番号6 
9/01/25  Signal Pulse  多時間枠分析ツール 1.0  初回リリース  ツール番号7 
17/01/25  Metrics Board  分析用のボタン付きパネル  1.0  初回リリース ツール番号8 
21/01/25 External Flow 外部ライブラリによる分析 1.0  初回リリース ツール番号9 
27/01/25 VWAP 出来高加重平均価格   1.3  初回リリース  ツール番号10 
02/02/25  Heikin Ashi  トレンドの平滑化と反転シグナルの識別  1.0  初回リリース  ツール番号11
04/02/25  FibVWAP  Python分析によるシグナル生成  1.0  初回リリース  ツール番号12
14/02/25  RSI DIVERGENCE  プライスアクションとRSIのダイバージェンス  1.0  初回リリース  ツール番号13 
17/02/25  Parabolic Stop and Reverse (PSAR)  PSAR戦略の自動化 1.0 初回リリース  ツール番号14
20/02/25  Quarters Drawerスクリプト チャートにクォーターレベルを描く  1.0  初回リリース  ツール番号15 
27/02/25  Intrusion Detector 価格がクォーターレベルに達したときに検出して警告する 1.0   初回リリース ツール番号16 
27/02/25  TrendLoom Tool 多時間枠分析パネル 1.0 初回リリース ツール番号17
11/03/25  Quarters Board  クォーターレベルを有効または無効にするボタン付きのパネル  1.0  初回リリース ツール番号18
26/03/25  ZigZag Analyzer  ジグザグインジケーターを使ったトレンドラインの描画  1.0  初回リリース  ツール番号19 
10/04/25  Correlation Pathfinder Pythonライブラリを使用して通貨の相関関係をプロットする 1.0 初回リリース  ツール番号20 
23/04/25 Market Structure Flip Detector Tool 市場構造反転を検出する 1.0  初回リリース  ツール番号21
08/05/25  Correlation Dashboard  異なるペア間の関係 1.0 初回リリース ツール番号22 
13/05/25 Currency Strength Meter  各通貨ペアの強さを測定する 1.0 初回リリース ツール番号23 
21/05/25 PAQ Analysis Tool  ローソク足形成検出器 1.0 初回リリース ツール番号24 
23/05/25 Pin bar, Engulfing and RSI divergence RSIダイバージェンスを使用してピンバーと包み足のシグナルを確認する  1.0 初回リリース ツール番号25 

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

MetaTrader 5機械学習の設計図(第1回):データリーケージとタイムスタンプの修正 MetaTrader 5機械学習の設計図(第1回):データリーケージとタイムスタンプの修正
MetaTrader 5で機械学習を取引に活用する以前に、最も見落とされがちな落とし穴の一つであるデータリーケージに対処することが極めて重要です。本記事では、データリーケージ、特にMetaTrader 5のタイムスタンプの罠がどのようにモデルのパフォーマンスを歪め、信頼性の低い売買シグナルにつながるのかを解説します。この問題の仕組みに踏み込み、その防止戦略を提示することで、実取引環境で信頼できる予測を提供する堅牢な機械学習モデルを構築するための道を切り開きます。
MQL5入門(第17回):トレンド反転のためのエキスパートアドバイザーの構築 MQL5入門(第17回):トレンド反転のためのエキスパートアドバイザーの構築
この記事では、トレンドラインのブレイクアウトや反転を利用したチャートパターン認識に基づいて取引をおこなうMQL5のエキスパートアドバイザー(EA)の構築方法を初心者向けに解説します。トレンドラインの値を動的に取得し、プライスアクションと比較する方法を学ぶことで、読者は上昇・下降トレンドライン、チャネル、ウェッジ、トライアングルなどのチャートパターンを識別し取引できるEAを開発できるようになります。
知っておくべきMQL5ウィザードのテクニック(第68回): コサインカーネルネットワークでTRIXとWPRのパターンを使用する 知っておくべきMQL5ウィザードのテクニック(第68回): コサインカーネルネットワークでTRIXとWPRのパターンを使用する
前回の記事では、TRIXとWilliams Percent Range (WPR)の指標ペアを紹介しましたが、今回はこの指標ペアを機械学習で拡張する方法について検討します。TRIXとWPRは、トレンド指標とサポート/レジスタンス補完ペアとして組み合わせられます。本機械学習アプローチでは、畳み込みニューラルネットワーク(CNN)を使用し、予測精度を微調整する際にコサインカーネルをアーキテクチャに組み込んでいます。これは常に、MQL5ウィザードと連携してエキスパートアドバイザー(EA)を組み立てるカスタムシグナルクラスファイル内で行われます。。
MQL5取引ツール(第3回):戦略的取引のための多時間軸スキャナーダッシュボードの構築 MQL5取引ツール(第3回):戦略的取引のための多時間軸スキャナーダッシュボードの構築
本記事では、MQL5で多時間軸スキャナーダッシュボードを構築し、リアルタイムの取引シグナルを表示する方法を解説します。インタラクティブなグリッドインターフェースの設計、複数のインジケーターによるシグナル計算の実装、そしてクローズボタンの追加を計画しています。記事はバックテストと戦略的取引の利点で締めくくられます。