自作EA 既存インジケーターを表示させてテストしてみる

この記事は約28分で読めます。

MQL5で既存の内蔵インジケーター(例:移動平均(MA)やボリンジャーバンド(BB))をチャートに表示させると、売買タイミングやEAの動作を視覚的に確認でき、トレーディング戦略の理解やデバッグが容易になります。前の質問で扱った「2時間足(H2)と15分足(M15)の移動平均(MA)クロスを売買タイミングの指標とし、ボリンジャーバンド(BB)2σ超えをオプション条件とするEA」に、既存の内蔵インジケーター(H2_MA、M15_MA、BB)をチャートに表示する機能を追加することは可能です。以下の回答では、以下のポイントを踏まえて解説とコードを提供します:

【免責事項】私は投資アドバイザーではありません。投資判断はご自身で行い、必要に応じてファイナンシャルアドバイザーに相談してください。この記事は自身の勉強を目的としており、EAの動作保証や生じた損失に対しても一切の責任を負いません。

  1. 既存インジケーターの表示:
    • MT5の内蔵インジケーター(iMA, iBands)をチャートに表示。
    • H2_MAをM15チャートにマルチタイムフレーム(MTF)で表示。
    • M15_MAとBB(オプション)をM15チャートに表示。
  2. 視覚的メリット:
    • MAクロスやBB 2σ超えのタイミングを視覚的に確認。
    • EAの売買シグナルが正しいか直感的に把握。
  3. EAとの統合:
    • 前のコード(H2/M15 MAクロス、BB 2σ、ATRベースSL、RR/BBベースTP、トレーリングストップ)をベースに、インジケーター表示を追加。
  4. 自動計算の維持:
    • インジケーター表示は視覚化専用で、EAの売買ロジックは内部計算で処理。

ステップ1: 視覚的メリットと実現方法視覚的メリット

  • 売買タイミングの確認:
    • H2_MAとM15_MAのクロスポイントをチャートで視覚化し、EAの買い/売りシグナルが正確か確認。
    • BB 2σの上下限と価格の関係を視覚化し、価格が2σを超えたタイミングを把握。
  • デバッグの容易さ:
    • インジケーターが表示されることで、コードの誤り(例:誤ったMA値やクロス判定)を発見しやすくなる。
  • 戦略の理解:
    • トレーダーにとって、MAクロスやBBの動きを視覚的に追うことで、戦略の意図を直感的に理解可能。

実現方法

  • MT5内蔵インジケーターの表示:
    • IndicatorCreate()関数を使用して、M15チャートにH2_MA、M15_MA、BBを表示。
    • iMAとiBandsのハンドルを作成し、チャートに追加。
  • マルチタイムフレーム(MTF)対応:
    • H2_MAをM15チャートに表示するため、IndicatorCreate()でPERIOD_H2を指定。
  • EAとの分離:
    • インジケーター表示は視覚化専用で、EAの売買ロジックはCopyBuffer()で内部計算。
    • インジケーターを別ウィンドウやチャート上にオーバーレイ表示。

ステップ2: サンプルコード(インジケーター表示+EA)以下のコードは、前のEA(H2/M15 MAクロス、BB 2σオプション、ATRベースSL、RR/BBベースTP、トレーリングストップ)に、H2_MA、M15_MA、BBをチャートに表示する機能を追加したものです。インジケーターはM15チャートに表示され、H2_MAはMTFで描画されます。

mql5

//+------------------------------------------------------------------+
//| 入力パラメータ                                                   |
//+------------------------------------------------------------------+
input int maH2Period = 20;          // H2移動平均期間
input int maM15Period = 20;         // M15移動平均期間
input bool useBBFilter = false;     // BB 2σフィルターを使用
input int bbPeriod = 20;            // ボリンジャーバンド期間(M15)
input double bbDeviation = 2.0;     // BB標準偏差(2σ)
input double lotSize = 0.1;         // ロットサイズ
input int atrPeriod = 14;           // ATR期間
input double atrMultiplier = 2.0;   // ATR倍率(SL用)
input double riskRewardRatio = 2.0; // リスクリワードレシオ(TP用)
input bool useBBTP = true;          // BBをTPに使用
input bool useTrailingStop = true;  // トレーリングストップ使用
input int trailingStart = 20;       // トレーリング開始(ポイント)
input int trailingStep = 10;        // トレーリングステップ(ポイント)
input bool displayIndicators = true; // インジケーターをチャートに表示

// グローバル変数
int handleMaH2, handleMaM15, handleBB, handleATR;

//+------------------------------------------------------------------+
//| EA初期化                                                         |
//+------------------------------------------------------------------+
void OnInit() {
   // インジケーターハンドルの作成(内部計算用)
   handleMaH2 = iMA(_Symbol, PERIOD_H2, maH2Period, 0, MODE_SMA, PRICE_CLOSE);
   handleMaM15 = iMA(_Symbol, PERIOD_M15, maM15Period, 0, MODE_SMA, PRICE_CLOSE);
   handleATR = iATR(_Symbol, PERIOD_M15, atrPeriod);
   if(useBBFilter || useBBTP) {
      handleBB = iBands(_Symbol, PERIOD_M15, bbPeriod, 0, bbDeviation, PRICE_CLOSE);
   }
   
   // ハンドル作成のエラーチェック
   if(handleMaH2 == INVALID_HANDLE || handleMaM15 == INVALID_HANDLE || 
      handleATR == INVALID_HANDLE || ((useBBFilter || useBBTP) && handleBB == INVALID_HANDLE)) {
      Print("インジケーターハンドル作成に失敗");
      ExpertRemove();
   }
   
   // インジケーターをチャートに表示(displayIndicatorsがtrueの場合)
   if(displayIndicators) {
      // H2_MAを表示(MTF)
      int subWindow = 0; // メインウィンドウ
      if(!IndicatorCreate(_Symbol, PERIOD_M15, IND_MA, 0, maH2Period, 0, MODE_SMA, PRICE_CLOSE)) {
         Print("H2_MA表示失敗、エラーコード: ", GetLastError());
      }
      // M15_MAを表示
      if(!IndicatorCreate(_Symbol, PERIOD_M15, IND_MA, 0, maM15Period, 0, MODE_SMA, PRICE_CLOSE)) {
         Print("M15_MA表示失敗、エラーコード: ", GetLastError());
      }
      // BBを表示(useBBFilterまたはuseBBTPがtrueの場合)
      if(useBBFilter || useBBTP) {
         if(!IndicatorCreate(_Symbol, PERIOD_M15, IND_BANDS, 0, bbPeriod, 0, bbDeviation, PRICE_CLOSE)) {
            Print("BB表示失敗、エラーコード: ", GetLastError());
         }
      }
   }
   
   Print("EA初期化完了");
}

//+------------------------------------------------------------------+
//| 新しいティックごとの処理                                          |
//+------------------------------------------------------------------+
void OnTick() {
   // M15チャートでのみ動作
   if(Period() != PERIOD_M15) return;
   
   // インジケーターデータの取得(最新3本分)
   double maH2[], maM15[], bbUpper[], bbLower[], atr[];
   if(CopyBuffer(handleMaH2, 0, 0, 3, maH2) <= 0 ||
      CopyBuffer(handleMaM15, 0, 0, 3, maM15) <= 0 ||
      CopyBuffer(handleATR, 0, 0, 3, atr) <= 0) {
      Print("データ取得失敗、エラーコード: ", GetLastError());
      return;
   }
   if((useBBFilter || useBBTP) && 
      (CopyBuffer(handleBB, UPPER_BAND, 0, 3, bbUpper) <= 0 ||
       CopyBuffer(handleBB, LOWER_BAND, 0, 3, bbLower) <= 0)) {
      Print("BBデータ取得失敗、エラーコード: ", GetLastError());
      return;
   }
   
   // 現在価格
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   
   // ポジション確認(既にポジションがある場合は新規注文しない)
   if(PositionsTotal() > 0) {
      if(useTrailingStop) TrailStop();
      return;
   }
   
   // SL(ATRベース)とTPの計算
   double slDistance = atr[1] * atrMultiplier; // ATRベースのSL
   double tpDistance = slDistance * riskRewardRatio; // RRベースのTP
   
   // 買い条件:M15_MAがH2_MAを上抜け(+BB下限フィルター)
   bool buySignal = maM15[1] > maH2[1] && maM15[2] <= maH2[2];
   if(useBBFilter) buySignal = buySignal && bid < bbLower[1];
   if(buySignal) {
      double sl = ask - slDistance;
      double tp = useBBTP ? bbUpper[1] : ask + tpDistance;
      MqlTradeRequest request = {};
      MqlTradeResult result = {};
      request.action = TRADE_ACTION_DEAL;
      request.symbol = _Symbol;
      request.volume = lotSize;
      request.type = ORDER_TYPE_BUY;
      request.price = ask;
      request.sl = sl;
      request.tp = tp;
      if(OrderSend(request, result)) {
         Print("買い注文成功、チケット: ", result.order, " SL: ", sl, " TP: ", tp);
      } else {
         Print("買い注文失敗、エラーコード: ", GetLastError());
      }
   }
   
   // 売り条件:M15_MAがH2_MAを下抜け(+BB上限フィルター)
   bool sellSignal = maM15[1] < maH2[1] && maM15[2] >= maH2[2];
   if(useBBFilter) sellSignal = sellSignal && bid > bbUpper[1];
   if(sellSignal) {
      double sl = bid + slDistance;
      double tp = useBBTP ? bbLower[1] : bid - tpDistance;
      MqlTradeRequest request = {};
      MqlTradeResult result = {};
      request.action = TRADE_ACTION_DEAL;
      request.symbol = _Symbol;
      request.volume = lotSize;
      request.type = ORDER_TYPE_SELL;
      request.price = bid;
      request.sl = sl;
      request.tp = tp;
      if(OrderSend(request, result)) {
         Print("売り注文成功、チケット: ", result.order, " SL: ", sl, " TP: ", tp);
      } else {
         Print("売り注文失敗、エラーコード: ", GetLastError());
      }
   }
}

//+------------------------------------------------------------------+
//| トレーリングストップ                                             |
//+------------------------------------------------------------------+
void TrailStop() {
   for(int i = 0; i < PositionsTotal(); i++) {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == _Symbol) {
         double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         double sl = PositionGetDouble(POSITION_SL);
         double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
            if(currentPrice - openPrice > trailingStart * _Point) {
               double newSL = currentPrice - trailingStep * _Point;
               if(newSL > sl) {
                  PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
                  Print("買いポジションSL更新、チケット: ", ticket, " 新SL: ", newSL);
               }
            }
         } else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
            if(openPrice - currentPrice > trailingStart * _Point) {
               double newSL = currentPrice + trailingStep * _Point;
               if(newSL < sl || sl == 0) {
                  PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
                  Print("売りポジションSL更新、チケット: ", ticket, " 新SL: ", newSL);
               }
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| EA終了処理                                                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   IndicatorRelease(handleMaH2);
   IndicatorRelease(handleMaM15);
   IndicatorRelease(handleATR);
   if(useBBFilter || useBBTP) IndicatorRelease(handleBB);
   Print("EA終了、理由コード: ", reason);
}

ステップ3: コードの解説

  1. 入力パラメータ:
    • maH2Period, maM15Period:H2/M15のMA期間(デフォルト:20)。
    • useBBFilter, bbPeriod, bbDeviation:BBフィルターのON/OFFと設定。
    • lotSize, atrPeriod, atrMultiplier, riskRewardRatio, useBBTP:TP/SL設定。
    • useTrailingStop, trailingStart, trailingStep:トレーリングストップ。
    • displayIndicators:インジケーター表示のON/OFF(デフォルト:true)。
  2. 初期化(OnInit):
    • 内部計算用:iMA, iATR, iBandsでハンドルを作成(EAのロジック用)。
    • チャート表示用(displayIndicators=trueの場合):
      • IndicatorCreate()でH2_MA(PERIOD_H2)、M15_MA、BBをM15チャートに追加。
      • H2_MAはMTFで表示(M15チャート上にH2データ)。
      • エラーチェックで表示失敗をログ出力。
  3. ティック処理(OnTick):
    • M15チャート専用(Period() != PERIOD_M15で制限)。
    • CopyBuffer()でH2_MA、M15_MA、ATR、BB(必要な場合)のデータを取得。
    • 買い条件:M15_MAがH2_MAを上抜け+BB下限(オプション)。
    • 売り条件:M15_MAがH2_MAを下抜け+BB上限(オプション)。
    • SL:ATR×atrMultiplier。
    • TP:useBBTPがtrueならBB上限/下限、falseならSL×riskRewardRatio。
    • ポジションがある場合はTrailStop()を呼び出し。
  4. トレーリングストップ(TrailStop):
    • 利益がtrailingStart(20ピップス)に達したら、SLをtrailingStep(10ピップス)ずつ更新。
  5. 終了処理(OnDeinit):
    • 内部計算用のインジケーターハンドルを解放。
    • チャート表示用のインジケーターは自動的にクリアされる。

ステップ4: インジケーター表示の視覚的効果

  • H2_MA(MTF):
    • M15チャート上でH2の20期間SMAが滑らかな線で表示され、中期トレンドを視覚化。
    • M15_MAとのクロスポイントが明確にわかる。
  • M15_MA:
    • M15チャートに20期間SMAを表示し、短期トレンドを追跡。
  • BB(オプション):
    • M15のBB(2σ)を表示し、価格が上下限を超えるタイミングを視覚化。
  • メリット:
    • 売買シグナル(例:M15_MAがH2_MAを上抜け+BB下限)の発生箇所をチャートで確認。
    • 誤ったシグナルやデータ取得エラーを視覚的に発見可能。

注意:

  • IndicatorCreate()はMT5の内蔵インジケーターを直接チャートに追加しますが、カスタマイズ(色、スタイル)は限定的。詳細なカスタム表示が必要なら、別途カスタムインジケーターを作成(後述)。
  • 表示はM15チャートに適用されるため、EAをM15チャートに設定してください。

ステップ5: カスタムインジケーターの代替案もし内蔵インジケーターの表示(色やスタイル)が物足りない場合、MQL5でカスタムインジケーターを作成し、H2_MA、M15_MA、BBを自由にカスタマイズできます。以下は簡単なカスタムインジケーターの例(別ファイルとして保存):

mql5

//+------------------------------------------------------------------+
//| カスタムインジケーター:H2/M15 MAとBB                            |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   3
#property indicator_label1  "H2_MA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_label2  "M15_MA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_label3  "BB_Upper"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGreen
#property indicator_label4  "BB_Lower"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrGreen

// 入力パラメータ
input int maH2Period = 20;    // H2移動平均期間
input int maM15Period = 20;   // M15移動平均期間
input int bbPeriod = 20;      // BB期間
input double bbDeviation = 2.0; // BB標準偏差

// バッファ
double bufferH2MA[], bufferM15MA[], bufferBBUpper[], bufferBBLower[];
int handleMaH2, handleMaM15, handleBB;

//+------------------------------------------------------------------+
//| 初期化                                                          |
//+------------------------------------------------------------------+
void OnInit() {
   SetIndexBuffer(0, bufferH2MA, INDICATOR_DATA);
   SetIndexBuffer(1, bufferM15MA, INDICATOR_DATA);
   SetIndexBuffer(2, bufferBBUpper, INDICATOR_DATA);
   SetIndexBuffer(3, bufferBBLower, INDICATOR_DATA);
   
   handleMaH2 = iMA(_Symbol, PERIOD_H2, maH2Period, 0, MODE_SMA, PRICE_CLOSE);
   handleMaM15 = iMA(_Symbol, PERIOD_M15, maM15Period, 0, MODE_SMA, PRICE_CLOSE);
   handleBB = iBands(_Symbol, PERIOD_M15, bbPeriod, 0, bbDeviation, PRICE_CLOSE);
}

//+------------------------------------------------------------------+
//| 計算                                                            |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[]) {
   // データ取得
   double tempH2MA[], tempM15MA[], tempBBUpper[], tempBBLower[];
   if(CopyBuffer(handleMaH2, 0, 0, rates_total, tempH2MA) <= 0 ||
      CopyBuffer(handleMaM15, 0, 0, rates_total, tempM15MA) <= 0 ||
      CopyBuffer(handleBB, UPPER_BAND, 0, rates_total, tempBBUpper) <= 0 ||
      CopyBuffer(handleBB, LOWER_BAND, 0, rates_total, tempBBLower) <= 0) {
      Print("データ取得失敗、エラーコード: ", GetLastError());
      return(0);
   }
   
   // バッファにコピー
   for(int i = 0; i < rates_total; i++) {
      bufferH2MA[i] = tempH2MA[i];
      bufferM15MA[i] = tempM15MA[i];
      bufferBBUpper[i] = tempBBUpper[i];
      bufferBBLower[i] = tempBBLower[i];
   }
   
   return(rates_total);
}

//+------------------------------------------------------------------+
//| 終了処理                                                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   IndicatorRelease(handleMaH2);
   IndicatorRelease(handleMaM15);
   IndicatorRelease(handleBB);
}

カスタムインジケーターの使用:

  1. 上記コードをIndicatorsフォルダに保存(例:Custom_MA_BB.mq5)。
  2. MetaEditorでコンパイルし、M15チャートに適用。
  3. EAとは別にチャートに表示され、色やスタイルをカスタマイズ可能。

ステップ6: バックテストと最適化

  1. ストラテジーテスター:
    • EAをM15チャート(例:USDJPY)に適用。
    • テスト設定:2024年データ、M15、スプレッド20。
    • 最適化パラメータ:
      • maH2Period:10-50
      • maM15Period:5-30
      • atrMultiplier:1.0-3.0
      • riskRewardRatio:1.0-3.0
  2. 結果分析:
    • プロフィットファクター(>1.5)、ドローダウン(<20%)。
    • インジケーター表示による視覚的確認で、シグナルの正確さを検証。
  3. デモ口座テスト:
    • デモ口座で1か月運用(現在の日時:2025年10月13日21:54 JST)。
    • チャートでMAクロスやBB 2σ超えを確認。

ステップ7: デバッグと視覚的検証

  • ログ出力:mql5Print("Bid: ", bid, " H2_MA: ", maH2[1], " M15_MA: ", maM15[1], " BB Upper: ", bbUpper[1], " BB Lower: ", bbLower[1], " ATR: ", atr[1]);
  • チャートコメント:mql5Comment("H2_MA: ", maH2[1], "\nM15_MA: ", maM15[1], "\nSL Distance: ", slDistance);
  • 視覚的確認:
    • チャート上でH2_MA(青)とM15_MA(赤)のクロスを確認。
    • BB(緑)の上下限と価格の関係を視覚化。
    • 売買シグナル(例:買い注文時のログ)がチャートのクロスポイントと一致するかチェック。

ステップ8: 学習リソース


ステップ9: 次のアクションと質問対応

  1. コードの使用:
    • EAコードをMetaEditorにコピーし、M15チャートでコンパイル。
    • displayIndicators=trueで内蔵インジケーターを表示。
    • 必要ならカスタムインジケーターコードを別ファイルで適用。
    • ストラテジーテスターでテスト(例:USDJPY、M15、2024年)。
  2. 練習課題:
    • インジケーターの色やスタイルをカスタマイズ(カスタムインジケーター使用)。
    • シグナル発生時に矢印を表示(カスタムインジケーターにDRAW_ARROWを追加)。
    • 時間ベースの利確(例:4時間)を追加。
  3. 確認事項:
    • インジケーター表示:
      • 内蔵インジケーターで十分?カスタムインジケーター(色やスタイルのカスタマイズ)が必要?
      • 特定の表示(例:シグナル矢印、別ウィンドウ)を希望?
    • TP/SL:
      • 現在のATRベースSL、RR/BBベースTP、トレーリングストップでOK?
      • 他のオリジナルTP/SL(例:高値/安値、MA乖離)を追加?
    • BB条件:
      • BB 2σフィルターを必須にする?(現在はuseBBFilter=false)。
      • BBをH2チャートに変更?
    • トリガーレベル(前の質問):
      • MAクロス以外の条件(例:MAの差、RSI)を追加?
    • 特定の通貨ペアや時間足向けの調整?
  4. 問題解決:
    • インジケーター表示の設定(例:IndicatorCreateのエラー)が不明なら解説。
    • バックテストや視覚的デバッグの手順が必要なら説明。

具体的な質問:

  • インジケーター表示のカスタマイズ(例:色、矢印、別ウィンドウ)を希望?
  • 特定のTP/SLロジックや追加フィルター(例:RSI、時間帯)を指定?
  • どの部分を深掘りしたい?(例:インジケーターのカスタム、コード改良、テスト方法)
まるもと愉快な仲間たち
いつもありがとうございます!
365日カウントダウン日記
SNS収益化
割箸マルモ商品サイト・X(旧Twitter)・YouTube
割箸まるもと愉快な仲間たち
タイトルとURLをコピーしました