MQL5で自作EAにオリジナルの利確(テイクプロフィット、TP)と損切り(ストップロス、SL)プログラムを構築するのは、トレーディング戦略を強化する重要なステップです。以下の手順では、前の質問で扱った「ボリンジャーバンド(BB)2σ超え」と「2時間足(H2)および15分足(M15)の移動平均(MA)クロスによる反転指標」をベースに、オリジナルのTP/SLロジックを組み込んだEAを構築する方法を初心者向けに段階的に解説します。また、ユーザーの要望に応じて柔軟性のあるカスタムTP/SL戦略を提供します。
【免責事項】私は投資アドバイザーではありません。投資判断はご自身で行い、必要に応じてファイナンシャルアドバイザーに相談してください。この記事は自身の勉強を目的としており、EAの動作保証や生じた損失に対しても一切の責任を負いません。
ステップ1: オリジナルのTP/SLロジックの定義「オリジナル」のTP/SLを構築するため、以下のようなカスタムロジックを仮定します(具体的な要望が不明なため、一般的かつ柔軟な例を採用)。必要なら、ユーザーの具体的なアイデアに基づいて修正します。仮定したTP/SLロジック
- ストップロス(SL):
- ATRベースの動的SL:平均真の値幅(ATR, Average True Range)を使用して、市場のボラティリティに応じたSLを設定(例:ATRの2倍)。
- 固定ポイントSL:バックテストやリスク管理のために固定値(例:50ピップス)もオプションで保持。
- テイクプロフィット(TP):
- リスクリワードレシオ(RR):SLの2倍の距離をTPに設定(例:RR=1:2)。
- ボリンジャーバンドベース:BBの対向バンド(例:買いならBB上限、売りならBB下限)をTPの目安に。
- トレーリングストップ(オプション):
- 価格が一定の利益(例:20ピップス)に達したら、SLを動的に追従(トレーリングストップ)。
- 統合条件:
- 前の質問の条件(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: コードの解説
- 入力パラメータ:
- 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:トレーリングストップの設定。
- 初期化(OnInit):
- H2/M15のMA、BB、ATRのハンドルを作成。
- ハンドル作成失敗時はEAを終了。
- ティック処理(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()を呼び出し。
- トレーリングストップ(TrailStop):
- 利益がtrailingStart(例:20ピップス)に達したら、SLをtrailingStep(例:10ピップス)ずつ追従。
- 買い:価格が上昇するにつれてSLを引き上げる。
- 売り:価格が下降するにつれてSLを引き下げる。
- 終了処理(OnDeinit):
- インジケーターハンドルを解放。
ステップ5: オリジナルのTP/SLアイデアユーザーが求める「オリジナル」のTP/SLに応じて、以下のようなカスタムロジックを追加できます(例):
- 直近の高値/安値ベース:
- TP:直近N本の高値(買い)/安値(売り)をiHigh()/iLow()で取得。mql5
double tp = iHigh(_Symbol, PERIOD_M15, iHighest(_Symbol, PERIOD_M15, MODE_HIGH, 20, 1)); // 買いTP
- TP:直近N本の高値(買い)/安値(売り)をiHigh()/iLow()で取得。mql5
- 時間ベースの利確:
- ポジション保有後N時間(例:4時間)で強制利確:mql5
if(TimeCurrent() - PositionGetDouble(POSITION_TIME) > 4 * 3600) { PositionClose(ticket); }
- ポジション保有後N時間(例:4時間)で強制利確:mql5
- MA乖離ベースのSL:
- 価格がH2_MAから一定距離(例:100ピップス)離れたら損切り:mql5
double sl = maH2[1] - 100 * _Point; // 買いSL
- 価格がH2_MAから一定距離(例:100ピップス)離れたら損切り:mql5
- ボラティリティ調整:
- ATRが大きい場合、SL/TPを広げる(例:ATR×3):mql5
if(atr[1] > 0.002) slDistance = atr[1] * 3.0;
- ATRが大きい場合、SL/TPを広げる(例:ATR×3):mql5
確認:
- 具体的なTP/SLのアイデア(例:特定の指標、価格パターン、時間条件)を教えてください。
- 例:TPを「前の高値」、SLを「ATR+MA乖離」など。
ステップ6: バックテストと最適化
- ストラテジーテスター:
- MT5でEAをM15チャート(例:USDJPY)に適用。
- テスト設定:2024年データ、M15、スプレッド20。
- 最適化パラメータ:
- maH2Period:10-50
- maM15Period:5-30
- atrMultiplier:1.0-3.0
- riskRewardRatio:1.0-3.0
- 結果分析:
- プロフィットファクター(>1.5)、最大ドローダウン(<20%)を確認。
- トレーリングストップの効果を比較(useTrailingStopのON/OFF)。
- デモ口座テスト:
- デモ口座で1か月運用(現在の日時:2025年10月13日21:45 JST)。
- ログでTP/SLの動作を確認。
ステップ7: デバッグと検証
- ログ出力:mql5
Print("Bid: ", bid, " H2_MA: ", maH2[1], " M15_MA: ", maM15[1], " BB Upper: ", bbUpper[1], " BB Lower: ", bbLower[1], " ATR: ", atr[1]);
- チャートコメント:mql5
Comment("SL Distance: ", slDistance, "\nTP Distance: ", tpDistance);
- エラーチェック:
- OrderSend()やPositionModify()のエラーコードをGetLastError()で確認。
- インジケーターデータの取得エラーをチェック。
ステップ8: 学習リソース
- MQL5公式ドキュメント:
- MQL5コミュニティ:
- 記事「How to Implement Trailing Stop」(https://www.mql5.com/en/articles)。
- Code Base(https://www.mql5.com/en/code)でATRやTP/SLのサンプル。
- YouTube:
- 「MQL5 Tutorial」チャンネル(英語)や日本語の「FX 自動売買 MQL5」。
- 書籍:
- 「MQL5 Programming for Traders」(無料、MQL5公式)。
ステップ9: 次のアクションと質問対応
- コードの使用:
- 上記コードをMetaEditorにコピーし、M15チャートでコンパイル。
- ストラテジーテスターでテスト(例:USDJPY、M15、2024年)。
- 練習課題:
- 直近高値/安値をTPに設定。
- 時間ベースの利確(例:4時間)を追加。
- RSIフィルター(例:70以上で売り、30以下で買い)を組み込む。
- 確認事項:
- オリジナルのTP/SL:具体的なアイデア(例:指標、価格パターン、時間)を教えてください。
- 前の条件の統合:
- BB 2σ条件は必須?(現在は必須として実装)。
- H2/M15 MAクロス以外の「トリガーレベル」(例:MAの差、RSIなど)が必要?
- 特定の通貨ペア(例:USDJPY)や時間足(例:M15以外)向けの調整?
- リスク管理(例:口座残高の1%リスク)やフィルター(時間帯、ボラティリティ)の追加?
- 問題解決:
- コードの特定部分(例:ATR計算、トレーリングストップ)が不明なら詳細解説。
- バックテストやデバッグの具体的な手順が必要なら説明。
具体的な質問:
- 「オリジナル」のTP/SLの詳細(例:特定の指標、価格レベル、時間条件)を教えてください。
- BB 2σやMAクロス条件を変更/追加するアイデアは?