Skip to content

Commit ba9f9a4

Browse files
author
EarnForex
authored
1.02
1. Added an input parameter to enable trailing on all currency pairs. 2. Added normalization of the calculated stop-loss level by the symbol's tick size.
1 parent f73198f commit ba9f9a4

File tree

5 files changed

+84
-53
lines changed

5 files changed

+84
-53
lines changed

MQL4/Experts/Trailing Stop on Profit.mq4

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#property link "https://www.earnforex.com/metatrader-expert-advisors/Trailing-Stop-on-Profit/"
2-
#property version "1.01"
2+
#property version "1.02"
33
#property strict
4-
#property copyright "EarnForex.com - 2022"
4+
#property copyright "EarnForex.com - 2023"
55
#property description "This Expert Advisor will start trailing the stop-loss after a given profit is reached."
66
#property description " "
77
#property description "WARNING: No warranty. This EA is offered \"as is\". Use at your own risk.\r\n"
@@ -21,6 +21,7 @@ input string Comment_1 = "===================="; // Expert Advisor Settings
2121
input int TrailingStop = 50; // Trailing Stop, points
2222
input int Profit = 100; // Profit in points when TS should kick in.
2323
input string Comment_2 = "===================="; // Orders Filtering Options
24+
input bool OnlyCurrentSymbol = true; // Apply to current symbol only
2425
input ENUM_CONSIDER OnlyType = All; // Apply to
2526
input bool UseMagic = false; // Filter by magic number
2627
input int MagicNumber = 0; // Magic number (if above is true)
@@ -34,7 +35,7 @@ input bool SendApp = true; // Send notification to mobil
3435
input bool SendEmail = true; // Send notification via email
3536
input string Comment_3a = "===================="; // Graphical Window
3637
input bool ShowPanel = true; // Show graphical panel
37-
input string IndicatorName = "TSOP"; // Indicator name (to name the objects)
38+
input string ExpertName = "TSOP"; // Expert name (to name the objects)
3839
input int Xoff = 20; // Horizontal spacing for the control panel
3940
input int Yoff = 20; // Vertical spacing for the control panel
4041

@@ -94,47 +95,63 @@ void TrailingStop()
9495
Print("ERROR - ", ErrorText);
9596
break;
9697
}
97-
if (OrderSymbol() != Symbol()) continue;
98+
if ((OnlyCurrentSymbol) && (OrderSymbol() != Symbol())) continue;
9899
if ((UseMagic) && (OrderMagicNumber() != MagicNumber)) continue;
99100
if ((UseComment) && (StringFind(OrderComment(), CommentFilter) < 0)) continue;
100101
if ((OnlyType != All) && (OrderType() != OnlyType)) continue;
101102

103+
int eDigits = (int)MarketInfo(OrderSymbol(), MODE_DIGITS);
104+
double point = MarketInfo(OrderSymbol(), MODE_POINT);
105+
double ask = SymbolInfoDouble(OrderSymbol(), SYMBOL_ASK);
106+
double bid = SymbolInfoDouble(OrderSymbol(), SYMBOL_BID);
107+
double TickSize = SymbolInfoDouble(OrderSymbol(), SYMBOL_TRADE_TICK_SIZE);
108+
102109
// Normalize trailing stop value to the point value.
103-
double TSTP = TrailingStop * _Point;
104-
double P = Profit * _Point;
110+
double TSTP = TrailingStop * point;
111+
double P = Profit * point;
105112

106113
if (OrderType() == OP_BUY)
107114
{
108-
if (NormalizeDouble(Bid - OrderOpenPrice(), _Digits) >= NormalizeDouble(P, _Digits))
115+
if (NormalizeDouble(bid - OrderOpenPrice(), eDigits) >= NormalizeDouble(P, eDigits))
109116
{
110-
if ((TSTP != 0) && (OrderStopLoss() < NormalizeDouble(Bid - TSTP, _Digits)))
117+
double new_sl = NormalizeDouble(bid - TSTP, eDigits);
118+
if (TickSize > 0) // Adjust for tick size granularity.
111119
{
112-
ModifyOrder(OrderTicket(), OrderOpenPrice(), NormalizeDouble(Bid - TSTP, _Digits), OrderTakeProfit());
120+
new_sl = NormalizeDouble(MathRound(new_sl / TickSize) * TickSize, eDigits);
121+
}
122+
if ((TSTP != 0) && (OrderStopLoss() < new_sl))
123+
{
124+
ModifyOrder(OrderTicket(), OrderOpenPrice(), new_sl, OrderTakeProfit(), OrderSymbol());
113125
}
114126
}
115127
}
116128
else if (OrderType() == OP_SELL)
117129
{
118-
if (NormalizeDouble(OrderOpenPrice() - Ask, _Digits) >= NormalizeDouble(P, _Digits))
130+
if (NormalizeDouble(OrderOpenPrice() - ask, eDigits) >= NormalizeDouble(P, eDigits))
119131
{
120-
if ((TSTP != 0) && ((OrderStopLoss() > NormalizeDouble(Ask + TSTP, _Digits)) || (OrderStopLoss() == 0)))
132+
double new_sl = NormalizeDouble(ask + TSTP, eDigits);
133+
if (TickSize > 0) // Adjust for tick size granularity.
134+
{
135+
new_sl = NormalizeDouble(MathRound(new_sl / TickSize) * TickSize, eDigits);
136+
}
137+
if ((TSTP != 0) && ((OrderStopLoss() > new_sl) || (OrderStopLoss() == 0)))
121138
{
122-
ModifyOrder(OrderTicket(), OrderOpenPrice(), NormalizeDouble(Ask + TSTP, _Digits), OrderTakeProfit());
139+
ModifyOrder(OrderTicket(), OrderOpenPrice(), new_sl, OrderTakeProfit(), OrderSymbol());
123140
}
124141
}
125142
}
126143
}
127144
}
128145

129-
void ModifyOrder(int Ticket, double OpenPrice, double SLPrice, double TPPrice)
146+
void ModifyOrder(int Ticket, double OpenPrice, double SLPrice, double TPPrice, string symbol)
130147
{
131148
for (int i = 1; i <= OrderOpRetry; i++) // Several attempts to modify the order.
132149
{
133150
bool result = OrderModify(Ticket, OpenPrice, SLPrice, TPPrice, 0);
134151
if (result)
135152
{
136153
Print("TRADE - UPDATE SUCCESS - Order ", Ticket, " new stop-loss ", SLPrice);
137-
NotifyStopLossUpdate(Ticket, SLPrice);
154+
NotifyStopLossUpdate(Ticket, SLPrice, symbol);
138155
break;
139156
}
140157
else
@@ -143,22 +160,22 @@ void ModifyOrder(int Ticket, double OpenPrice, double SLPrice, double TPPrice)
143160
string ErrorText = ErrorDescription(Error);
144161
Print("ERROR - UPDATE FAILED - error modifying order ", Ticket, " return error: ", Error, " Open=", OpenPrice,
145162
" Old SL=", OrderStopLoss(),
146-
" New SL=", SLPrice, " Bid=", MarketInfo(OrderSymbol(), MODE_BID), " Ask=", MarketInfo(OrderSymbol(), MODE_ASK));
163+
" New SL=", SLPrice, " Bid=", MarketInfo(symbol, MODE_BID), " Ask=", MarketInfo(symbol, MODE_ASK));
147164
Print("ERROR - ", ErrorText);
148165
}
149166
}
150167
}
151168

152-
void NotifyStopLossUpdate(int Ticket, double SLPrice)
169+
void NotifyStopLossUpdate(int Ticket, double SLPrice, string symbol)
153170
{
154171
if (!EnableNotify) return;
155172
if ((!SendAlert) && (!SendApp) && (!SendEmail)) return;
156-
string EmailSubject = IndicatorName + " " + Symbol() + " Notification";
157-
string EmailBody = AccountCompany() + " - " + AccountName() + " - " + IntegerToString(AccountNumber()) + "\r\n\r\n" + IndicatorName + " Notification for " + Symbol() + "\r\n\r\n";
173+
string EmailSubject = ExpertName + " " + symbol + " Notification";
174+
string EmailBody = AccountCompany() + " - " + AccountName() + " - " + IntegerToString(AccountNumber()) + "\r\n\r\n" + ExpertName + " Notification for " + symbol + "\r\n\r\n";
158175
EmailBody += "Stop-loss for order " + IntegerToString(Ticket) + " moved to " + DoubleToString(SLPrice, _Digits);
159-
string AlertText = IndicatorName + " - " + Symbol() + " Notification: ";
176+
string AlertText = ExpertName + " - " + Symbol() + " Notification: ";
160177
AlertText += "Stop-loss for order " + IntegerToString(Ticket) + " moved to " + DoubleToString(SLPrice, _Digits);
161-
string AppText = AccountCompany() + " - " + AccountName() + " - " + IntegerToString(AccountNumber()) + " - " + IndicatorName + " - " + Symbol() + " - ";
178+
string AppText = AccountCompany() + " - " + AccountName() + " - " + IntegerToString(AccountNumber()) + " - " + ExpertName + " - " + symbol + " - ";
162179
AppText += "Stop-loss for order " + IntegerToString(Ticket) + " moved to " + DoubleToString(SLPrice, _Digits);
163180
if (SendAlert) Alert(AlertText);
164181
if (SendEmail)
@@ -169,12 +186,12 @@ void NotifyStopLossUpdate(int Ticket, double SLPrice)
169186
{
170187
if (!SendNotification(AppText)) Print("Error sending notification " + IntegerToString(GetLastError()));
171188
}
172-
Print(IndicatorName + " - last notification sent on " + TimeToString(TimeCurrent()));
189+
Print(ExpertName + " - last notification sent on " + TimeToString(TimeCurrent()));
173190
}
174191

175-
string PanelBase = IndicatorName + "-P-BAS";
176-
string PanelLabel = IndicatorName + "-P-LAB";
177-
string PanelEnableDisable = IndicatorName + "-P-ENADIS";
192+
string PanelBase = ExpertName + "-P-BAS";
193+
string PanelLabel = ExpertName + "-P-LAB";
194+
string PanelEnableDisable = ExpertName + "-P-ENADIS";
178195

179196
int PanelMovX = 50;
180197
int PanelMovY = 20;
@@ -256,7 +273,7 @@ void DrawPanel()
256273

257274
void CleanPanel()
258275
{
259-
ObjectsDeleteAll(ChartID(), IndicatorName);
276+
ObjectsDeleteAll(ChartID(), ExpertName);
260277
}
261278

262279
void ChangeTrailingEnabled()

MQL4/Files/EF-Icon-64x64px.ico

0 Bytes
Binary file not shown.

MQL5/Experts/Trailing Stop on Profit.mq5

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#property link "https://www.earnforex.com/metatrader-expert-advisors/Trailing-Stop-on-Profit/"
2-
#property version "1.01"
2+
#property version "1.02"
33
#property strict
4-
#property copyright "EarnForex.com - 2022"
4+
#property copyright "EarnForex.com - 2023"
55
#property description "This Expert Advisor will start trailing the stop-loss after a given profit is reached."
66
#property description " "
77
#property description "WARNING: No warranty. This EA is offered \"as is\". Use at your own risk.\r\n"
@@ -22,6 +22,7 @@ input group "Expert advisor settings"
2222
input int TrailingStop = 50; // Trailing Stop, points
2323
input int Profit = 100; // Profit in points when TS should kick in.
2424
input group "Orders filtering options"
25+
input bool OnlyCurrentSymbol = true; // Apply to current symbol only
2526
input ENUM_CONSIDER OnlyType = All; // Apply to
2627
input bool UseMagic = false; // Filter by magic number
2728
input int MagicNumber = 0; // Magic number (if above is true)
@@ -35,7 +36,7 @@ input bool SendApp = true; // Send notification to mobil
3536
input bool SendEmail = true; // Send notification via email
3637
input group "Graphical window"
3738
input bool ShowPanel = true; // Show graphical panel
38-
input string IndicatorName = "TSOP"; // Indicator name (to name the objects)
39+
input string ExpertName = "TSOP"; // Expert name (to name the objects)
3940
input int Xoff = 20; // Horizontal spacing for the control panel
4041
input int Yoff = 20; // Vertical spacing for the control panel
4142

@@ -106,53 +107,67 @@ void TrailingStop()
106107
if (SymbolInfoInteger(PositionGetString(POSITION_SYMBOL), SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) continue;
107108

108109
// Filters.
109-
if (PositionGetString(POSITION_SYMBOL) != Symbol()) continue;
110+
if ((OnlyCurrentSymbol) && (PositionGetString(POSITION_SYMBOL) != Symbol())) continue;
110111
if ((UseMagic) && (PositionGetInteger(POSITION_MAGIC) != MagicNumber)) continue;
111112
if ((UseComment) && (StringFind(PositionGetString(POSITION_COMMENT), CommentFilter) < 0)) continue;
112113
if ((OnlyType != All) && (PositionGetInteger(POSITION_TYPE) != OnlyType)) continue;
113114

115+
double point = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL), SYMBOL_POINT);
116+
114117
// Normalize trailing stop value to the point value.
115-
double TSTP = TrailingStop * _Point;
116-
double P = Profit * _Point;
118+
double TSTP = TrailingStop * point;
119+
double P = Profit * point;
117120

118-
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
119-
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
121+
double Bid = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL), SYMBOL_BID);
122+
double Ask = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL), SYMBOL_ASK);
120123
double OpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
121124
double StopLoss = PositionGetDouble(POSITION_SL);
122125
double TakeProfit = PositionGetDouble(POSITION_TP);
126+
int eDigits = (int)SymbolInfoInteger(PositionGetString(POSITION_SYMBOL), SYMBOL_DIGITS);
127+
double TickSize = SymbolInfoDouble(OrderSymbol(), SYMBOL_TRADE_TICK_SIZE);
123128

124129
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
125130
{
126-
if (NormalizeDouble(Bid - OpenPrice, _Digits) >= NormalizeDouble(P, _Digits))
131+
if (NormalizeDouble(Bid - OpenPrice, eDigits) >= NormalizeDouble(P, eDigits))
127132
{
128-
if ((TSTP != 0) && (StopLoss < NormalizeDouble(Bid - TSTP, _Digits)))
133+
double new_sl = NormalizeDouble(Bid - TSTP, eDigits);
134+
if (TickSize > 0) // Adjust for tick size granularity.
135+
{
136+
new_sl = NormalizeDouble(MathRound(new_sl / TickSize) * TickSize, eDigits);
137+
}
138+
if ((TSTP != 0) && (StopLoss < new_sl))
129139
{
130-
ModifyPosition(ticket, OpenPrice, NormalizeDouble(Bid - TSTP, _Digits), TakeProfit);
140+
ModifyPosition(ticket, OpenPrice, new_sl, TakeProfit, PositionGetString(POSITION_SYMBOL));
131141
}
132142
}
133143
}
134144
else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
135145
{
136-
if (NormalizeDouble(OpenPrice - Ask, _Digits) >= NormalizeDouble(P, _Digits))
146+
if (NormalizeDouble(OpenPrice - Ask, eDigits) >= NormalizeDouble(P, eDigits))
137147
{
138-
if ((TSTP != 0) && ((StopLoss > NormalizeDouble(Ask + TSTP, _Digits)) || (StopLoss == 0)))
148+
double new_sl = NormalizeDouble(Ask + TSTP, eDigits);
149+
if (TickSize > 0) // Adjust for tick size granularity.
150+
{
151+
new_sl = NormalizeDouble(MathRound(new_sl / TickSize) * TickSize, eDigits);
152+
}
153+
if ((TSTP != 0) && ((StopLoss > new_sl) || (StopLoss == 0)))
139154
{
140-
ModifyPosition(ticket, OpenPrice, NormalizeDouble(Ask + TSTP, _Digits), TakeProfit);
155+
ModifyPosition(ticket, OpenPrice, new_sl, TakeProfit, PositionGetString(POSITION_SYMBOL));
141156
}
142157
}
143158
}
144159
}
145160
}
146161

147-
void ModifyPosition(ulong Ticket, double OpenPrice, double SLPrice, double TPPrice)
162+
void ModifyPosition(ulong Ticket, double OpenPrice, double SLPrice, double TPPrice, string symbol)
148163
{
149164
for (int i = 1; i <= OrderOpRetry; i++) // Several attempts to modify the position.
150165
{
151166
bool result = Trade.PositionModify(Ticket, SLPrice, TPPrice);
152167
if (result)
153168
{
154169
Print("TRADE - UPDATE SUCCESS - Order ", Ticket, " new stop-loss ", SLPrice);
155-
NotifyStopLossUpdate(Ticket, SLPrice);
170+
NotifyStopLossUpdate(Ticket, SLPrice, symbol);
156171
break;
157172
}
158173
else
@@ -161,22 +176,21 @@ void ModifyPosition(ulong Ticket, double OpenPrice, double SLPrice, double TPPri
161176
string ErrorText = ErrorDescription(Error);
162177
Print("ERROR - UPDATE FAILED - error modifying order ", Ticket, " return error: ", Error, " Open=", OpenPrice,
163178
" Old SL=", PositionGetDouble(POSITION_SL),
164-
" New SL=", SLPrice, " Bid=", SymbolInfoDouble(Symbol(), SYMBOL_BID), " Ask=", SymbolInfoDouble(Symbol(), SYMBOL_ASK));
179+
" New SL=", SLPrice, " Bid=", SymbolInfoDouble(symbol, SYMBOL_BID), " Ask=", SymbolInfoDouble(symbol, SYMBOL_ASK));
165180
Print("ERROR - ", ErrorText);
166181
}
167182
}
168183
}
169184

170-
void NotifyStopLossUpdate(ulong Ticket, double SLPrice)
185+
void NotifyStopLossUpdate(ulong Ticket, double SLPrice, string symbol)
171186
{
172187
if (!EnableNotify) return;
173188
if ((!SendAlert) && (!SendApp) && (!SendEmail)) return;
174-
string EmailSubject = IndicatorName + " " + Symbol() + " Notification";
175-
string EmailBody = AccountInfoString(ACCOUNT_COMPANY) + " - " + AccountInfoString(ACCOUNT_NAME) + " - " + IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN)) + "\r\n\r\n" + IndicatorName + " Notification for " + Symbol() + "\r\n\r\n";
189+
string EmailSubject = ExpertName + " " + Symbol() + " Notification";
190+
string EmailBody = AccountInfoString(ACCOUNT_COMPANY) + " - " + AccountInfoString(ACCOUNT_NAME) + " - " + IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN)) + "\r\n\r\n" + ExpertName + " Notification for " + symbol + "\r\n\r\n";
176191
EmailBody += "Stop-loss for order " + IntegerToString(Ticket) + " moved to " + DoubleToString(SLPrice, _Digits);
177-
string AlertText = IndicatorName + " - Notification: ";
178-
AlertText += "Stop-loss for order " + IntegerToString(Ticket) + " moved to " + DoubleToString(SLPrice, _Digits);
179-
string AppText = AccountInfoString(ACCOUNT_COMPANY) + " - " + AccountInfoString(ACCOUNT_NAME) + " - " + IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN)) + " - " + IndicatorName + " - " + Symbol() + " - ";
192+
string AlertText = symbol + " - Stop-loss for order " + IntegerToString(Ticket) + " moved to " + DoubleToString(SLPrice, _Digits);
193+
string AppText = AccountInfoString(ACCOUNT_COMPANY) + " - " + AccountInfoString(ACCOUNT_NAME) + " - " + IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN)) + " - " + ExpertName + " - " + symbol + " - ";
180194
AppText += "Stop-loss for order " + IntegerToString(Ticket) + " moved to " + DoubleToString(SLPrice, _Digits);
181195
if (SendAlert) Alert(AlertText);
182196
if (SendEmail)
@@ -187,12 +201,12 @@ void NotifyStopLossUpdate(ulong Ticket, double SLPrice)
187201
{
188202
if (!SendNotification(AppText)) Print("Error sending notification " + IntegerToString(GetLastError()));
189203
}
190-
Print(IndicatorName + " - last notification sent on " + TimeToString(TimeCurrent()));
204+
Print(ExpertName + " - last notification sent on " + TimeToString(TimeCurrent()));
191205
}
192206

193-
string PanelBase = IndicatorName + "-P-BAS";
194-
string PanelLabel = IndicatorName + "-P-LAB";
195-
string PanelEnableDisable = IndicatorName + "-P-ENADIS";
207+
string PanelBase = ExpertName + "-P-BAS";
208+
string PanelLabel = ExpertName + "-P-LAB";
209+
string PanelEnableDisable = ExpertName + "-P-ENADIS";
196210

197211
int PanelMovX = 50;
198212
int PanelMovY = 20;
@@ -275,7 +289,7 @@ void DrawPanel()
275289

276290
void CleanPanel()
277291
{
278-
ObjectsDeleteAll(ChartID(), IndicatorName);
292+
ObjectsDeleteAll(ChartID(), ExpertName);
279293
}
280294

281295
void ChangeTrailingEnabled()

MQL5/Files/EF-Icon-64x64px.ico

0 Bytes
Binary file not shown.
1.44 KB
Loading

0 commit comments

Comments
 (0)