Problem Description
Solution
To achieve automatic cancellation of pending orders at a specific time every day, a Script is technically insufficient because a script runs once and terminates. Instead, you need an Expert Advisor (EA). An EA runs continuously on the chart and can monitor the time to execute the cancellation logic daily.
Below is the complete MQL4 code for an Expert Advisor that performs this task.
MQL4 Expert Advisor: Daily Pending Order Cleaner
//+------------------------------------------------------------------+
//| DailyPendingOrderCleaner.mq4 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input int InpCancelHour = 23; // Hour to cancel orders (Server Time)
input int InpCancelMinute = 55; // Minute to cancel orders
input bool InpOnlyCurrentSymbol = false; // If true, only cancels orders for the chart symbol
//--- Global Variables
datetime LastCancellationTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Basic validation of inputs
if(InpCancelHour < 0 || InpCancelHour > 23)
{
Print("Error: Invalid Hour. Please set between 0 and 23.");
return(INIT_PARAMETERS_INCORRECT);
}
if(InpCancelMinute < 0 || InpCancelMinute > 59)
{
Print("Error: Invalid Minute. Please set between 0 and 59.");
return(INIT_PARAMETERS_INCORRECT);
}
Print("Daily Pending Order Cleaner Started. Target Time: ", InpCancelHour, ":", InpCancelMinute);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Get current server time
datetime currentTime = TimeCurrent();
// Check if the current time matches or exceeds the target time
if(TimeHour(currentTime) == InpCancelHour && TimeMinute(currentTime) >= InpCancelMinute)
{
// Check if we have already run the cancellation today
// We compare the Day of Year of the last run vs current time
if(TimeDayOfYear(currentTime) != TimeDayOfYear(LastCancellationTime))
{
Print("Target time reached. Starting cancellation of pending orders...");
CancelAllPendingOrders();
// Update the last run time to prevent repetition on the next tick
LastCancellationTime = currentTime;
}
}
}
//+------------------------------------------------------------------+
//| Function to cancel all pending orders |
//+------------------------------------------------------------------+
void CancelAllPendingOrders()
{
int total = OrdersTotal();
// Loop backwards when deleting orders to avoid index shifting issues
for(int i = total - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// Filter by symbol if required
if(InpOnlyCurrentSymbol && OrderSymbol() != _Symbol)
continue;
// Check if the order is a pending order
// OP_BUYLIMIT(2), OP_SELLLIMIT(3), OP_BUYSTOP(4), OP_SELLSTOP(5)
if(OrderType() > OP_SELL)
{
// Attempt to delete the order
bool res = OrderDelete(OrderTicket(), clrRed);
if(res)
{
Print("Successfully deleted pending order #", OrderTicket(), " ", OrderSymbol());
}
else
{
Print("Failed to delete order #", OrderTicket(), ". Error: ", GetLastError());
}
}
}
}
}
//+------------------------------------------------------------------+
How It Works
- Time Monitoring: Inside the
OnTick()function, the EA checks theTimeCurrent()(Broker Server Time) on every price tick. - Trigger Condition: It compares the current server hour and minute with your inputs (
InpCancelHourandInpCancelMinute). - Execution Control: It uses the variable
LastCancellationTimeto ensure the code runs exactly once per day. Even if multiple ticks arrive during the specified minute, the logic prevents it from trying to delete orders more than once. - Order Loop: The
CancelAllPendingOrdersfunction loops through the trade pool backwards (from last to first). This is critical in MQL4; if you loop forwards while deleting, the index of remaining orders shifts, causing the loop to skip orders. - Order Type Check: It checks
OrderType() > OP_SELL. In MQL4,OP_BUYis 0 andOP_SELLis 1. Any type greater than 1 (Buy Limit, Sell Limit, Buy Stop, Sell Stop) is considered a pending order.
Installation and Usage
- Open MetaTrader 4.
- Press F4 to open the MetaEditor.
- Click New -> Expert Advisor (template) -> Next.
- Name it
DailyPendingOrderCleanerand click Next/Finish. - Paste the code provided above into the editor, replacing everything currently there.
- Press F7 or click Compile. Ensure there are no errors in the "Errors" tab at the bottom.
- Return to the main MT4 terminal.
- Find
DailyPendingOrderCleanerin the Navigator window under Expert Advisors. - Drag it onto one chart (it does not need to be on every chart unless you set
InpOnlyCurrentSymbolto true). - In the settings window, set your desired
InpCancelHourandInpCancelMinute. Note: This is Broker Server Time, which you can see in the "Market Watch" window. - Ensure the AutoTrading button at the top of MT4 is green (Enabled).
Q&A
Q: Why use an Expert Advisor instead of a Script?
A: A Script executes its code once and then removes itself from the chart. To run "automatically at the end of each day," the program must remain active on the chart to monitor the time continuously. Only an Expert Advisor can do this.
Q: Will this close my active (open) trades?
A: No. The code specifically checks if(OrderType() > OP_SELL). Active market orders are type 0 (Buy) or 1 (Sell). Pending orders are types 2 through 5. This logic ensures only pending orders are deleted.
Q: What happens if I restart my computer?
A: The variable LastCancellationTime resets to 0. If you restart the computer after the designated time has passed for the day, the EA will see that the time condition is met and the "Day of Year" check differs, so it will run the cancellation immediately upon restart. If you restart before the time, it will wait for the time as usual.
Q: Does this work for all symbols?
A: Yes, by default. If you want it to only work for the specific chart you attach it to, change the input InpOnlyCurrentSymbol to true.