このサイトのEA記事では、
損切り(StopLoss)を入れ忘れたコードが何度も登場しました。
ですがこの問題は自動売買のEAだけでなく、手動でポジションを持っている人にも起こります。
損切り注文を入れたつもりが実は入っていなかった、
あるいは損切りラインを価格からかなり離れた位置に置いたまま忘れていた、
というのは決して珍しいことではありません。
この記事では、保有中のポジションごとに、
損切りラインまでの距離をpips換算でチャート上に常時表示し、
損切りが未設定のポジションがあれば警告表示するインジケーターを作ります。
設計思想: 『損切りは入れた』を過信しない
損切りを入れたかどうかは、注文時の画面を見れば分かります。
ですが一度エントリーしてしまうと、多くのトレーダーはチャートに集中し、
注文の詳細画面を何度も見返すことはしません。
この記事のインジケーターは、注文画面を開き直さなくても、
チャート上に常に表示され続ける形で「損切りまでの距離」
と「損切り未設定」を知らせます。
距離をpipsという具体的な数字にすることで、「近すぎてすぐ引っかかりそう」
「遠すぎてリスクが大きい」といった判断もその場でできるようにします。
保有ポジションを1件ずつ調べるロジック
保有中の注文は、OrdersTotal()で件数を取得し、
OrderSelect()で1件ずつ選択して調べます。
今回のインジケーターでは、
現在のチャートの通貨ペア(Symbol())と一致する注文だけを対象にし、
必要であればマジックナンバーでの絞り込みもできるようにします。
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderSymbol()!=Symbol()) continue;
if(OrderType()!=OP_BUY && OrderType()!=OP_SELL) continue;//成行ポジションのみ対象
//ここで損切りまでの距離を計算する
}
損切りが未設定(OrderStopLoss()が0)の場合は距離を計算せず、
そのポジションが未設定である旨をそのまま表示します。
実際に動くコード全体
保有ポジションごとに、画面左上へ縦に並べたラベルで「損切りまでの距離(pips)」
または「損切り未設定」を表示し、距離が10pips以内に近づいたら警告色に変わる、
実際にMetaEditorでコンパイルできるインジケーターです。
//+------------------------------------------------------------------+
//| StopLossDistance.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 0
input int MagicFilter = 0;//0なら全ポジションを対象、特定EAだけ見たい場合はマジックナンバーを指定
input int WarningPips = 10;//この距離以下になったら警告色にする
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ClearDistanceLabels();
}
//+------------------------------------------------------------------+
//| 前回作成したラベルをすべて削除する |
//+------------------------------------------------------------------+
void ClearDistanceLabels()
{
for(int i=ObjectsTotal(0,0,OBJ_LABEL)-1; i>=0; i--)
{
string objName = ObjectName(0,i,0,OBJ_LABEL);
if(StringFind(objName,"SLDistance_")==0)
ObjectDelete(0,objName);
}
}
//+------------------------------------------------------------------+
//| 1件分のラベルを作成・更新する |
//+------------------------------------------------------------------+
void DrawDistanceLabel(int rowIndex,string text,color textColor)
{
string name = "SLDistance_"+IntegerToString(rowIndex);
ObjectCreate(0,name,OBJ_LABEL,0,0,0);
ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_LEFT_UPPER);
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,10);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,20+rowIndex*16);
ObjectSetText(name,text,10,"Arial",textColor);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
ClearDistanceLabels();
int rowIndex = 0;
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderSymbol()!=Symbol()) continue;
if(OrderType()!=OP_BUY && OrderType()!=OP_SELL) continue;
if(MagicFilter!=0 && OrderMagicNumber()!=MagicFilter) continue;
double sl = OrderStopLoss();
if(sl==0)
{
DrawDistanceLabel(rowIndex, StringFormat("#%d 損切り未設定です", OrderTicket()), clrRed);
rowIndex++;
continue;
}
double currentPrice = (OrderType()==OP_BUY) ? Bid : Ask;
double distancePoints = MathAbs(currentPrice - sl) / Point;
double distancePips = distancePoints / 10.0;//5桁ブローカー前提。4桁の場合はこの割り算を外す
color c = (distancePips <= WarningPips) ? clrOrange : clrLime;
DrawDistanceLabel(rowIndex, StringFormat("#%d 損切りまで%.1fpips", OrderTicket(), distancePips), c);
rowIndex++;
}
return(rates_total);
}
//+------------------------------------------------------------------+
MetaEditorで実際に動かす手順
- MT4の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
- 「ファイル」→「新規作成」→「カスタムインディケータ」を選び、名前を「StopLossDistance」にして作成する
- テンプレートの中身をすべて削除し、上のコードを丸ごと貼り付ける
- F7キーでコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- チャートへ適用し、デモ口座でポジションを持ちながら、損切り設定済みは緑(近づくとオレンジ)、未設定は赤の文字で表示されることを確認する
この設計の限界と使いどころ
このインジケーターは、あくまで「今どういう状態か」を表示するだけで、
損切りを自動で設定したり変更したりはしません。
損切りを入れ忘れていることに気づくきっかけを作る道具であり、
気づいた後の対応(実際に損切りを入れ直す操作)は自分で行う必要があります。
また、pips換算の計算は5桁ブローカーの前提で書いているため、
4桁表示のブローカーを使っている場合はコード中の「10.0」
で割る処理を外してください。
コピペして動かない・意図と違うときに確認すること
- ラベルが増え続けて画面が乱れる場合、`ClearDistanceLabels()`をOnCalculate()の先頭で呼び忘れていないか確認する。毎回いったん全消去してから作り直す設計になっている
- pipsの数値が実際の値の10倍・0.1倍にずれる場合、口座のブローカーが4桁表示か5桁表示かを確認し、`distancePoints / 10.0`の扱いを合わせる
- 複数のEAを同じ通貨ペアで動かしている場合、`MagicFilter`を0のままにすると全ポジションが表示され行が増えるため、見たいEAのマジックナンバーを指定する
- 両建て(同じ通貨ペアで買いと売りを同時保有)している場合、Bid/Askのどちらを基準にするかがOrderType()で自動的に切り替わることを確認する
まとめ
損切りの入れ忘れは、EAだけでなく手動トレードでも起こります。
損切りラインまでの距離をpipsで常時表示し、
未設定のポジションを赤字で警告するだけの単純な仕組みですが、
注文画面を開き直さなくても状態が一目で分かるようになります。
まずはデモ口座で表示を確認してから、実際のトレードに取り入れてみてください。
コメント