Skip to content

Commit

Permalink
1.04
Browse files Browse the repository at this point in the history
1. Added an option to close trades in the asynchronous mode in MT5.
2. Added input parameters to filter trades by magic numbers.
3. Changed the messages about disabled auto-trading to specify whether it is disabled in the platform or in the EA.
4. Changed how the EA works when Always enforce schedule is off and the WaitForNoPositions input parameter is set to true. It will now proceed to toggle auto-trading with a schedule period if it finds that there are no more positions after the period starts.
5. Fixed a crashing error that could occur when unticking the Always enforce schedule checkbox with an empty schedule.
  • Loading branch information
EarnForex authored Jan 20, 2025
1 parent c5a07da commit dbde5d7
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 34 deletions.
59 changes: 57 additions & 2 deletions MQL4/Experts/AutoTrading Scheduler/AutoTrading Scheduler.mq4
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#property copyright "EarnForex.com"
#property link "https://www.earnforex.com/metatrader-expert-advisors/AutoTrading-Scheduler/"
#property version "1.03"
string Version = "1.03";
#property version "1.04"
string Version = "1.04";
#property strict

#property description "Creates a weekly schedule when AutoTrading is enabled."
Expand Down Expand Up @@ -34,10 +34,13 @@ input int Slippage = 2; // Slippage
input string ScheduleFile = ""; // ScheduleFile (optional)
input bool WaitForNoPositions = false; // Switch A/T off only when there are no open positions?
input bool WaitForNoOrders = false; // Switch A/T off only when there are no pending orders?
input string MagicNumbersFilter = ""; // Magic numbers filter
input bool IgnoreMagicNumbers = false; // Ignore trades with above-listed magic numbers

CScheduler Panel;

int DeinitializationReason = -1;
long MagicNumbers_array[];

//+------------------------------------------------------------------+
//| Initialization function |
Expand Down Expand Up @@ -77,6 +80,8 @@ int OnInit()
Panel.RefreshValues();
}

ProcessMagicNumbers();

EventSetTimer(1);

return INIT_SUCCEEDED;
Expand Down Expand Up @@ -162,4 +167,54 @@ void OnTimer()
Panel.CheckTimer();
ChartRedraw();
}

void ProcessMagicNumbers()
{
if (MagicNumbersFilter == "")
{
ArrayFree(MagicNumbers_array);
return;
}

string magic = MagicNumbersFilter;
int length = StringLen(magic);

// Only allowed characters are digits, commas, spaces, and semicolons. At least one digit should be present.
for (int i = 0; i < length; i++)
{
if (((magic[i] < '0') || (magic[i] > '9')) && (magic[i] != ' ') && (magic[i] != ',') && (magic[i] != ';'))
{
// Wrong character found.
int replaced_characters = StringReplace(magic, CharToString((uchar)magic[i]), "");
length -= replaced_characters;
i--;
}
}

if (magic == "") return;

// Split string with Magic numbers using all separators, getting an array with clean Magic numbers.
string result[];
int n = StringSplit(magic, StringGetCharacter(",", 0), result);
for (int i = 0; i < n; i++)
{
string second_result[];
int m = StringSplit(result[i], StringGetCharacter(";", 0), second_result);
for (int j = 0; j < m; j++)
{
string third_result[];
// Third result, at this point, holds all the magic numbers (strings) even if there was only one.
// The problem is that it will vanish on next cycle iteration.
int l = StringSplit(second_result[j], StringGetCharacter(" ", 0), third_result);

// Fill MagicNumbers_array.
for (int k = 0; k < l; k++)
{
if (third_result[k] == "") continue;
ArrayResize(MagicNumbers_array, ArraySize(MagicNumbers_array) + 1, 10);
MagicNumbers_array[ArraySize(MagicNumbers_array) - 1] = StringToInteger(third_result[k]);
}
}
}
}
//+------------------------------------------------------------------+
43 changes: 34 additions & 9 deletions MQL4/Experts/AutoTrading Scheduler/AutoTrading Scheduler.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ private:
void Notify(const int count, const bool enable_or_disable);
bool ExistsPosition();
bool ExistsOrder();
bool CheckFilterMagic(const long magic);

// Event handlers
void OnChangeChkClosePos();
Expand Down Expand Up @@ -562,7 +563,7 @@ void CScheduler::ProcessWeeklySchedule()
Schedule.Sort(0); // Sort schedule by time in ascending mode.

// Check if the previous week's last switch might be needed. It might be needed to know whether to toggle autotrading when we are inside the first period of the current week in non-enforced mode.
if (sets.Enforce == false) // Only in non-enforced mode.
if ((sets.Enforce == false) && (Schedule.Total() > 0)) // Only in non-enforced mode and if some schedule is given.
{
CTimeStamp* ts = Schedule.GetFirstNode();
datetime current_time;
Expand Down Expand Up @@ -1192,16 +1193,16 @@ void CScheduler::CheckTimer()
if (StartedToggling) return;
StartedToggling = true;
sets.LastToggleTime = time;
if (((WaitForNoPositions) && (ExistsPosition())) || ((WaitForNoOrders) && (ExistsOrder())))
{
StartedToggling = false;
return;
}
int n_closed = 0;
if (sets.ClosePos)
{
n_closed = Close_All_Trades();
}
if (((WaitForNoPositions) && (ExistsPosition())) || ((WaitForNoOrders) && (ExistsOrder())))
{
StartedToggling = false;
return;
}
if (IsANeedToContinueClosingTrades) Print("Not all trades have been closed! Disabling AutoTrading anyway.");
Toggle_AutoTrading();
Notify(n_closed, false);
Expand Down Expand Up @@ -1308,9 +1309,9 @@ int CScheduler::Close_All_Trades()

if ((!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) || (!TerminalInfoInteger(TERMINAL_CONNECTED)) || (!MQLInfoInteger(MQL_TRADE_ALLOWED)))
{
if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) Print("AutoTrading disabled!");
if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) Print("AutoTrading disabled (platform)!");
if (!TerminalInfoInteger(TERMINAL_CONNECTED)) Print("No connection!");
if (!MQLInfoInteger(MQL_TRADE_ALLOWED)) Print("Trade not allowed!");
if (!MQLInfoInteger(MQL_TRADE_ALLOWED)) Print("AutoTrading disabled (EA)!");
return 0;
}

Expand All @@ -1323,8 +1324,11 @@ int CScheduler::Close_All_Trades()
error = GetLastError();
Print("AutoTrading Scheduler: OrderSelect failed " + IntegerToString(error) + ".");
IsANeedToContinueClosingTrades = true;
continue;
}
else if (SymbolInfoInteger(OrderSymbol(), SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED)
if (CheckFilterMagic(OrderMagicNumber())) continue; // Skip if the magic number filter says to.

if (SymbolInfoInteger(OrderSymbol(), SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED)
{
Print("AutoTrading Scheduler: Trading disabled by broker for symbol " + OrderSymbol() + ".");
IsANeedToContinueClosingTrades = true;
Expand All @@ -1351,6 +1355,7 @@ int CScheduler::Close_All_Trades()
}
else
{
if (CheckFilterMagic(OrderMagicNumber())) continue; // Skip if the magic number filter says to.
AreAllTradesEliminated = false;
break;
}
Expand Down Expand Up @@ -1462,6 +1467,7 @@ bool CScheduler::ExistsPosition()
{
if (OrderSelect(i, SELECT_BY_POS))
{
if (CheckFilterMagic(OrderMagicNumber())) continue; // Skip if the magic number filter says to.
if ((OrderType() == OP_BUY) || (OrderType() == OP_SELL)) return true;
}
}
Expand All @@ -1476,6 +1482,7 @@ bool CScheduler::ExistsOrder()
{
if (OrderSelect(i, SELECT_BY_POS))
{
if (CheckFilterMagic(OrderMagicNumber())) continue; // Skip if the magic number filter says to.
if ((OrderType() != OP_BUY) && (OrderType() != OP_SELL)) return true;
}
}
Expand All @@ -1499,6 +1506,24 @@ int CScheduler::AddTimeStamp(CTimeStamp *new_node)
return Schedule.Total(); // Return the number of nodes after adding the new one to the list.
}

// Returns true if order should be filtered out based on its magic number and filter settings.
bool CScheduler::CheckFilterMagic(const long magic)
{
int total = ArraySize(MagicNumbers_array);
if (total < 1) return false; // Empty array - don't filter.

for (int i = 0; i < total; i++)
{
// Skip order if its magic number is in the array, and "Ignore" option is turned on.
if ((magic == MagicNumbers_array[i]) && (IgnoreMagicNumbers)) return true;
// Do not skip order if its magic number is in the array, and "Ignore" option is turned off.
if ((magic == MagicNumbers_array[i]) && (!IgnoreMagicNumbers)) return false;
}

if (IgnoreMagicNumbers) return false; // If not found in the array and should ignore listed magic numbers, then default ruling is - don't filter out this order.
else return true;
}

// Returns true if weekday is actually a date for a long-term schedule.
bool IsWeekdayADate(const string wd)
{
Expand Down
60 changes: 58 additions & 2 deletions MQL5/Experts/AutoTrading Scheduler/AutoTrading Scheduler.mq5
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#property copyright "EarnForex.com"
#property link "https://www.earnforex.com/metatrader-expert-advisors/AutoTrading-Scheduler/"
#property version "1.03"
string Version = "1.03";
#property version "1.04"
string Version = "1.04";
#property strict

#property description "Creates a weekly schedule when AutoTrading is enabled."
Expand Down Expand Up @@ -35,10 +35,14 @@ input int Slippage = 2; // Slippage
input string ScheduleFile = ""; // ScheduleFile (optional)
input bool WaitForNoPositions = false; // Switch A/T off only when there are no open positions?
input bool WaitForNoOrders = false; // Switch A/T off only when there are no pending orders?
input string MagicNumbersFilter = ""; // Magic numbers filter
input bool IgnoreMagicNumbers = false; // Ignore trades with above-listed magic numbers
input bool AsyncMode = false; // AsyncMode: If true, trades are closed in async mode

CScheduler Panel;

int DeinitializationReason = -1;
long MagicNumbers_array[];

//+------------------------------------------------------------------+
//| Initialization function |
Expand Down Expand Up @@ -78,6 +82,8 @@ int OnInit()
Panel.RefreshValues();
}

ProcessMagicNumbers();

EventSetTimer(1);

return INIT_SUCCEEDED;
Expand Down Expand Up @@ -164,4 +170,54 @@ void OnTimer()
Panel.CheckTimer();
ChartRedraw();
}

void ProcessMagicNumbers()
{
if (MagicNumbersFilter == "")
{
ArrayFree(MagicNumbers_array);
return;
}

string magic = MagicNumbersFilter;
int length = StringLen(magic);

// Only allowed characters are digits, commas, spaces, and semicolons. At least one digit should be present.
for (int i = 0; i < length; i++)
{
if (((magic[i] < '0') || (magic[i] > '9')) && (magic[i] != ' ') && (magic[i] != ',') && (magic[i] != ';'))
{
// Wrong character found.
int replaced_characters = StringReplace(magic, CharToString((uchar)magic[i]), "");
length -= replaced_characters;
i--;
}
}

if (magic == "") return;

// Split string with Magic numbers using all separators, getting an array with clean Magic numbers.
string result[];
int n = StringSplit(magic, StringGetCharacter(",", 0), result);
for (int i = 0; i < n; i++)
{
string second_result[];
int m = StringSplit(result[i], StringGetCharacter(";", 0), second_result);
for (int j = 0; j < m; j++)
{
string third_result[];
// Third result, at this point, holds all the magic numbers (strings) even if there was only one.
// The problem is that it will vanish on next cycle iteration.
int l = StringSplit(second_result[j], StringGetCharacter(" ", 0), third_result);

// Fill MagicNumbers_array.
for (int k = 0; k < l; k++)
{
if (third_result[k] == "") continue;
ArrayResize(MagicNumbers_array, ArraySize(MagicNumbers_array) + 1, 10);
MagicNumbers_array[ArraySize(MagicNumbers_array) - 1] = StringToInteger(third_result[k]);
}
}
}
}
//+------------------------------------------------------------------+
Loading

0 comments on commit dbde5d7

Please sign in to comment.