OrderGuardian
Download scriptThis script, titled OrderGuardian, is designed as an automated management tool for your trading platform. Its primary purpose is to monitor open trades and automatically execute "Take Profit" (TP) or "Stop Loss" (SL) actions based on specific mathematical calculations or visual indicators you place on your chart.
Core Functionality
The script acts as a watchful supervisor. It scans your active trading positions and identifies which ones need protection or profit-taking. Instead of relying solely on fixed price levels, it can dynamically calculate these targets using technical indicators or by "reading" the geometry of objects you have drawn manually on the chart.
How It Works
1. Target Identification (Where to Exit) The tool provides different methods for determining your exit prices:
- Moving Average & Envelopes: You can set the script to calculate a profit or loss level based on moving averages. It looks at specific timeframes and periods to create a dynamic "buffer" around the price.
- Visual Objects (Trendlines & Channels): This is a sophisticated feature where the script scans your chart for manually drawn Trendlines or Channels.
- For a Buy position, it automatically looks for the nearest line above the current price to use as a profit target and the nearest line below to use as a stop loss.
- For a Sell position, it flips this logic, looking for the nearest line below for profit and above for risk management.
- Parabolic SAR: For stop losses specifically, it can also use the Parabolic SAR indicator to determine the safest exit point based on volatility.
2. Order Monitoring & Execution Once the script knows where your targets are, it performs the following actions:
- Real-Time Tracking: It constantly compares the current market price against the calculated Take Profit and Stop Loss levels.
- Automatic Closure: If the market hits one of these target prices, the script immediately sends a command to close the corresponding trade.
- Visual Feedback: To keep you informed, the script can draw physical dashed lines on your chart at the current calculated Take Profit and Stop Loss levels. It also displays a text summary on your screen showing exactly what those prices are (e.g., "S/L @ [Price] T/P @ [Price]").
3. Smart Filtering The script is designed to be precise. It can be configured to manage all trades, or you can specify specific trade tickets. It also ensures it only acts on the correct asset (currency pair/instrument) to prevent accidental interference with other charts you might have open.
Summary for the User
Think of OrderGuardian as an automated "Safety Net." You don't have to manually watch the charts to see if your trade hit a trendline or a moving average. You simply draw your lines or set your technical preferences, and the script handles the heavy lifting of monitoring those levels and closing your trades at the exact moment the conditions are met.
//+------------------------------------------------------------------+
//| OrderGuardian.mq4 |
//| Greatshore |
//| greatshore@live.cn |
//+------------------------------------------------------------------+
#property copyright "Greatshore"
#property link "greatshore@live.cn"
#define TP_PRICE_LINE "OG TP Price Line"
#define SL_PRICE_LINE "OG SL Price Line"
//---- input parameters
extern string Orders = "*"; // ¹ÜÀíÄÄЩ¶©µ¥
extern int TP_Method = 2; // »ñÀû·½Ê½£º1-Envelopes°üÂçÏߺ;ùÏߣ¬2-Ç÷ÊÆÏß
extern int SL_Method = 2; // »ñÀû·½Ê½£º1-Envelopes°üÂçÏߺ;ùÏߣ¬2-Ç÷ÊÆÏß, 3-SAR
extern bool ShowLines = true; // ÊÇ·ñÏÔʾ»ñÀûÖ¹ËðÏß
extern string SPLIT1 = "=== Parameters for TP ===";
extern color TP_LineColor = LimeGreen; // »ñÀû¼Û¸ñÏßÑÕÉ«
extern int TP_TimeFrame = 0; // »ñÀû¼Û¼ÆËãµÄʱ¼äͼÖÜÆÚ
extern int TP_MA_Period = 31; // »ñÀû¾ùÏßÖÜÆÚ
extern int TP_MA_Method = MODE_EMA; // »ñÀû¾ùÏß¼ÆËã·½·¨
extern int TP_MA_Price = PRICE_CLOSE; // »ñÀû¾ùÏß¼ÆËã¼Û¸ñ
extern double TP_Env_Dev = 0.2; // »ñÀûEnvelopesÆ«sÒÆ°Ù·Ö±È
extern int TP_Shift = 0; // »ñÀû¼Û¼ÆËãµÄshiftÖµ
extern string SPLIT2 = "=== Parameters of SL ===";
extern color SL_LineColor = Red; // Ö¹Ëð¼Û¸ñÏßÑÕÉ«
extern int SL_TimeFrame = 0; // Ö¹Ëð¼Û¼ÆËãµÄʱ¼äͼÖÜÆÚ
extern int SL_MA_Period = 31; // Ö¹Ëð¾ùÏß¼ÆËã·½·¨
extern int SL_MA_Method = MODE_EMA; // Ö¹Ëð¾ùÏß¼ÆËã·½·¨
extern int SL_MA_Price = PRICE_CLOSE; // Ö¹Ëð¾ùÏß¼ÆËã¼Û¸ñ
extern double SL_Env_Dev = 0; // Ö¹ËðEnvelopesÆ«ÒÆ°Ù·Ö±È
extern double SL_SARStep = 0.02; // SARÖ¹ËðµÄ²½³¤
extern double SL_SARMax = 0.5; // SARÖ¹Ëð×î´óÖµ
extern int SL_Shift = 0; // Ö¹Ëð¼Û¼ÆËãµÄshiftÖµ
string TPObjName, SLObjName;
int OrdersID[], OrdersCount, OpType;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
if ((SL_Method == 3) && (SL_Shift < 1))
SL_Shift = 1;
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
ObjectDelete(TP_PRICE_LINE);
ObjectDelete(SL_PRICE_LINE);
Comment("");
return(0);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
int i;
double TPPrice, SLPrice;
bool SetTPObj = false, SetSLObj = false;
string MesgText;
GetOrdersID(); // »ñÈ¡ÐèÒª¹ÜÀíµÄ¶©µ¥ID
if (OpType >= 0) // ·½ÏòÒ»ÖÂ
{
if (TP_Method == 2)
SetTPObj = FindObject(TPObjName) < 0;
if (SL_Method == 2)
SetSLObj = FindObject(SLObjName) < 0;
if (SetTPObj || SetSLObj)
SearchObjName(OpType, SetTPObj, SetSLObj); // ËÑѰ»ñÀûÖ¹ËðÏߵĶÔÏóÃû
CalcPrice(TPPrice, SLPrice);
MesgText = "S/L @ ";
if (SLPrice < 0)
MesgText = MesgText + " __ ";
else
MesgText = MesgText + DoubleToStr(SLPrice, Digits);
MesgText = MesgText + " T/P @ ";
if (TPPrice < 0)
MesgText = MesgText + " __ ";
else
MesgText = MesgText + DoubleToStr(TPPrice, Digits);
Comment(MesgText);
if (ShowLines)
ShowTPSLLines(TPPrice, SLPrice);
for (i = 0; i < OrdersCount; i++)
{
if ((SLPrice > 0) &&
(((OpType == OP_BUY) && (Bid <= SLPrice)) ||
((OpType == OP_SELL) && (Bid >= SLPrice))))
CloseOrder(OrdersID[i], 1);
if ((TPPrice > 0) &&
(((OpType == OP_BUY) && (Bid >= TPPrice)) ||
((OpType == OP_SELL) && (Bid <= TPPrice))))
CloseOrder(OrdersID[i], 2);
}
}
return(0);
}
//+------------------------------------------------------------------+
// === »ñÈ¡¶©µ¥ID ===
void GetOrdersID()
{
int i, n, t, o;
bool all;
n = OrdersTotal();
ArrayResize(OrdersID, n);
all = StringFind(Orders, "*") >= 0;
OpType = -1;
for (i = 0, OrdersCount = 0; i < n; i++)
{
OrderSelect(i, SELECT_BY_POS);
if (Symbol() == OrderSymbol())
{
t = OrderTicket();
if (all || (StringFind(Orders, DoubleToStr(t, 0)) >= 0))
{
o = OrderType();
if (o < 2)
{
if ((OpType >= 0) && (o != OpType))
{
OpType = -1;
break;
}
else
{
OpType = o;
OrdersID[OrdersCount] = t;
OrdersCount++;
}
}
}
}
}
if (OrdersCount == 0)
{
if (ObjectFind(TP_PRICE_LINE) >= 0)
ObjectDelete(TP_PRICE_LINE);
if (ObjectFind(SL_PRICE_LINE) >= 0)
ObjectDelete(SL_PRICE_LINE);
}
}
// === ѰÕÒ»ñÀûÖ¹ËðÏß ===
void SearchObjName(int Type, bool GetTPObj = true, bool GetSLObj = true)
{
int i, ObjType, iAbove, iBelow, iTP, iSL;
double MinAbove, MaxBelow, y1, y2;
string ObjName;
MinAbove = 999999;
MaxBelow = 0;
iAbove = -1;
iBelow = -1;
for (i = 0; i < ObjectsTotal(); i++)
{
ObjName = ObjectName(i);
ObjType = ObjectType(ObjName);
switch (ObjType)
{
case OBJ_TREND :
case OBJ_TRENDBYANGLE :
y1 = CalcLineValue(ObjName, 0, 1, ObjType);
y2 = y1;
break;
case OBJ_CHANNEL :
y1 = CalcLineValue(ObjName, 0, MODE_UPPER, ObjType);
y2 = CalcLineValue(ObjName, 0, MODE_LOWER, ObjType);
break;
default :
y1 = -1;
y2 = -1;
}
if ((y1 > 0) && (y1 < Bid) && (y1 > MaxBelow)) // Á½ÌõÏß¶¼ÔÚµ±Ç°¼ÛÏ·½
{
MaxBelow = y1;
iBelow = i;
}
else if ((y2 > Bid) && (y2 < MinAbove)) // Á½ÌõÏß¶¼ÔÚµ±Ç°¼ÛÉÏ·½
{
MinAbove = y2;
iAbove = i;
}
else // Á½ÌõÏßÒ»ÉÏÒ»ÏÂ
{
if ((y1 > 0) && (y1 < MinAbove))
{
MinAbove = y1;
iAbove = i;
}
if (y2 > MaxBelow)
{
MaxBelow = y2;
iBelow = i;
}
}
}
switch (Type)
{
case OP_BUY :
iTP = iAbove;
iSL = iBelow;
break;
case OP_SELL :
iTP = iBelow;
iSL = iAbove;
break;
default :
iTP = -1;
iSL = -1;
}
if (GetTPObj)
{
if (iTP >= 0)
TPObjName = ObjectName(iTP);
}
if (GetSLObj)
{
if (iSL >= 0)
SLObjName = ObjectName(iSL);
}
}
// === ¼ÆËã»ñÀû¼ÛºÍÖ¹Ëð¼Û ===
void CalcPrice(double &TPPrice, double &SLPrice)
{
// »ñÀû¼Û
switch (TP_Method)
{
case 1 :
TPPrice = (1 + TP_Env_Dev * 0.01) * iMA(NULL, TP_TimeFrame, TP_MA_Period, 0, TP_MA_Method, TP_MA_Price, TP_Shift);
break;
case 2 :
TPPrice = CalcLineValue(TPObjName, TP_Shift, 1 + OpType);
break;
default :
TPPrice = -1;
}
// Ö¹Ëð¼Û
switch (SL_Method)
{
case 1 :
SLPrice = (1 + SL_Env_Dev * 0.01) * iMA(NULL, SL_TimeFrame, SL_MA_Period, 0, SL_MA_Method, TP_MA_Price, SL_Shift);
break;
case 2 :
SLPrice = CalcLineValue(SLObjName, SL_Shift, 2 - OpType);
break;
case 3 :
SLPrice = iSAR(NULL, SL_TimeFrame, SL_SARStep, SL_SARMax, SL_Shift);
break;
default :
SLPrice = -1;
}
}
// === ¼ÆËãÖ±ÏßÔÚij¸ökÏßµÄÖµ ===
double CalcLineValue(string ObjName, int Shift, int ValueIndex = 1, int ObjType = -1)
{
double y1, y2, delta, ret;
int i;
if ((ObjType < 0) && (StringLen(ObjName) > 0))
ObjType = ObjectType(ObjName);
switch (ObjType)
{
case OBJ_TREND :
case OBJ_TRENDBYANGLE :
ret = LineGetValueByShift(ObjName, Shift);
break;
case OBJ_CHANNEL :
i = GetBarShift(Symbol(), 0, ObjectGet(ObjName, OBJPROP_TIME3));
delta = ObjectGet(ObjName, OBJPROP_PRICE3) - LineGetValueByShift(ObjName, i);
y1 = LineGetValueByShift(ObjName, Shift);
y2 = y1 + delta;
if (ValueIndex == MODE_UPPER)
ret = MathMax(y1, y2);
else if (ValueIndex == MODE_LOWER)
ret = MathMin(y1, y2);
else
ret = -1;
break;
default :
ret = -1;
}
return(ret);
}
// === ÏÔʾ»ñÀûÖ¹Ëð¼ÛˮƽÏß ===
void ShowTPSLLines(double TPPrice, double SLPrice)
{
if (TPPrice < 0)
ObjectDelete(TP_PRICE_LINE);
else
{
if (FindObject(TP_PRICE_LINE) < 0)
{
ObjectCreate(TP_PRICE_LINE, OBJ_HLINE, 0, 0, 0);
ObjectSet(TP_PRICE_LINE, OBJPROP_COLOR, TP_LineColor);
ObjectSet(TP_PRICE_LINE, OBJPROP_STYLE, STYLE_DASHDOTDOT);
ObjectSet(TP_PRICE_LINE, OBJPROP_WIDTH, 1);
}
ObjectMove(TP_PRICE_LINE, 0, Time[0], TPPrice);
}
if (SLPrice < 0)
ObjectDelete(SL_PRICE_LINE);
else
{
if (FindObject(SL_PRICE_LINE) < 0)
{
ObjectCreate(SL_PRICE_LINE, OBJ_HLINE, 0, 0, 0);
ObjectSet(SL_PRICE_LINE, OBJPROP_COLOR, SL_LineColor);
ObjectSet(SL_PRICE_LINE, OBJPROP_STYLE, STYLE_DASHDOTDOT);
ObjectSet(SL_PRICE_LINE, OBJPROP_WIDTH, 1);
}
ObjectMove(SL_PRICE_LINE, 0, Time[0], SLPrice);
}
}
// === ²éÕÒ¶ÔÏó ===
int FindObject(string Name)
{
if (StringLen(Name) <= 0)
return(-1);
else
return(ObjectFind(Name));
}
// === ƽ²Ö ===
void CloseOrder(int Ticket, int type)
{
double ClosePrice;
string str[2] = {"TP", "SL"};
if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES))
{
if (OrderType() == OP_BUY)
ClosePrice = MarketInfo(Symbol(), MODE_BID);
else
ClosePrice = MarketInfo(Symbol(), MODE_ASK);
if (OrderClose(Ticket, OrderLots(), ClosePrice, 0))
Print("Order #", Ticket, " was closed successfully at ", str[type], " ", ClosePrice);
else
Print("Order #", Ticket, " reached ", str[type], " ", ClosePrice, ", but failed to close for error ", GetLastError());
}
}
// === ¼ÆËãÖ±ÏßÉϵÄÖµ ===
double LineGetValueByShift(string ObjName, int Shift)
{
double i1, i2, i, y1, y2, y;
i1 = GetBarShift(Symbol(), 0, ObjectGet(ObjName, OBJPROP_TIME1));
i2 = GetBarShift(Symbol(), 0, ObjectGet(ObjName, OBJPROP_TIME2));
y1 = ObjectGet(ObjName, OBJPROP_PRICE1);
y2 = ObjectGet(ObjName, OBJPROP_PRICE2);
if (i1 < i2)
{
i = i1;
i1 = i2;
i2 = i;
y = y1;
y1 = y2;
y2 = y;
}
if (Shift > i1)
y = (y2 - y1) / (i2 - i1) * (Shift - i1) + y1;
else
y = ObjectGetValueByShift(ObjName, Shift);
return(y);
}
// === ȡʱ¼äÖµµÄshiftÊý ===
int GetBarShift(string symbol, int timeframe, datetime time)
{
int now;
now = iTime(symbol, timeframe, 0);
if (time < now + timeframe * 60)
return(iBarShift(symbol, timeframe, time));
else
{
if (timeframe == 0)
timeframe = Period();
return((now - time) / timeframe / 60);
}
}
Comments