Skip to content

Commit e23e2f2

Browse files
author
EarnForex
authored
3.04
1. Added a dark theme mode, which can be set via the DarkMode input parameter. 2. Added an option to display breakeven lines at levels where the Position Sizer will apply breakeven to existing positions. 3. Added the Entry line label to display the distance from the current price to the Entry level for pending orders. 4. Added input parameters (ShowMaxParametersOnTrading, ShowFusesOnTrading, and ShowCheckboxesOnTrading) to make the Trading tab more compact. 5. Added separate total and per-symbol fields to control volume, risk, and number of trades on the Trading tab. 6. Added an input parameter (SettingsFile) to let users load their own custom settings file with panel fields configured according to their needs. The EA won't delete custom settings files. 7. Added two new hotkeys — to set a stop-loss (SetStopLossHotKey) and a take-profit (SetTakeProfitHotKey) to the price level at the mouse pointer's current position. 8. Added an option to change the translation of the panel's interface in MetaTrader 5. Language files are currently only available for Ukrainian and Russian. Users can create and use their own translation files. 9. Changed the breakeven mechanism to take into account the size of the commission if UseCommissionToSetTPDistance is set to true. 10. Changed the additional TP fields to appear with some non-zero value if the main TP is non-zero. 11. Fixed a bug when switching the chart's symbol could result in line labels disappearing if SymbolChange was set to Keep panel as is. 12. Fixed a bug in the MT5 version that resulted in the trade type not resetting properly when SymbolChange was set to Reset to defaults on symbol change. 13. Fixed a bug that resulted in false warnings and incorrect position size calculation when the EA failed to get the symbol information at the first attempt. 14. Fixed a bug that resulted in some of the +/- buttons to remain on the chart when the panel was minimized. 15. Fixed a bug that resulted in the stop-loss not keeping its correct distance when SLDistanceInPoints was set to true. 16. Fixed a bug when the additional funds asterisk remained visible even when the panel was minimized. 17. Fixed a bug in the MT5 version that resulted in the risk field resetting to default when the user clicked on the position size field after setting it to a custom value. 18. Fixed a bug that resulted in the stop-loss line sometimes disappearing on a symbol change. 19. Fixed a bug in the MT5 version that resulted in the Stop Price line appearing after switching from Stop Limit to Instant and setting the DisableStopLimit input parameter to true. 20. Fixed a bug that would result in wrong value appearing in the account size field after clicking on it and then clicking outside if the value contained a thousands separator. 21. Fixed a bug in the MT5 version that caused a critical 'array out of range' error when clicking on the +/- buttons for a single take-profit field. 22. Fixed a bug in the MT4 version that caused a critical 'array out of range' error when switching the chart symbol to a one with more additional TPs saved in a settings file. 23. Fixed a bug that caused the risk to be calculated based on the percentage value instead of the money value when Custom Balance was updated even if the MoneyRisk parameter was greater than 0. 24. Fixed a bug with ATR timeframe button not working. 25. Fixed a bug with incorrect volume share allocation when adding a new TP. 26. Fixed a bug in the MT5 version that caused a critical 'stack overflow' error when the EA failed to convert a symbol's profit or margin currency. 27. Fixed a bug that would cause TP values set in points to shift when dragging doing some unrelated chart manipulations.
1 parent 45e7c67 commit e23e2f2

File tree

13 files changed

+2878
-985
lines changed

13 files changed

+2878
-985
lines changed

MQL4/Experts/Position Sizer/Defines.mqh

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,19 @@
99
#include <Controls\Label.mqh>
1010
#include <Arrays\List.mqh>
1111

12-
#define CONTROLS_EDIT_COLOR_ENABLE C'255,255,255'
13-
#define CONTROLS_EDIT_COLOR_DISABLE C'221,221,211'
12+
color CONTROLS_EDIT_COLOR_ENABLE = C'255,255,255';
13+
color CONTROLS_EDIT_COLOR_DISABLE = C'221,221,211';
1414

15-
#define CONTROLS_BUTTON_COLOR_ENABLE C'200,200,200'
16-
#define CONTROLS_BUTTON_COLOR_DISABLE C'224,224,224'
15+
color CONTROLS_BUTTON_COLOR_ENABLE = C'200,200,200';
16+
color CONTROLS_BUTTON_COLOR_DISABLE = C'224,224,224';
17+
18+
color DARKMODE_BG_DARK_COLOR = 0x444444;
19+
color DARKMODE_CONTROL_BRODER_COLOR = 0x888888;
20+
color DARKMODE_MAIN_AREA_BORDER_COLOR = 0x333333;
21+
color DARKMODE_MAIN_AREA_BG_COLOR = 0x666666;
22+
color DARKMODE_EDIT_BG_COLOR = 0xAAAAAA;
23+
color DARKMODE_BUTTON_BG_COLOR = 0xA19999;
24+
color DARKMODE_TEXT_COLOR = 0x000000;;
1725

1826
enum ENTRY_TYPE
1927
{
@@ -82,6 +90,13 @@ enum COMMISSION_TYPE
8290
COMMISSION_PERCENT, // Percentage
8391
};
8492

93+
enum CALCULATE_RISK_FOR_TRADING_TAB
94+
{
95+
CALCULATE_RISK_FOR_TRADING_TAB_NO, // Normal calculation
96+
CALCULATE_RISK_FOR_TRADING_TAB_TOTAL, // For Trading tab - total
97+
CALCULATE_RISK_FOR_TRADING_TAB_PER_SYMBOL // For Trading tab - per symbol
98+
};
99+
85100
struct Settings
86101
{
87102
ENTRY_TYPE EntryType;
@@ -116,7 +131,6 @@ struct Settings
116131
int MaxSpread;
117132
int MaxEntrySLDistance;
118133
int MinEntrySLDistance;
119-
double MaxPositionSize;
120134
// For SL/TP distance modes:
121135
int StopLoss;
122136
int TakeProfit;
@@ -131,9 +145,12 @@ struct Settings
131145
bool CommentAutoSuffix;
132146
int TrailingStopPoints;
133147
int BreakEvenPoints;
134-
int MaxNumberOfTrades;
135-
bool AllSymbols;
136-
double MaxTotalRisk;
148+
int MaxNumberOfTradesTotal;
149+
int MaxNumberOfTradesPerSymbol;
150+
double MaxPositionSizeTotal;
151+
double MaxPositionSizePerSymbol;
152+
double MaxRiskTotal;
153+
double MaxRiskPerSymbol;
137154
// For ATR:
138155
int ATRPeriod;
139156
double ATRMultiplierSL;
2.62 KB
Binary file not shown.

MQL4/Experts/Position Sizer/Position Sizer Trading.mqh

Lines changed: 135 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -98,34 +98,39 @@ void Trade()
9898
}
9999
}
100100

101-
if (sets.MaxNumberOfTrades > 0)
101+
if ((sets.MaxNumberOfTradesTotal > 0) || (sets.MaxNumberOfTradesPerSymbol > 0))
102102
{
103103
int total = OrdersTotal();
104-
int cnt = 0;
104+
int cnt = 0, persymbol_cnt = 0;
105105
for (int i = 0; i < total; i++)
106106
{
107107
if (!OrderSelect(i, SELECT_BY_POS)) continue;
108108
if ((sets.MagicNumber != 0) && (OrderMagicNumber() != sets.MagicNumber)) continue;
109-
if ((!sets.AllSymbols) && (OrderSymbol() != Symbol())) continue;
109+
if (OrderSymbol() == Symbol()) persymbol_cnt++;
110110
cnt++;
111111
}
112-
if (cnt >= sets.MaxNumberOfTrades)
112+
if ((cnt + sets.TakeProfitsNumber > sets.MaxNumberOfTradesTotal) && (sets.MaxNumberOfTradesTotal > 0))
113113
{
114-
Alert("Not taking a trade - current # of traes (", cnt, ") >= maximum number of trades (", sets.MaxNumberOfTrades, ").");
114+
Alert("Not taking a trade - current total # of trades (", cnt, ") + number of trades in execution (", sets.TakeProfitsNumber, ") > maximum total number of trades allowed (", sets.MaxNumberOfTradesTotal, ").");
115+
return;
116+
}
117+
if ((persymbol_cnt + sets.TakeProfitsNumber > sets.MaxNumberOfTradesPerSymbol) && (sets.MaxNumberOfTradesPerSymbol > 0))
118+
{
119+
Alert("Not taking a trade - current # of trades per symbol (", persymbol_cnt, ") + number of trades in execution (", sets.TakeProfitsNumber, ") > maximum number of trades per symbol allowed (", sets.MaxNumberOfTradesPerSymbol, ").");
115120
return;
116121
}
117122
}
118123

119-
if (sets.MaxTotalRisk > 0)
124+
if (sets.MaxRiskTotal > 0)
120125
{
121-
CalculatePortfolioRisk(true);
126+
CalculatePortfolioRisk(CALCULATE_RISK_FOR_TRADING_TAB_TOTAL);
122127
double risk;
123128
if (PortfolioLossMoney != DBL_MAX)
124129
{
125130
risk = (PortfolioLossMoney + OutputRiskMoney) / AccSize * 100;
126-
if (risk > sets.MaxTotalRisk)
131+
if (risk > sets.MaxRiskTotal)
127132
{
128-
Alert("Not taking a trade - total potential risk (", DoubleToString(risk, 2), ") >= maximum risk (", DoubleToString(sets.MaxTotalRisk, 2), ").");
133+
Alert("Not taking a trade - total potential risk (", DoubleToString(risk, 2), ") >= maximum total risk allowed (", DoubleToString(sets.MaxRiskTotal, 2), ").");
129134
return;
130135
}
131136
}
@@ -135,6 +140,25 @@ void Trade()
135140
return;
136141
}
137142
}
143+
if (sets.MaxRiskPerSymbol > 0)
144+
{
145+
CalculatePortfolioRisk(CALCULATE_RISK_FOR_TRADING_TAB_PER_SYMBOL);
146+
double risk;
147+
if (PortfolioLossMoney != DBL_MAX)
148+
{
149+
risk = (PortfolioLossMoney + OutputRiskMoney) / AccSize * 100;
150+
if (risk > sets.MaxRiskPerSymbol)
151+
{
152+
Alert("Not taking a trade - potential risk per symbol (", DoubleToString(risk, 2), ") >= maximum risk per symbol allowed (", DoubleToString(sets.MaxRiskPerSymbol, 2), ").");
153+
return;
154+
}
155+
}
156+
else
157+
{
158+
Alert("Not taking a trade - infinite potential risk per symbol.");
159+
return;
160+
}
161+
}
138162

139163
ENUM_SYMBOL_TRADE_EXECUTION Execution_Mode = (ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(Symbol(), SYMBOL_TRADE_EXEMODE);
140164
string warning_suffix = "";
@@ -189,20 +213,25 @@ void Trade()
189213
}
190214
}
191215

192-
if (sets.MaxPositionSize > 0)
216+
if ((sets.MaxPositionSizeTotal > 0) && (sets.MaxPositionSizePerSymbol > 0))
193217
{
194218
int total = OrdersTotal();
195-
double volume = 0;
219+
double volume = 0, volume_persymbol = 0;
196220
for (int i = 0; i < total; i++)
197221
{
198222
if (!OrderSelect(i, SELECT_BY_POS)) continue;
199223
if ((sets.MagicNumber != 0) && (OrderMagicNumber() != sets.MagicNumber)) continue;
200-
if ((!sets.AllSymbols) && (OrderSymbol() != Symbol())) continue;
224+
if (OrderSymbol() == Symbol()) volume_persymbol += OrderLots();
201225
volume += OrderLots();
202226
}
203-
if (volume + PositionSize > sets.MaxPositionSize)
227+
if ((volume + PositionSize > sets.MaxPositionSizeTotal) && (sets.MaxPositionSizeTotal > 0))
204228
{
205-
Alert("Not taking a trade - current total volume (", DoubleToString(volume, LotStep_digits), ") + new position volume (", DoubleToString(PositionSize, LotStep_digits), ") >= maximum total volume (", sets.MaxPositionSize, ").");
229+
Alert("Not taking a trade - current total volume (", DoubleToString(volume, LotStep_digits), ") + new position volume (", DoubleToString(PositionSize, LotStep_digits), ") >= maximum total volume allowed (", DoubleToString(sets.MaxPositionSizeTotal, LotStep_digits), ").");
230+
return;
231+
}
232+
if ((volume_persymbol + PositionSize > sets.MaxPositionSizePerSymbol) && (sets.MaxPositionSizePerSymbol > 0))
233+
{
234+
Alert("Not taking a trade - current volume per symbol (", DoubleToString(volume_persymbol, LotStep_digits), ") + new position volume (", DoubleToString(PositionSize, LotStep_digits), ") >= maximum volume per symbol allowed (", DoubleToString(sets.MaxPositionSizePerSymbol, LotStep_digits), ").");
206235
return;
207236
}
208237
}
@@ -480,7 +509,38 @@ void DoTrailingStop()
480509
// Sets SL to breakeven based on the Magic number and symbol.
481510
void DoBreakEven()
482511
{
483-
if ((!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) || (!TerminalInfoInteger(TERMINAL_CONNECTED)) || (!MQLInfoInteger(MQL_TRADE_ALLOWED))) return;
512+
if (!TerminalInfoInteger(TERMINAL_CONNECTED)) return;
513+
514+
// Delete old BE lines if necessary.
515+
if (be_line_color != clrNONE)
516+
{
517+
int obj_total = ObjectsTotal(ChartID(), -1, OBJ_HLINE);
518+
for (int i = obj_total - 1; i >= 0; i--)
519+
{
520+
string obj_name = ObjectName(ChartID(), i, -1, OBJ_HLINE);
521+
if (StringFind(obj_name, ObjectPrefix + "BE") == -1) continue; // Skip all other horizontal lines.
522+
int ticket = (int)StringToInteger(StringSubstr(obj_name, StringLen(ObjectPrefix + "BE")));
523+
if (!OrderSelect(ticket, SELECT_BY_TICKET)) // No longer exists.
524+
{
525+
ObjectDelete(ChartID(), obj_name); // Delete the line.
526+
if (ShowLineLabels) ObjectDelete(ChartID(), ObjectPrefix + "BEL" + IntegerToString(ticket)); // Delete the label.
527+
}
528+
else // Check if already triggered. Order selected.
529+
{
530+
double be_price = NormalizeDouble(StringToDouble(ObjectGetString(ChartID(), obj_name, OBJPROP_TOOLTIP)), _Digits);
531+
if (((OrderType() == OP_BUY) && (OrderStopLoss() >= be_price)) // Already triggered.
532+
|| ((OrderType() == OP_SELL) && (OrderStopLoss() <= be_price) && (OrderStopLoss() != 0)))
533+
{
534+
ObjectDelete(ChartID(), obj_name); // Delete the line.
535+
if (ShowLineLabels) ObjectDelete(ChartID(), ObjectPrefix + "BEL" + IntegerToString(ticket)); // Delete the label.
536+
}
537+
}
538+
}
539+
}
540+
541+
if (sets.BreakEvenPoints <= 0) return;
542+
543+
if ((!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) || (!MQLInfoInteger(MQL_TRADE_ALLOWED))) return;
484544

485545
for (int i = 0; i < OrdersTotal(); i++)
486546
{
@@ -489,25 +549,44 @@ void DoBreakEven()
489549
else
490550
{
491551
if ((OrderSymbol() != Symbol()) || (OrderMagicNumber() != sets.MagicNumber)) continue;
552+
553+
// Based on the commission if UseCommissionToSetTPDistance is set to true.
554+
double extra_be_distance = 0;
555+
if ((UseCommissionToSetTPDistance) && (sets.CommissionPerLot != 0))
556+
{
557+
// Calculate real commission in currency units.
558+
double commission = CalculateCommission();
559+
560+
// Extra BE Distance = Commission Size / Point_value.
561+
// Commission Size = Commission * 2.
562+
// Extra BE Distance = Commission * 2 / Point_value.
563+
if ((UnitCost_reward != 0) && (TickSize != 0))
564+
extra_be_distance = commission * 2 / (UnitCost_reward / TickSize);
565+
}
566+
492567
if (OrderType() == OP_BUY)
493568
{
494-
double BE = NormalizeDouble(OrderOpenPrice() + sets.BreakEvenPoints * _Point, _Digits);
495-
if ((Bid >= BE) && (OrderOpenPrice() > OrderStopLoss())) // Only move to breakeven if the current stop-loss is lower.
569+
double BE_threshold = NormalizeDouble(OrderOpenPrice() + sets.BreakEvenPoints * _Point, _Digits);
570+
double BE_price = NormalizeDouble(OrderOpenPrice() + extra_be_distance, _Digits);
571+
if ((be_line_color != clrNONE) && (BE_price > OrderStopLoss())) DrawBELine(OrderTicket(), BE_threshold, BE_price); // Only draw if not triggered yet.
572+
if ((Bid >= BE_threshold) && (Bid >= BE_price) && (BE_price > OrderStopLoss())) // Only move to BE if the price reached the necessary threshold, the price is above the calculated BE price, and the current stop-loss is lower.
496573
{
497574
// Write Open price to the SL field.
498-
if (!OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), OrderExpiration()))
575+
if (!OrderModify(OrderTicket(), OrderOpenPrice(), BE_price, OrderTakeProfit(), OrderExpiration()))
499576
Print("OrderModify Buy BE failed " + ErrorDescription(GetLastError()) + ".");
500577
else
501578
Print("Breakeven was applied to position - " + Symbol() + " BUY-order #" + IntegerToString(OrderTicket()) + " Lotsize = " + DoubleToString(OrderLots(), LotStep_digits) + ", OpenPrice = " + DoubleToString(OrderOpenPrice(), _Digits) + ", Stop-Loss was moved from " + DoubleToString(OrderStopLoss(), _Digits) + ".");
502579
}
503580
}
504581
else if (OrderType() == OP_SELL)
505582
{
506-
double BE = NormalizeDouble(OrderOpenPrice() - sets.BreakEvenPoints * _Point, _Digits);
507-
if ((Ask <= BE) && ((OrderOpenPrice() < OrderStopLoss()) || (OrderStopLoss() == 0))) // Only move to breakeven if the current stop-loss is higher (or zero).
583+
double BE_threshold = NormalizeDouble(OrderOpenPrice() - sets.BreakEvenPoints * _Point, _Digits);
584+
double BE_price = NormalizeDouble(OrderOpenPrice() - extra_be_distance, _Digits);
585+
if ((be_line_color != clrNONE) && ((BE_price < OrderStopLoss()) || (OrderStopLoss() == 0))) DrawBELine(OrderTicket(), BE_threshold, BE_price);
586+
if ((Ask <= BE_threshold) && (Ask <= BE_price) && ((BE_price < OrderStopLoss()) || (OrderStopLoss() == 0))) // Only move to BE if the price reached the necessary threshold, the price below the calculated BE price, and the current stop-loss is higher (or zero).
508587
{
509588
// Write Open price to the SL field.
510-
if (!OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), OrderExpiration()))
589+
if (!OrderModify(OrderTicket(), OrderOpenPrice(), BE_price, OrderTakeProfit(), OrderExpiration()))
511590
Print("OrderModify Sell BE failed " + ErrorDescription(GetLastError()) + ".");
512591
else
513592
Print("Breakeven was applied to position - " + Symbol() + " SELL-order #" + IntegerToString(OrderTicket()) + " Lotsize = " + DoubleToString(OrderLots(), LotStep_digits) + ", OpenPrice = " + DoubleToString(OrderOpenPrice(), _Digits) + ", Stop-Loss was moved from " + DoubleToString(OrderStopLoss(), _Digits) + ".");
@@ -516,4 +595,39 @@ void DoBreakEven()
516595
}
517596
}
518597
}
598+
599+
void DrawBELine(int ticket, double be_threshold, double be_price)
600+
{
601+
string obj_name = ObjectPrefix + "BE" + IntegerToString(ticket); // Line.
602+
ObjectCreate(ChartID(), obj_name, OBJ_HLINE, 0, TimeCurrent(), be_threshold);
603+
ObjectSetDouble(ChartID(), obj_name, OBJPROP_PRICE, be_threshold);
604+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_STYLE, be_line_style);
605+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, be_line_color);
606+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_WIDTH, be_line_width);
607+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_SELECTABLE, false);
608+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BACK, true);
609+
ObjectSetString(ChartID(), obj_name, OBJPROP_TOOLTIP, DoubleToString(be_price, _Digits)); // Store BE price in the tooltip.
610+
611+
if (sets.ShowLines) ObjectSetInteger(ChartID(), obj_name, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);
612+
else ObjectSetInteger(ChartID(), obj_name, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);
613+
614+
if (ShowLineLabels)
615+
{
616+
obj_name = ObjectPrefix + "BEL" + IntegerToString(ticket); // Label.
617+
ObjectCreate(ChartID(), obj_name, OBJ_LABEL, 0, 0, 0);
618+
if (sets.ShowLines) ObjectSetInteger(ChartID(), obj_name, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);
619+
else ObjectSetInteger(ChartID(), obj_name, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);
620+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_COLOR, clrNONE);
621+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_SELECTABLE, false);
622+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_HIDDEN, false);
623+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
624+
ObjectSetInteger(ChartID(), obj_name, OBJPROP_BACK, DrawTextAsBackground);
625+
ObjectSetString(ChartID(), obj_name, OBJPROP_TOOLTIP, "");
626+
string text = "BE for ";
627+
if (OrderType() == OP_BUY) text += "Buy";
628+
else if (OrderType() == OP_SELL) text += "Sell";
629+
text += " #" + IntegerToString(ticket);
630+
DrawLineLabel(obj_name, text, be_threshold, be_line_color, false, -6);
631+
}
632+
}
519633
//+------------------------------------------------------------------+

0 commit comments

Comments
 (0)