Skip to content

Commit b3c3f53

Browse files
author
EarnForex
authored
1.08
1. Added an input parameter (DoNotDisableEquityTS) to not disable equity trailing stop upon triggering. 2. Added an input parameter (AlertOnEquityTS) for alerts upon equity trailing stop closing trades. 3. Added an input parameter (CloseMostDistantFirst) to specify closing order for positions. 4. Renamed input parameter DoNotResetConditions to DoNotDisableConditions and DoNotResetActions to DoNotDisableActions. 5. Fixed a bug that prevented position closing when log file name wasn't specified. 6. Fixed a bug that prevented logging from working sometimes.
1 parent 4676abd commit b3c3f53

File tree

6 files changed

+45
-35
lines changed

6 files changed

+45
-35
lines changed

MQL4/Experts/Account Protector/Account Protector.mq4

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
//+------------------------------------------------------------------+
66
#property copyright "EarnForex.com"
77
#property link "https://www.earnforex.com/metatrader-expert-advisors/Account-Protector/"
8-
#property version "1.07"
9-
string Version = "1.07";
8+
#property version "1.08"
9+
string Version = "1.08";
1010
#property strict
1111

1212
#property description "Protects account balance by applying given actions when set conditions trigger."
@@ -19,8 +19,10 @@ input int Slippage = 2; // Slippage
1919
input string LogFileName = "log.txt"; // Log file name
2020
input Enable EnableEmergencyButton = No; // Enable emergency button
2121
input bool PanelOnTopOfChart = true; // PanelOnTopOfChart: Draw chart as background?
22-
input bool DoNotResetConditions = false; // DoNotResetConditions: Don't reset conditions on trigger?
23-
input bool DoNotResetActions = false; // DoNotResetActions: if true, actions won't be reset on trigger.
22+
input bool DoNotDisableConditions = false; // DoNotDisableConditions: Don't disable conditions on trigger?
23+
input bool DoNotDisableActions = false; // DoNotDisableActions: Don't disable actions on trigger?
24+
input bool DoNotDisableEquityTS = false; // DoNotDisableEquityTS: Don't disable equity TS on trigger?
25+
input bool AlertOnEquityTS = false; // AlertOnEquityTS: Alert when equity trailing stop triggers?
2426
input bool DisableFloatLossRisePerc = false; // Disable floating loss rises % condition.
2527
input bool DisableFloatLossFallPerc = true; // Disable floating loss falls % condition.
2628
input bool DisableFloatLossRiseCurr = false; // Disable floating loss rises currency units condition.
@@ -51,6 +53,7 @@ input int DelayOrderClose = 0; // DelayOrderClose: Delay in milliseconds.
5153
input bool UseTotalVolume = false; // UseTotalVolume: enable if trading with many small trades and partial position closing.
5254
input double AdditionalFunds = 0; // AdditionalFunds: Added to balance, equity, and free margin.
5355
input string Instruments = ""; // Instruments: Default list of trading instruments for order filtering.
56+
input bool CloseMostDistantFirst = false; // CloseMostDistantFirst: Close most distant trades first?
5457

5558
CAccountProtector ExtDialog;
5659

MQL4/Experts/Account Protector/Account Protector.mqh

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ private:
7676
double m_DPIScale;
7777
bool NoPanelMaximization; // Crutch variable to prevent panel maximization when Maximize() is called at the indicator's initialization.
7878
CArrayLong *PartiallyClosedOrders; // Stores order tickets that have been partially closed by Eliminate_Orders().
79-
double PositionsByProfit[][2]; // Stores position (order) ticket and its floating profit/loss. Gets filled and sorted when some condition is met and actions are about to get triggered.
79+
double PositionsByProfit[][2]; // Stores position (order) ticket and its floating profit/loss. When CloseMostDistantFirst == true, the profit is replaced with absolute distance. Gets filled and sorted when some condition is met and actions are about to get triggered.
8080
ENUM_CONDITIONS TriggeredCondition; // Checked for position array sorting (when optimal) and for partial position closure cancellation when UseTotalVolume is enabled.
8181
double ClosedVolume; // How much of the volume has already been closed - for partial closure when UseTotalVolume == true.
8282
double TotalVolume; // Store the total volume of filtered trades.
@@ -399,7 +399,7 @@ EVENT_MAP_END(CAppDialog)
399399
CAccountProtector::CAccountProtector()
400400
{
401401
m_FileName = "AP_" + IntegerToString(ChartID()) + ".txt";
402-
LogFile = -1;
402+
LogFile = INVALID_HANDLE;
403403
QuantityClosedMarketOrders = 0;
404404
QuantityDeletedPendingOrders = 0;
405405
IsANeedToContinueClosingOrders = false;
@@ -3669,12 +3669,12 @@ void CAccountProtector::Close_All_Positions()
36693669

36703670
// Check condition to know whether and how to sort PositionsByProfit.
36713671
// Switching sorting modes because the array is traversed backwards - from total - 1 to 0.
3672-
if ((TriggeredCondition == Floating_loss_rises_to_perecentage) || (TriggeredCondition == Floating_loss_rises_to_currency_units) || (TriggeredCondition == Floating_loss_rises_to_points)) ArraySort(PositionsByProfit, WHOLE_ARRAY, 0, MODE_DESCEND);
3672+
if (CloseMostDistantFirst) ArraySort(PositionsByProfit, WHOLE_ARRAY, 0, MODE_ASCEND); // Regardless of condition.
3673+
else if ((TriggeredCondition == Floating_loss_rises_to_perecentage) || (TriggeredCondition == Floating_loss_rises_to_currency_units) || (TriggeredCondition == Floating_loss_rises_to_points)) ArraySort(PositionsByProfit, WHOLE_ARRAY, 0, MODE_DESCEND);
36733674
else if ((TriggeredCondition == Floating_profit_rises_to_perecentage) || (TriggeredCondition == Floating_profit_rises_to_currency_units) || (TriggeredCondition == Floating_profit_rises_to_points)) ArraySort(PositionsByProfit, WHOLE_ARRAY, 0, MODE_ASCEND);
36743675
// Otherwise no sorting needed.
36753676

36763677
int total = ArrayRange(PositionsByProfit, 0); // We already have an array with all tickets.
3677-
36783678
// Closing market orders. Going backwards to delete an order from the array after closing it.
36793679
for (int i = total - 1; i >= 0; i--)
36803680
{
@@ -4088,14 +4088,21 @@ void CAccountProtector::EquityTrailing()
40884088
string AdditionalFunds_Asterisk = "";
40894089
if (AdditionalFunds != 0) AdditionalFunds_Asterisk = "*";
40904090
Logging("Account Protector: Equity stop-loss of " + DoubleToString(sets.doubleCurrentEquityStopLoss, 2) + " hit at " + DoubleToString(AE, 2) + AdditionalFunds_Asterisk + ". Closing all positions.");
4091+
if (AlertOnEquityTS) Alert("Account Protector: Equity stop-loss of " + DoubleToString(sets.doubleCurrentEquityStopLoss, 2) + " hit at " + DoubleToString(AE, 2) + AdditionalFunds_Asterisk + ". Closing all positions.");
40914092
Logging_Condition_Is_Met();
40924093
Close_All_Positions();
40934094

4094-
sets.boolEquityTrailingStop = false;
4095-
m_ChkEquityTrailingStop.Checked(false);
4096-
4097-
m_LblCurrentEquityStopLoss.Hide();
4098-
m_BtnResetEquityStopLoss.Hide();
4095+
if (!DoNotDisableEquityTS)
4096+
{
4097+
sets.boolEquityTrailingStop = false;
4098+
m_ChkEquityTrailingStop.Checked(false);
4099+
m_LblCurrentEquityStopLoss.Hide();
4100+
m_BtnResetEquityStopLoss.Hide();
4101+
}
4102+
else
4103+
{
4104+
sets.doubleCurrentEquityStopLoss = 0;
4105+
}
40994106

41004107
SaveSettingsOnDisk();
41014108
MoveAndResize();
@@ -4236,8 +4243,8 @@ void CAccountProtector::Logging_Condition_Is_Met()
42364243
double floating_profit = 0;
42374244
ClosedVolume = 0;
42384245
TotalVolume = 0;
4239-
if (LogFileName == "") return;
42404246
for (i = 0; i < OrdersTotal(); i++)
4247+
{
42414248
if (!OrderSelect(i, SELECT_BY_POS)) Logging("Account Protector: OrderSelect failed " + IntegerToString(GetLastError()));
42424249
else
42434250
{
@@ -4255,14 +4262,18 @@ void CAccountProtector::Logging_Condition_Is_Met()
42554262
floating_profit += order_floating_profit;
42564263
market++;
42574264
ArrayResize(PositionsByProfit, market, 100); // Reserve extra physical memory to increase the resizing speed.
4258-
PositionsByProfit[market - 1][0] = order_floating_profit;
4265+
if (!CloseMostDistantFirst) PositionsByProfit[market - 1][0] = order_floating_profit; // Normal profit.
4266+
else PositionsByProfit[market - 1][0] = MathAbs(OrderOpenPrice() - OrderClosePrice()) / SymbolInfoDouble(OrderSymbol(), SYMBOL_POINT);
42594267
PositionsByProfit[market - 1][1] = OrderTicket();
42604268
TotalVolume += OrderLots();
42614269
}
42624270
else if ((OrderType() == OP_BUYSTOP) || (OrderType() == OP_SELLSTOP) || (OrderType() == OP_BUYLIMIT) || (OrderType() == OP_SELLLIMIT)) pending++;
42634271
break; // Order already processed - no point to process this order with other magic numbers.
42644272
}
42654273
}
4274+
}
4275+
4276+
if (LogFileName == "") return;
42664277

42674278
string AdditionalFunds_Asterisk = "";
42684279
if (AdditionalFunds != 0) AdditionalFunds_Asterisk = "*";
@@ -4329,7 +4340,7 @@ void CAccountProtector::CheckOneCondition(T &SettingsEditValue, bool &SettingsCh
43294340
Logging("CONDITION IS MET: " + EventDescription);
43304341
TriggeredCondition = triggered_condition;
43314342
Trigger_Actions(EventDescription);
4332-
if (!DoNotResetConditions)
4343+
if (!DoNotDisableConditions)
43334344
{
43344345
SettingsCheckboxValue = false;
43354346
SettingsEditValue = 0;
@@ -4597,7 +4608,7 @@ void CAccountProtector::Trigger_Actions(string title)
45974608
// Close all positions.
45984609
if (sets.ClosePos)
45994610
{
4600-
if (!DoNotResetActions) sets.ClosePos = false;
4611+
if (!DoNotDisableActions) sets.ClosePos = false;
46014612
Logging("ACTION IS TAKEN: Close positions (" + DoubleToString(sets.doubleClosePercentage, 2) + "% of " + EnumToString(sets.CloseWhichPositions) + ").");
46024613
PartiallyClosedOrders.Clear();
46034614
Close_All_Positions();
@@ -4608,7 +4619,7 @@ void CAccountProtector::Trigger_Actions(string title)
46084619
// Delete all pending orders.
46094620
if (sets.DeletePend)
46104621
{
4611-
if (!DoNotResetActions) sets.DeletePend = false;
4622+
if (!DoNotDisableActions) sets.DeletePend = false;
46124623
Logging("ACTION IS TAKEN: Delete all pending orders.");
46134624
Delete_All_Pending_Orders();
46144625
sets.Triggered = true;
@@ -4618,7 +4629,7 @@ void CAccountProtector::Trigger_Actions(string title)
46184629
// Disable autotrading.
46194630
if (sets.DisAuto)
46204631
{
4621-
if (!DoNotResetActions) sets.DisAuto = false;
4632+
if (!DoNotDisableActions) sets.DisAuto = false;
46224633
Logging("ACTION IS TAKEN: Disable autotrading.");
46234634
// Toggle AutoTrading button. "2" in GetAncestor call is the "root window".
46244635
if (TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) SendMessageW(GetAncestor(WindowHandle(Symbol(), Period()), 2), WM_COMMAND, 33020, 0);
@@ -4630,7 +4641,7 @@ void CAccountProtector::Trigger_Actions(string title)
46304641
// Send emails.
46314642
if (sets.SendMails)
46324643
{
4633-
if (!DoNotResetActions) sets.SendMails = false;
4644+
if (!DoNotDisableActions) sets.SendMails = false;
46344645
Logging("ACTION IS TAKEN: Send email.");
46354646
PrepareSubjectBody(subject, body, title, TimeCurrent(), QuantityClosedMarketOrders, QuantityDeletedPendingOrders, WasAutoTradingDisabled, WasNotificationSent, false, WasPlatformClosed, WasAutoTradingEnabled, WasRecapturedSnapshots);
46364647
SendMailFunction(subject, body);
@@ -4641,7 +4652,7 @@ void CAccountProtector::Trigger_Actions(string title)
46414652
// Send push notifications.
46424653
if (sets.SendNotif)
46434654
{
4644-
if (!DoNotResetActions) sets.SendNotif = false;
4655+
if (!DoNotDisableActions) sets.SendNotif = false;
46454656
Logging("ACTION IS TAKEN: Send push notifications.");
46464657
PrepareSubjectBody(subject, body, title, TimeCurrent(), QuantityClosedMarketOrders, QuantityDeletedPendingOrders, WasAutoTradingDisabled, false, WasMailSent, WasPlatformClosed, WasAutoTradingEnabled, WasRecapturedSnapshots, true);
46474658
SendNotificationFunction(subject, body);
@@ -4652,15 +4663,15 @@ void CAccountProtector::Trigger_Actions(string title)
46524663
// Close platform.
46534664
if (sets.ClosePlatform)
46544665
{
4655-
if (!DoNotResetActions) sets.ClosePlatform = false;
4666+
if (!DoNotDisableActions) sets.ClosePlatform = false;
46564667
Logging("ACTION IS TAKEN: Close platform.");
46574668
TerminalClose(0);
46584669
}
46594670

46604671
// Enable autotrading.
46614672
if (sets.EnableAuto)
46624673
{
4663-
if (!DoNotResetActions) sets.EnableAuto = false;
4674+
if (!DoNotDisableActions) sets.EnableAuto = false;
46644675
Logging("ACTION IS TAKEN: Enable autotrading.");
46654676
// Toggle AutoTrading button. "2" in GetAncestor call is the "root window".
46664677
if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) SendMessageW(GetAncestor(WindowHandle(Symbol(), Period()), 2), WM_COMMAND, 33020, 0);
@@ -4671,7 +4682,7 @@ void CAccountProtector::Trigger_Actions(string title)
46714682
// Recapture snapshots.
46724683
if (sets.RecaptureSnapshots)
46734684
{
4674-
if (!DoNotResetActions) sets.RecaptureSnapshots = false;
4685+
if (!DoNotDisableActions) sets.RecaptureSnapshots = false;
46754686
Logging("ACTION IS TAKEN: Recapture snapshots.");
46764687
UpdateEquitySnapshot();
46774688
UpdateMarginSnapshot();
@@ -4688,14 +4699,14 @@ void CAccountProtector::Logging(string message)
46884699
{
46894700
if (StringLen(LogFileName) > 0)
46904701
{
4691-
string filename = LogFileName + ".log";
4692-
if (LogFile < 0) LogFile = FileOpen(filename, FILE_CSV | FILE_READ | FILE_WRITE, ' ');
4693-
if (LogFile < 1) Alert("Cannot open file for logging: ", filename, ".");
4702+
string filename = LogFileName;
4703+
if (LogFile == INVALID_HANDLE) LogFile = FileOpen(filename, FILE_CSV | FILE_READ | FILE_WRITE, ' ');
4704+
if (LogFile == INVALID_HANDLE) Alert("Cannot open file for logging: ", filename, ".");
46944705
else if (FileSeek(LogFile, 0, SEEK_END))
46954706
{
46964707
FileWrite(LogFile, TimeToString(TimeLocal(), TIME_DATE | TIME_MINUTES | TIME_SECONDS), " ", message);
46974708
FileClose(LogFile);
4698-
LogFile = -1;
4709+
LogFile = INVALID_HANDLE;
46994710
}
47004711
else Alert("Unexpected error accessing file: ", filename, ".");
47014712
}
-16.3 KB
Binary file not shown.
-252 KB
Binary file not shown.
-6.37 KB
Binary file not shown.

MQL5/Experts/Account Protector/WinUser32.mqh

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
//+------------------------------------------------------------------+
1+
//+------------------------------------------------------------------+
22
//| WinUser32.mqh |
3-
//| Copyright © 2013, MetaQuotes Software Corp. |
3+
//| Copyright © 2013, MetaQuotes Software Corp. |
44
//| http://www.mql4.com/ |
55
//+------------------------------------------------------------------+
6-
#property copyright "Copyright © 2013, MetaQuotes Software Corp."
6+
#property copyright "Copyright © 2013, MetaQuotes Software Corp."
77
#property link "http://www.mql4.com/"
88

99
#import "user32.dll"
@@ -367,10 +367,6 @@
367367
#define MB_ICONEXCLAMATION 0x00000030
368368
#define MB_ICONASTERISK 0x00000040
369369
#define MB_USERICON 0x00000080
370-
#define MB_ICONWARNING MB_ICONEXCLAMATION
371-
#define MB_ICONERROR MB_ICONHAND
372-
#define MB_ICONINFORMATION MB_ICONASTERISK
373-
#define MB_ICONSTOP MB_ICONHAND
374370
#define MB_DEFBUTTON1 0x00000000
375371
#define MB_DEFBUTTON2 0x00000100
376372
#define MB_DEFBUTTON3 0x00000200

0 commit comments

Comments
 (0)