How To Write a Close All Script in MQL4?
If you're just wanting to get a ready-made Metatrader script that closes all trades per chart or for the whole trading account, then follow the links and download the MQ4 script file of your choice:There are many ways to write a script that closes all orders in MQL4, just as there are many ways to accomplish virtually anything via code. However, if you've taken the time to look at the code for any of the various Close All routines that can be found on the various sites on the WWW, you will notice some striking similarities. Before you can close all orders, you must first learn how to iterate through all the open orders and learn something about how MT4 (Metatrader 4) handles orders.
MQL4 has a simple way to iterate through all open orders for a given account by using two simple functions. The
OrdersTotal()
function help file states that it returns, "market and pending orders count." By orders, the creators of MT4 really mean orders such as stop orders, or trades such as buy or sell trades. The other little tidbit that the MT4 help
file leaves out is that all orders and trades for the current account
will be checked with this function. A simple loop to iterate through all
orders and trades might look like the following:for (int i = OrdersTotal(); i >=0; i--) {
// Do something here
}
In the code above the (int)eger i is declared (
int i = OrdersTotal();
)
or in other words i is set to the total open order count.. The line
termination character in MQL4 is the semicolon. The loop continues while
i >= 0
or in other words until no orders are left. When
OrdersTotal() returns
-1 there are no orders open. (This is an undocumented return value that
you may want to make note of.) The integer i increments down by 1 each
time (i--
). This is the basics of a "for" loop. The
variable names can change (i was used in this example) but "for" loops
follow this basic pattern every time. Curly brackets start and end a
block of code, in this case a for loop.
Next you need to select the orders by using the
OrderSelect()
function. This can be done as follows:OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
In the MQL4 code
above, orders are selected one at a time, using i as the reference
number. Orders are selected by position. The two ways to select an order
are
SELECT_BY_POS
which will give the index of total open orders, starting at 1, and SELECT_BY_TICKET
which will return the actual order ticket number. When SELECT_BY_POS
is used, a optional pool index may be entered with the default being MODE_TRADES
which returns order index numbers of open orders and trades, while MODE_HISTORY
will return the index numbers of closed and cancelled orders.
If you wish to close all open orders, you should use
MODE_TRADES
, which will select trades by index number so SELECT_BY_POS
is used for this example. Putting the code together, you have the following:for (int i = OrdersTotal(); i >=0; i--) {
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
}
MQL4 contains a simple way to differentiate between different
types of orders. The order types that are of most concern when
attempting to close all open trades are open buy and sell orders,
represented by the
OP_BUY
and OP_SELL
constants used in the OrderType()
function. The OrderType()
function
simply returns the type of order that is currently selected. Returning
back to the code, it is possible to create a Close All routine that only
closes buy (or long) orders as follows:
for (int i = OrdersTotal(); i >=0; i--) {
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
if (OrderType() == OP_BUY) {
bool closed = OrderClose( OrderTicket(), OrderLots(), Bid, 5, White);
}
}
In the MQL4 code above "closed" is a boolean (true/false) variable that is defined to accept the return value from the
OrderClose()
function. By selecting the orders with the OrderSelect()
function, it is possible to make use of several other built-in MQL4 functions that make the job of closing an order much simpler.
The
OrderClose()
function defined in the code above takes the following variables:
ticket -
Refers to the order index number selected, in this case it will be i,
but to keep the code generalizable it is best to use the
OrderTicket()
function.
lots - May be referenced by the
OrderLots()
function which returns the number of lots open for a given ticket number.
Bid -
Refers to the current symbol's bid price. Unfortunately in the code
sample provided, does not distinguish between the orders that refer to
the current symbol and the orders that belong to other symbols so using
the Bid price of the current symbol will often lead to errors due to
prices not matching.
5 - Refers to the number of pips (or pippettes for 3/5 digit symbols) of slippage you are willing to allow.
White - refers to a color that will be used to show the exit on the chart. Any valid color constant will work here.
CLR_NONE
may be used to instruct Metatrader not to draw a close object on the screen.
To make sure the code works for a single symbol you need to add an additional condition to the code as follows:
for (int i = OrdersTotal(); i >=0; i--) {
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
if (OrderType() == OP_BUY && Symbol() == OrderSymbol()) {
bool closed = OrderClose( OrderTicket(), OrderLots(), Bid, 5, White);
}
}
By specifying that
Symbol() == OrderSymbol()
you
are requiring the current chart's symbol be equal to the symbol with
the currently selected open order. Open orders of other symbols will not
be closed in this manner. The code can be made to close both buy and
sell orders as follows:int Slippage = 5;
for (int i = OrdersTotal(); i >=0; i--) {
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
if (OrderType() == OP_BUY && Symbol() == OrderSymbol()) {
bool closed = OrderClose( OrderTicket(), OrderLots(), Bid, Slippage, White);
}
if (OrderType() == OP_SELL && Symbol() == OrderSymbol()) {
bool closed = OrderClose( OrderTicket(), OrderLots(), Ask, Slippage, White);
}
}
Additionally,
a variable has been created for Slippage for reuse purposes. Note that
the Ask price is used as the exiting price for sell orders as open sell
orders must be bought back at the ask price in order to close. Likewise,
open buy orders must be sold back at the bid price to close.
MT4 has some gotchas with regards to order placement that need to be taken into account. Often times the above code will cause MT4 to
kick out errors when the program isn't expecting an order to be
submitted due to the trade context being busy, or due to stale prices.
Magic Numbers
Note the parameter "
MT4 contains a simple method for referencing the prices and data of different symbols in MQL4. This function is the
You may not be familiar with the concept of a magic number as it is used in MT4.
Magic Numbers are actually a very important concept to understand
because Magic Numbers are found in many different types of MQL4 code,
and can be integrated into a Close All routine simply. A Magic Number is
a number used by an MT4 indicator, MT4 expert advisor or MT4 script to differentiate that MT4 expert advisor, MT4 indicator or MT4 script from one another being run on the same account. Perhaps the most useful way to think about a Magic Number is in terms of an MT4 expert advisor. If you are running multiple MT4 expert advisors or
systems on a single account. If you want to keep track of the orders
from a single strategy and differentiate them from another strategy
running on the same account for the purposes of opening and closing
orders (trades), and perhaps even on the same symbol, you could use a
Magic Number. The
OrderSend()
function is defined as follows:int
OrderSend
(
string
symbol,
int
cmd,
double
volume,
double
price,
int
slippage,
double
stoploss,
double
takeprofit,
string
comment=NULL,
int
magic=0,
datetime
expiration=0,
color
arrow_color=CLR_NONE)
int magic = 0
"
which refers to a Magic Number that may be entered when an order is
created. This same Magic Number may be referenced when closing an order.
If you are running two different MT4 expert advisors on a single symbol, you could specify two different Magic Numbers in the OrderSend()
function of each MT4 expert advisor, to ensure that each could handle its close order routine separately. Without using a unique Magic Number for each MT4 expert advisor, either Expert could close orders opened by a different MT4 expert advisor. This is usually not the intent of an MT4 expert advisor though in some cases it is desirable to close orders created by a different MT4 expert advisor.
The
close all routine can be ammended to specify that only a given Magic
Number is closed out with this routine. This can be accomplished as
follows:
int Slippage = 5;
int MagicNumber = 321;
for (int i = OrdersTotal(); i >=0; i--) {
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
if (OrderType() == OP_BUY && Symbol() == OrderSymbol()
&& MagicNumber == OrderMagicNumber()) {
bool closed = OrderClose( OrderTicket(), OrderLots(), Bid, Slippage, White);
}
if (OrderType() == OP_SELL && Symbol() == OrderSymbol()
&& MagicNumber == OrderMagicNumber()
) {
bool closed = OrderClose( OrderTicket(), OrderLots(), Ask, Slippage, White);
}
}
Finally,
MQL4 code can be added that ensures that the trade context is ready,
and that the most recent prices are available. The MQL4 code has
been placed in a function called CloseThis, because the routine just
closes a single symbol's trades with the given Magic Number.
void CloseThis(
int Slippage, int MagicNumber) {
for (int i = OrdersTotal(); i >=0; i--) {
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
while(IsTradeContextBusy()) Sleep(100);
RefreshRates();
if (OrderType() == OP_BUY && Symbol() == OrderSymbol()
&& MagicNumber == OrderMagicNumber()) {
bool closed = OrderClose( OrderTicket(), OrderLots(), Bid, Slippage, White);
}
if (OrderType() == OP_SELL && Symbol() == OrderSymbol()
&& MagicNumber == OrderMagicNumber()
) {
bool closed = OrderClose( OrderTicket(), OrderLots(), Ask, Slippage, White);
}
}
}
The
IsTradeContextBusy()
function returns a boolean TRUE just as one would expect when some
other EA is tying up the trade thread, and false when trading is
available. Alternatively the function IsTradeAllowed()
may
be used as this function not only checks that the Trade context isn't
busy, but also checks that trading is allowed for the expert.
The
Sleep()
function simply waits a given number of milliseconds before resuming with the next line of MQL4 code.
The
RefreshRates()
function forces the current prices to be updated. If you are sending orders and getting errors 135 (ERR_PRICE_CHANGED
) or 138 (ERR_REQUOTE
) you should use the RefreshRates
()
function to force new prices to update to your trade variables. It is a
good practice to attempt to refresh rates during a close loop as
closing orders may take time, during which time prices may shift causing
errors.
The CloseThis() function may be called from any other MT4 function simply as follows for slippage of 7 pips and a magic number of zero:
CloseThis(7,0);
MT4 contains a simple method for referencing the prices and data of different symbols in MQL4. This function is the
MarketInfo()
function. The MarketInfo()
function has many uses, all of which will not be explored in this article. MarketInfo()
can be used to retrieve the bid and ask prices of the currently selected symbol as MT4 iterates
through a list of orders and attempts to close them. This is a useful
feature that is needed to make a CloseAll routine work correctly.
One additional gotcha with regards to MT4 is that sometimes rounding errors can cause problems that prevent orders from closing. The
OrderClose()
function is very particular about the type of data it receives,
particularly the prices used, including the number of decimals in those
prices. When referencing prices from a symbol other than the current
symbol, it is good practice to round the symbol's price to the correct
number of decimal places. A symbol's decimal places or Digits can be
retrieved via the MarketInfo()
function from the currently selected order symbol as follows:MarketInfo(OrderSymbol(), MODE_BID);
MarketInfo(OrderSymbol(), MODE_ASK);
To finish off these lines of MQL4 code, the
NormalizeDouble()
function can be used to round a price to a specified number of Digits, and in the case of MarketInfo(OrderSymbol(), MODE_DIGITS);
to retrieve the digits from the selected order's settings. The code to
close all orders for all symbols can be generalized as follows:void CloseAll(
int Slippage, int MagicNumber
) {
bool closed;
for (int i = OrdersTotal(); i >=0; i--) {
OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
while(IsTradeContextBusy()) Sleep(100);
RefreshRates();
if (OrderType() == OP_BUY && MagicNumber == OrderMagicNumber()) {
closed = OrderClose(OrderTicket(),OrderLots(),
NormalizeDouble(MarketInfo(OrderSymbol(),
MODE_BID),MarketInfo(OrderSymbol(),MODE_DIGITS)),Slippage,White);
}
if (OrderType() == OP_SELL && MagicNumber == OrderMagicNumber()) {
closed = OrderClose(OrderTicket(),OrderLots(),
NormalizeDouble(MarketInfo(OrderSymbol(),
MODE_ASK),MarketInfo(OrderSymbol(),MODE_DIGITS)),Slippage,White);
}
}
}
Just
as with the CloseThis routine, the CloseAll routine may be called as
follows using 7 pips of slippage and a Magic Number of zero:
CloseAll(7, 0);
Using
the MQL4 code contained in this sample, you should now be able to write
your own CloseAll or CloseThis routine. While not all advanced topics
have been covered in this short tutorial, by making use of the MT4 help files and the other MQL4 code samples on this site and others, you should be able to build or adapt your very own Metatrader order closing routine!
If you would like to download the code for this tutorial, you may find the links here:
Close All Orders This Symbol Only MQL4 Script for Metatrader Close All Trades All Symbols MQL4 Script for Metatrader 4