MQL5の自作EAでオリジナルの利確・損切りプログラムを構築したい

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

MQL5で自作EAにオリジナルの利確(テイクプロフィット、TP)と損切り(ストップロス、SL)プログラムを構築するのは、トレーディング戦略を強化する重要なステップです。以下の手順では、前の質問で扱った「ボリンジャーバンド(BB)2σ超え」と「2時間足(H2)および15分足(M15)の移動平均(MA)クロスによる反転指標」をベースに、オリジナルのTP/SLロジックを組み込んだEAを構築する方法を初心者向けに段階的に解説します。また、ユーザーの要望に応じて柔軟性のあるカスタムTP/SL戦略を提供します。

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


ステップ1: オリジナルのTP/SLロジックの定義「オリジナル」のTP/SLを構築するため、以下のようなカスタムロジックを仮定します(具体的な要望が不明なため、一般的かつ柔軟な例を採用)。必要なら、ユーザーの具体的なアイデアに基づいて修正します。仮定したTP/SLロジック

  1. ストップロス(SL):
    • ATRベースの動的SL:平均真の値幅(ATR, Average True Range)を使用して、市場のボラティリティに応じたSLを設定(例:ATRの2倍)。
    • 固定ポイントSL:バックテストやリスク管理のために固定値(例:50ピップス)もオプションで保持。
  2. テイクプロフィット(TP):
    • リスクリワードレシオ(RR):SLの2倍の距離をTPに設定(例:RR=1:2)。
    • ボリンジャーバンドベース:BBの対向バンド(例:買いならBB上限、売りならBB下限)をTPの目安に。
  3. トレーリングストップ(オプション):
    • 価格が一定の利益(例:20ピップス)に達したら、SLを動的に追従(トレーリングストップ)。
  4. 統合条件:
    • 前の質問の条件(BB 2σ超え+H2/M15 MAクロス)を注文トリガーとして使用。
    • ユーザーが「トリガーレベル」や「反転指標」の詳細を指定した場合、それに合わせて調整。

確認:

  • 具体的なTP/SLロジック(例:特定の指標、価格レベル、時間ベースなど)を教えていただければ、カスタムします。
  • 例:TPを「直近の高値/安値」、SLを「MAからの乖離距離」など。

ステップ2: 必要な知識

  • インジケーター:
    • iBands():BBの上下限を取得。
    • iMA():H2/M15のMAを取得。
    • iATR():ATRを計算(動的SL用)。
  • 注文管理:
    • OrderSend():注文にSL/TPを設定。
    • PositionModify():トレーリングストップでSLを更新。
  • ポジション管理:
    • PositionsTotal(), PositionSelectByTicket():ポジションの状態をチェック。
  • デバッグ:
    • Print(), Comment():TP/SL値やシグナルをログ出力。

ステップ3: サンプルコード(カスタムTP/SL付きEA)以下のコードは、BB 2σ超え+H2/M15 MAクロスをトリガーとし、ATRベースのSL、リスクリワードレシオおよびBBベースのTP、トレーリングストップを組み込んだEAです。

mql5

//+------------------------------------------------------------------+
//| 入力パラメータ                                                   |
//+------------------------------------------------------------------+
input int maH2Period = 20;          // H2移動平均期間
input int maM15Period = 20;         // M15移動平均期間
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;        // トレーリングステップ(ポイント)

// グローバル変数
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);
   handleBB = iBands(_Symbol, PERIOD_M15, bbPeriod, 0, bbDeviation, PRICE_CLOSE);
   handleATR = iATR(_Symbol, PERIOD_M15, atrPeriod);
   
   // ハンドル作成のエラーチェック
   if(handleMaH2 == INVALID_HANDLE || handleMaM15 == INVALID_HANDLE || 
      handleBB == INVALID_HANDLE || handleATR == INVALID_HANDLE) {
      Print("インジケーターハンドル作成に失敗");
      ExpertRemove();
   }
   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, 3, maM15) <= 0 ||
      CopyBuffer(handleBB, UPPER_BAND, 0, 3, bbUpper) <= 0 ||
      CopyBuffer(handleBB, LOWER_BAND, 0, 3, bbLower) <= 0 ||
      CopyBuffer(handleATR, 0, 0, 3, atr) <= 0) {
      Print("データ取得失敗、エラーコード: ", 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] && bid < bbLower[1];
   if(buySignal) {
      double sl = ask - slDistance;
      double tp = useBBTP ? bbUpper[1] : ask + tpDistance; // BB上限またはRRベース
      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] && bid > bbUpper[1];
   if(sellSignal) {
      double sl = bid + slDistance;
      double tp = useBBTP ? bbLower[1] : bid - tpDistance; // BB下限またはRRベース
      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(handleBB);
   IndicatorRelease(handleATR);
   Print("EA終了、理由コード: ", reason);
}

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

  1. 入力パラメータ:
    • maH2Period, maM15Period:H2/M15のMA期間。
    • bbPeriod, bbDeviation:BBの設定(M15)。
    • atrPeriod, atrMultiplier:ATRベースのSL計算用。
    • riskRewardRatio:TPのRR比率(例:1:2)。
    • useBBTP:TPにBBを使用するか(trueならBB上限/下限、falseならRRベース)。
    • useTrailingStop, trailingStart, trailingStep:トレーリングストップの設定。
  2. 初期化(OnInit):
    • H2/M15のMA、BB、ATRのハンドルを作成。
    • ハンドル作成失敗時はEAを終了。
  3. ティック処理(OnTick):
    • M15チャート専用(Period() != PERIOD_M15で制限)。
    • インジケーターデータ(MA、BB、ATR)を取得。
    • 買い条件:M15_MAがH2_MAを上抜け+価格がBB下限を下回る。
    • 売り条件:M15_MAがH2_MAを下抜け+価格がBB上限を超える。
    • SL:ATR×atrMultiplier(例:ATRの2倍)。
    • TP:useBBTPがtrueならBB上限/下限、falseならSL×riskRewardRatio。
    • ポジションがある場合はTrailStop()を呼び出し。
  4. トレーリングストップ(TrailStop):
    • 利益がtrailingStart(例:20ピップス)に達したら、SLをtrailingStep(例:10ピップス)ずつ追従。
    • 買い:価格が上昇するにつれてSLを引き上げる。
    • 売り:価格が下降するにつれてSLを引き下げる。
  5. 終了処理(OnDeinit):
    • インジケーターハンドルを解放。

ステップ5: オリジナルのTP/SLアイデアユーザーが求める「オリジナル」のTP/SLに応じて、以下のようなカスタムロジックを追加できます(例):

  1. 直近の高値/安値ベース:
    • TP:直近N本の高値(買い)/安値(売り)をiHigh()/iLow()で取得。mql5double tp = iHigh(_Symbol, PERIOD_M15, iHighest(_Symbol, PERIOD_M15, MODE_HIGH, 20, 1)); // 買いTP
  2. 時間ベースの利確:
    • ポジション保有後N時間(例:4時間)で強制利確:mql5if(TimeCurrent() - PositionGetDouble(POSITION_TIME) > 4 * 3600) { PositionClose(ticket); }
  3. MA乖離ベースのSL:
    • 価格がH2_MAから一定距離(例:100ピップス)離れたら損切り:mql5double sl = maH2[1] - 100 * _Point; // 買いSL
  4. ボラティリティ調整:
    • ATRが大きい場合、SL/TPを広げる(例:ATR×3):mql5if(atr[1] > 0.002) slDistance = atr[1] * 3.0;

確認:

  • 具体的なTP/SLのアイデア(例:特定の指標、価格パターン、時間条件)を教えてください。
  • 例:TPを「前の高値」、SLを「ATR+MA乖離」など。

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

  1. ストラテジーテスター:
    • MT5で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%)を確認。
    • トレーリングストップの効果を比較(useTrailingStopのON/OFF)。
  3. デモ口座テスト:
    • デモ口座で1か月運用(現在の日時:2025年10月13日21:45 JST)。
    • ログでTP/SLの動作を確認。

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

  • ログ出力:mql5Print("Bid: ", bid, " H2_MA: ", maH2[1], " M15_MA: ", maM15[1], " BB Upper: ", bbUpper[1], " BB Lower: ", bbLower[1], " ATR: ", atr[1]);
  • チャートコメント:mql5Comment("SL Distance: ", slDistance, "\nTP Distance: ", tpDistance);
  • エラーチェック:
    • OrderSend()やPositionModify()のエラーコードをGetLastError()で確認。
    • インジケーターデータの取得エラーをチェック。

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


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

  1. コードの使用:
    • 上記コードをMetaEditorにコピーし、M15チャートでコンパイル。
    • ストラテジーテスターでテスト(例:USDJPY、M15、2024年)。
  2. 練習課題:
    • 直近高値/安値をTPに設定。
    • 時間ベースの利確(例:4時間)を追加。
    • RSIフィルター(例:70以上で売り、30以下で買い)を組み込む。
  3. 確認事項:
    • オリジナルのTP/SL:具体的なアイデア(例:指標、価格パターン、時間)を教えてください。
    • 前の条件の統合:
      • BB 2σ条件は必須?(現在は必須として実装)。
      • H2/M15 MAクロス以外の「トリガーレベル」(例:MAの差、RSIなど)が必要?
    • 特定の通貨ペア(例:USDJPY)や時間足(例:M15以外)向けの調整?
    • リスク管理(例:口座残高の1%リスク)やフィルター(時間帯、ボラティリティ)の追加?
  4. 問題解決:
    • コードの特定部分(例:ATR計算、トレーリングストップ)が不明なら詳細解説。
    • バックテストやデバッグの具体的な手順が必要なら説明。

具体的な質問:

  • 「オリジナル」のTP/SLの詳細(例:特定の指標、価格レベル、時間条件)を教えてください。
  • BB 2σやMAクロス条件を変更/追加するアイデアは?
まるもと愉快な仲間たち
いつもありがとうございます!
365日カウントダウン日記
投資
割箸マルモ商品サイト・X(旧Twitter)・YouTube
割箸まるもと愉快な仲間たち
タイトルとURLをコピーしました