Saturday, 9 February 2013

Two Things Every Forex Trader Ought To Know About MT4 Scripts


Some things you should know about Metatrader Scripts 
Running a MT4 script is easy. Simply double click the Metatrader script or drop it on the chart of your choice.

Confirmation (or lack of it) 
property show_confirm
Unless a particular property called show_confirm is set within the MT4 Script's code, after double clicking your script within the MT4 Navigator pane, the script will run immediately. If you want to run your MT4 script immediately, you don't need to do anything special. 

If you wish to add a confirmation box (example show_confirm picture above) to your MT4 script when it runs so that you don't accidentally undo the work of several months in a single double click, copy the code below into the top section of your MT4 script.  To comment out the line put two double forward slashes // in front of the # sign. The property for adding a confirmation box after double clicking a MT4 script is listed below:
#property show_confirm  // comment out this line to eliminate the confirmation box

Editing Inputs 
property show_inputs
By default in a MT4 script, there are no editable inputs from the Metatrader terminal. There is an exception that can be added to a MT4 script if you would like to have a box pop up that includes the inputs after you double click before the script runs. It is the show_inputs property and use of this property disables the show_confirm property. You can include this property as follows:
#property show_inputs // comment out this line to eliminate showing inputs

Unlike an MT4 indicator or expert advisor where you can edit the inputs by right clicking on your forex chart, with MT4 scripts, you may need to get your hands dirty and edit the code if you aren't using the show_inputs property in your MT4 script.

If you wish to edit inputs for a particular script (if it has inputs) then you will need to right click on the script from the Navigator window and select Modify.Once the MetaEditor opens up you will see something like the following snippet. The thing to keep in mind is that the editable inputs are placed BEFORE the int start() function. In the code below, editable inputs include Lots, stoploss, takeprofit, Slippage and MagicNumber.
#property show_confirm  // comment out this line to eliminate the confirmation box
// #property show_inputs // comment out this line to eliminate showing inputs
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
// edit these values as desired below:
extern double Lots =             0.01;
extern int stoploss =            20;
extern int takeprofit =          30;
extern int Slippage =            7;
extern int MagicNumber =         0;

int start()
  {
//----
Tip:
To make a confirmation box pop up every time you double click a MT4 script or drop a script on a chart to run, simply comment out the line #property show_confirm and uncomment the line // #property show_inputs and you will be able to see and edit the inputs from within Metatrader! Shown below:
// #property show_confirm  // comment out this line to eliminate the MT4 confirmation box
#property show_inputs // comment out this line to eliminate showing inputs


Variable Type
One final thing to keep in mind is the variable type. Lots is declared as double: 
extern double Lots =             0.01;
   

As a result, you will need to make sure to enter your numbers as a double type. Best practice states that the double type requires a decimal place in MQL4. If you wanted to trade a 1 lot, you would write it as 1.0 and not as simply 1 within the MQL4 code. The int type can't handle decimals, so make sure to leave those out when declaring Slippage, for instance.

If you enjoyed this MT4 help tutorial, you might also enjoy reading a MQL4 Code Tutorial for Metatrader. Every trader needs to learn at least some MQL4 in order to perform the simple operations of modifying code inputs, commenting out a line of code and understanding how to read the code to know if it is executing your MT4 IndicatorsMetatrader expert advisors and MT4 scripts properly.

How To Write a Close All Script in MQL4? (4 of 4)


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

How To Write a Close All Script in MQL4? (3 of 4)

Magic Numbers
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)
Note the parameter "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); 

Turn the CloseThis() routine into a CloseAll() routine by eliminating the symbol restriction and by using the MarketInfo() function to retrieve bid and ask prices from other symbols.

How To Write a Close All Script in MQL4? (2 of 4)

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.

How To Write a Close All Script in MQL4? (1 of 4)

How To Write a Close All Script in MQL4? (1 of 4)

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);
}

You will learn how to close an order using OrderClose(), and how to use the OrderType() function to differentiate between buy and sell orders in MQL4.

How to delete all objects from a MT4 chart?

If you'd like to skip right to a downloadable MT4 script that will clean your MT4 (Metatrader 4) chart, you can find Clean Up All Objects An MQL4 Script Using ObjectDelete here.

The three main functions that are needed to find and delete all objects from a MT4 chart are ObjectsTotal(), ObjectDelete() as and ObjectName(). The MQL4 help file offers the following with regards to ObjectsTotal():

int ObjectsTotal( int type=EMPTY) 
Returns total amount of objects of the specified type in the chart. 

The important thing to understand is that objects have a reference number, but they must be removed by name. ObjectsTotal() will give the total number of objects on a chart. The key is to loop through each object and delete it by referencing it by name. The ObjectName() function returns the name of each object as the code loops through each object but requires a reference number (provided by ObjectsTotal()). The ObjectDelete() function needs the ObjectName() in order to delete an object. The code for deletion of the zeroth object is as follows:
ObjectDelete(ObjectName(0));

A simple loop can be created to go through each object, starting at the highest down to zero, progressing in reverse order. This can be written as:
for(int i = ObjectsTotal() -1; i >=0; i--) {

}

Putting the single object deletion together with the for loop (similar to a while loop) looks like the following:
for(int i = ObjectsTotal() -1; i >=0; i--) {
   ObjectDelete(ObjectName(i));
}

Add in a line to eliminate the lingering Comment at the top left of a chart and you are done!
Comment("");

If you'd like to download the code in this sample as an MQ4 file for Metatrader, then you're in luck.

How To Create a Simple Forex MT4 Expert Advisor Template Using the RSI That Trades Once Per Bar

This is a two-part  MQL4 code tutorial discussing how to create a simple Metatrader expert advisor using the RSI that trades only once per bar. At the end of part 2, a fully functioning RSI EA template may be downloaded.   Additionally, the code will reference a different time frame chart for the RSI. So if you're interested in learning how to reference a different time frame from within an EA, this tutorial should prove informative. This MQL4 code tutorial is the sequal to How to place only one trade per bar on a forex MT4 expert advisor. This article will expand on that simple concept and present code that may be used as a template in many different expert advisor applications and with many different types of indicators, including the RSI.

As was discussed in the previous MQL4 tutorial, the key to trading only once per bar is to encapsulate the trading logic within a conditional block that uses a module level variable to keep track of the bar number using the Bars variable. MQL4 has many built-in indicator functions that may be used in system building. 

Using the RSI in MQL4

The iBarShift function returns the bar shift for a given time. In the code below, the current bar Time[0] is referenced. If this code is used on a chart other than the 1 hour chart, the bar sequence could be unpredictable. IBarShift allows for determination of the correct bar, or the closest bar if the last term is set to false. The return value may be entered wherever a shift parameter is required, such as in the iRSI  function.

The RSI or Relative Strength Index may be referenced in the MQL4 code and is declared as follows:
double iRSI(string symbol, int timeframe, int period, int applied_price, int shift)

The first term is symbol and if it refers to the current symbol may be entered as NULL or Symbol(), or even successfully as 0 (though best practice suggests you should use NULL instead of 0) all with equivalent meaning. 

The second term is timeframe and may be entered as 0 for the currently selected chart's timeframe, or as one of the pre-built timeframe enumeration values (see your help file under "iRSI" for more details). 

In this example the PERIOD_H1 variable is used for referencing data from a 1 hour chart. 

The third term period refers to the length of the RSI where the variable RSILength is used (below). 

applied_price refers to bar prices like close (PRICE_CLOSE) or high (PRICE_HIGH).

shift refers to how many bars to shift the RSI for the calculation. For instance, to calculate the RSI of 5 bars ago you would use 5 in the 5th term. For this example no shift is used so 0 is used (below).

After creating an external input for RSILength and two inputs for Buy and Sell thresholds for the RSI value at 70 and 30 respectively, the code looks like this:
extern int RSILength =         14;
extern int BuyThreshold =      70;
extern int SellThreshold =     30;
extern double Lots =           0.01;
extern int Slippage =          7;
extern string comment =        "RSI_Template";
extern int MagicNumber =       0;
/////////////////////////////////////
int ThisBarTrade        =      0;
int Position            =      0;
int start() {
    double RSI = 0.0;
    if ( ThisBarTrade != Bars) {
        int iShift = iBarShift(Symbol() PERIOD_H1, Time[0], false);
        RSI = iRSI(NULL, PERIOD_H1, RSILength, PRICE_CLOSE, iShift);

        // Buy Condition
        if ( RSI >= BuyThreshold ) {
            ThisBarTrade = Bars;
            // Buy code goes here
        }
        // Sell Condition
        if ( RSI <= SellThreshold) {
            ThisBarTrade = Bars;
            // Sell code goes here
        }
    }
}

By setting the buy threshold to 70, buy orders are created when the RSI crosses above 70. When the RSI crosses below 30 the sell condition is triggered and a sell trade is placed.
The RSI system in this MQL4 tutorial will trade as a stop and reversal (SAR) system, going from long to short and short to long with only single positions long or short being opened. The buy code must determine the currently open position. If the position is already long, nothing is done. If the position is short, the short trade must be exited first. Then when the position is flat, a long trade may be initiated. 

The opposite will be done when the sell condition is met. A routine called CalcPosition (shown below) loops through all open trades and adds up the current position into the Position module level variable. Long trades (OP_BUY) are added up as positive numbers Position += 1; while short trades (OP_SELL) are added up as negative numbers Position -=1;.
void CalcPosition() {
    Position = 0;
    for (int i = 0; i < OrdersTotal(); i++) {
        OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if( OrderSymbol() == Symbol() ) {
            if (OrderType() == OP_BUY) Position += 1;
            if (OrderType() == OP_SELL) Position -=1;
        }
    }
}

Open trades need to be closed for buy and sell trades respectively. This can be done by creating two routines. A close routine called CloseSingleBuy, and a second routine called CloseSingleSell to close out the open Buy or Sell orders respectively. As the code is essentially the same for both, for brevity only the CloseSingleBuy code will be shown below.
bool CloseSingleBuy() {
    bool closed;
    for (int i = 0; i < OrdersTotal(); i++) {
        OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        if(Symbol() == OrderSymbol()) {
            while(IsTradeAllowed() == false)  Sleep(100);
            RefreshRates();
            if ( OrderType() == OP_BUY) {
                closed = OrderClose( OrderTicket(), OrderLots(), Bid, Slippage, White);
                Print ("Attempting to CloseSingleBuy order # " + i + " " + Bid);
                if (closed == -1) {
                    return(false);
                } else {
                    return(true);
                }
            }
        }
    }
}

The CloseSingleBuy routine is a typical looping block of code that works through all open orders and trades (OrdersTotal), matching up by Symbol() = OrderSymbol() and using the OrderClose() function to close a single open trade.

In the next part, all the pieces are put together into a single simple RSI EA template that you may download and use.

How to Place Only One Trade Per Bar on a Forex MT4 Expert Advisor?


A common desire when creating a forex MT4 expert advisor system or converting one to an MT4 expert advisor is to limit the ability to trade only once per bar. This is easily accomplished by the use of a module level variable within the Metatrader MQL4 language. 

By default, Metatrader 4 handles all data coming into the workstation tick by tick. A tick is a price change on the forex chart where your expert advisor is running. As each tick is processed, indicators and expert advisors are processed. 

Note that it is possible to set up an expert advisor to run in an endless loop, to force it to calculate at a given time, like every 1 second. Endless loops are outside the scope of this tutorial and in my view are generally bad coding convention, but there are some legitamate uses for an endless loop such as for an indicator that tracks a basket of currencies, like Basket_Stats.mq4 or for placing, then modifying an order within a Metatrader script as is done in the Buy w/ SL & TP and Sell w/ SL & TP scripts. Because I tend to avoid endless loops unless special circumstances warrant, Basket_Stats.mq4 doesn't use endless loops. Whichever method you use (event driven or endless loop), module level variables can help in preventing code reentry into a trade block.

The simplest way to prevent an MT4 expert advisor from executing your MQL4 code more than once per bar is to declare a module level variable. Module level variables are declared at the top, just under the external declarations, like so:

extern int Time1Start =       200;
extern int Time1Stop =        430;
////////////////////////////////////
int ThisBarTrade           =  0;
 
In the above example the integer variable ThisBarTrade is going to be used to prevent multiple trades on a single bar. The variable is declared as an integer type because it will have the Bars predefined variable assigned to it. The Bars predefined variable is declared as follows: (from the MT4 help file in the MetaEditor).

int Bars
Number of bars in the current chart.

The idea is to encapsulate your trading logic within a block of code that evaluates whether the current bar is a new bar or has already been evaluated for trade or conditional possibilites. This can be accomplished by creating a simple conditional block and placing your trade routine within this block like this:

if (Bars != ThisBarTrade ) {
   ThisBarTrade = Bars;  // ensure only one trade opportunity per bar
   // Trade logic goes here
}

The simple block above checks if the current bar (Bars) is equal to the ThisBarTrade variable. The != operand means not equal to. So if Bars is not equal to ThisBarTrade, then MT4 enters the block of code which starts with a curly bracket {, otherwise the code skips over the block to the end curly bracket }. 

When Bars != ThisBarTrade then the block of code is executed. The next line sets the module level variable ThisBarTrade equal to the current bar number (Bars). This is done so that the code in the block may only be processed one time. It really is this simple to prevent multiple trades per bar or to prevent processing any event intrabar, by encapsulating that event within a block of code that uses the Bars predefined variable.

To recap, if you wish to limit processing of a certain block of MQL4 code to only once per bar do the following:
  • Declare a module level variable of type integer.
  • Place a conditional if block around the block of code you would like to limit and check for inequality (!=) of your module level variable with Bars.
  • Within the conditional if block, set your module level variable equal to Bars.
Continue reading how to create a simple forex MT4 expert advisor template that trades only once per bar. If you've ever wanted a template to create simple expert advisors, this might be a good starting point. The code gets more complex as new functions are added to close out buy and sell orders, to keep track of the currently open position, and to place buy or sell orders. At the end of the MQL4 tutorial, a fully functional template is available for download.

Alternatively, if you would like to see a fully functional MT4 expert advisor that only trades once per bar, download the SnowRoller EA for MT4 Expert Advisor and check out the MQL4 code in the MetaEditor.

Close All Trades All Symbols MQL4 Script for Metatrader 4

There are times when having the quick ability to close out all trades on an account or on a given magic number comes in handy. Whether you are taking a large profit or getting out of a jam, the CloseAll_AllSymbols MQL4 script for Metatrader belongs in every forex trader's arsenal of tools. Simply double click the script from the Navigator pane after copying it into the correct folder, and all open trades should be closed for the magic number selected. The default value is to close all trades for all magic numbers (MagicNumber = -1).

CloseAll_AllSymbols MQL4 is a Metatrader 4 Script that searches through an account and closes out all open trades that match the selected magic number. By default all trades are closed so this makes a handy way to exit the market and get flat in a flash. The script contains default values that will execute unless you manually edit the code from within the MetaEditor.

// when MagicNumber = -1 then close all magic numbers
extern int MagicNumber = -1;

// pips of slippage to allow
extern int Slippage = 7; 

If you wish to change the maximum allowance for slippage, you must change the value in the code prior to executing the script on your chart. Right-click on the navigator pane while selecting the script's name, and choose Modify. This should open up the MetaEditor and load the script into memory. Change the value as desired, then click the "Compile" button at the top of the MetaEditor. 

How to use CloseAll_AllSymbols.mq4

Download the file below and copy it into your "..\experts\scripts" folder. After restarting Metatrader 4 so that it has a chance to compile and find the script and place it in the Navigator pane. You should see the script CloseAll_AllSymbols listed under "Scripts" if you copied the file into the right location, and restarted your Metatrader. Be careful because when you double click the MT4 script all trades on ALL selected charts should close immediately!

You may post this MT4 script to other sites, but if you do, you must post a link to this page directly and you may not sell it or the source code. You are otherwise free to copy, use and distribute this MQL4 script for non-commercial use. 

Note: updated 11/11/2011 to eliminate a small bug that prevented the script from unloading correctly, and reworked the for loop direction to take all fill possibilities into account.

Updated 12/1/2012 to make script compatible with FIFO order exit rule.

Close All Orders This Symbol Only MQL4 Script for Metatrader

If you trade like me, sometimes you just need to exit a particular forex pair, and quickly! This script will do that for a single currency chart. Simply double click the script from the navigator pane after copying into the correct folder, and the selected chart's open trades should all be closed.

CloseAll_ThisSymbol.mq4 is a MQL4 script for closing all orders for a single forex symbol. The code is explained in greater detail in the MQL4 code tutorial titled, "How To Write a Close All Script in MQL4?" If you have questions about the MQL4 code, please refer to that document. 

Default values for slippage and magic number have been placed in the script as follows:

// when MagicNumber = -1 then close all magic numbers
extern int MagicNumber = -1;

// pips of slippage to allow
extern int Slippage = 7; 

If you wish to change the maximum allowance for slippage, you must change the value in the code prior to executing the script on your chart. Right-click on the navigator pane while selecting the script's name, and choose Modify. This should open up the MetaEditor and load the script into memory. Change the value as desired, then click the "Compile" button at the top of the MetaEditor. 

The default value for MagicNumber is -1. This value indicates that magic number should not be used to limit the trades that should be closed for this fx symbol. In other words, when MagicNumber equals -1, all open trades for the currently selected chart will be closed. Change MagicNumber to the desired number if you wish to only close out certain trades that use the magic number tag.

How to use CloseAll_ThisSymbol MQL4

Download the file below and copy it into your "..\experts\scripts" folder. After restarting Metatrader 4 so that it has a chance to compile and find the script and place it in the Navigator pane. You should see the script CloseAll_ThisSymbol listed under "Scripts" if you copied the file into the right location, and restarted your Metatrader. Be careful because when you double click the MT4 script all trades on the currently selected chart should close immediately!

You may post this MT4 script to other sites, but if you do, you must post a link to this page directly and you may not sell it or the source code. You are otherwise free to copy, use and distribute this MQL4 script for non-commercial use. 

Note: updated 11/11/2011 to eliminate a small bug that prevented the script from unloading correctly, and reworked the for loop direction to take all fill possibilities into account.

Updated 12/1/2012 to make script compatible with FIFO order exit rule.

How to Use the MarketInfo MQL4 function?

This how to MQL4 article covers the MarketInfo() function and touches on some other useful functions including, Symbol()OrderSelect(), OrderSymbol(), OrderClose(), and NormalizeDouble(). In addition this article discusses the constants MODE_BID, Bid, MODE_ASK, Ask, MODE_DIGITS, Digits and NULL.
Let's say you wish to create an expert advisor or indicator that references data from another chart. How would a trader go about doing that in MQL4? The MarketInfo() function has many useful request identifiers. (Please consult the help within MetaEditor for a complete list). But first read on! MarketInfo() is defined as follows:
double MarketInfo(string symbol, int type)

To reference the current chart's data, simply insert NULL or Symbol() where it says symbol, such as MarketInfo(NULL, ...) or MarketInfo(Symbol(), ...).
string Symbol()

If you'd like to use MarketInfo() to reference other forex charts within Metatrader, there are several ways to do this and they are context specific. Let's assume you wish to close out a group of trades on a different symbol. For instance in the scripts Close All Orders This Symbol Only, and Close All Trades All Symbols trades are closed out via a loop. Here is a snippet from the second link.

bool closed = false;
   for (int i = 0; i < OrdersTotal(); i++) {
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
        .............
      if (OrderType() == OP_BUY && (MagicNumber == OrderMagicNumber() || MagicNumber == -1)) {
        closed = OrderClose( OrderTicket(), OrderLots(), 
        NormalizeDouble(MarketInfo(OrderSymbol(),MODE_BID),MarketInfo(OrderSymbol(),MODE_DIGITS)), Slippage,        White);
      }
.................

Note that within the close out for loop, OrderSelect is called. This effectively opens up some opportunities to use built-in MQL4 functions to reference information about trades that have originated from charts other than the current chart. 
bool OrderSelect(int index, int select, int pool=MODE_TRADES)

The OrderClose function calls for a ticket number, the number of lots to close, a closing price, a slippage amount, and a color. Notice the presence of the MarketInfo function in the parameter that refers to a closing price. 
bool OrderClose(int ticket, double lots, double price, int slippage, color Color=CLR_NONE)

In this case functions are nested to ensure that data is formatted in the correct way. The first term of the MarketInfo function is OrderSymbol which references the selected order's symbol. This handy function provides the symbol term that is needed to fill the first term of MarketInfo. The bid price is referenced by using the MODE_BID request identifier. MODE_BID is a constant with the value of 9. 

It is not hard to see how this MQL4 example could be easily adapted to close out a long trade by using MarketInfo along with the MODE_ASK request identifier. That block of MQL4 code would look something like this:    
if (OrderType() == OP_SELL && (MagicNumber == OrderMagicNumber() || MagicNumber == -1)) {
        closed = OrderClose( OrderTicket(), OrderLots(), 
        NormalizeDouble(MarketInfo(OrderSymbol(),MODE_ASK),MarketInfo(OrderSymbol(),MODE_DIGITS)), Slippage, White);
}

The NormalizeDouble function is called to ensure the proper decimal places are used to round the price before order submission. I have noticed that Metatrader brokers tend to be VERY picky about the formatting of orders with the OrderClose function, thus the need for extra special care by using the NormalizeDouble function. The help file declares NormalizeDouble as follows:
double NormalizeDouble( double value, int digits)

In this case the market price that will be used to close the open trade is referenced either by MODE_BID or MODE_ASK. Thus the bid or ask price will be used as returned from the MarketInfo function. Metatrader brokers will reject orders if the incorrect price is used in an OrderClose function. Ensure that MODE_BID is used to close a long trade, and MODE_ASK is used to close a short trade. Referencing Close[0] or any other price will often kick out a dreaded error usually in the range of 135-138 (see your MetaEditor help file under "Error codes") or some similar error that prevents trade execution in the Metatrader terminal, so it pays to double check your MQL4 code.

The second term of NormalizeDouble requires the number of Digits. Because this routine may be referring to a symbol that may be different than the local variable Digits, the correct value is retrieved by making another call to MarketInfo as below:
MarketInfo(OrderSymbol(),MODE_DIGITS)
If the symbol is a Japanese Yen pair and the broker is using pippettes, then the function above will return 3 for Digits. If pips are used it will return 2. For non-JPY pairs the return values will be 5 or 4 respectively for Digits

For more information about how to close all open trades, or how to close all open orders for the selected symbol only, please see the referenced scripts, or read the tutorial for a full blow-by-blow walkthrough of how to write a close all script in MQL4.

These are just two short examples of how to use the MarketInfo function to reference data that may or may not be on a different chart. There are many other possible uses for this function (see the MetaEditor help file under "MarketInfo" for more information about request identifiers) but the form of the MarketInfo function is similar to the form discussed in this short tutorial.

MQL4 OrderClose, OrderCloseBy, OrderDelete, OrderModify, OrderSend OrderClose


OrderCloseBy
OrderDelete
OrderModify
OrderSend
Trade Operation (OP_BUY, OP_SELL, OP_BUYLIMIT, OP_SELLLIMIT, OP_BUYSTOP, OP_SELLSTOP)



OrderClose Closes an open trade with the matching ticket number at the specified price. 
bool OrderClose(int ticket, double lots, double price, int slippage, color Color=CLR_NONE)
Returns TRUE if OrderClose succeeds and the open trade is closed, and FALSE if the OrderClose function fails and order doesn't close. Detailed error information may be retrieved on failure with the GetLastError function.

Parameters:
int ticket    Order ticket number of order to close
double lots   Amount of Lots to close
double price  Requested order closing price
int slippage  Amount of slippage in pips (for 4/2 digit brokers) or pippettes (for 5/3 digit brokers)
color Color   (Optional) Color of the closing arrow on the chart.
              The default value is CLR_NONE or no arrow drawn.

Example: Routine to close all orders for all symbols with given Slippage and OrderMagicNumber.

void CloseAll(int Slippage, int MagicNumber) {
bool closed;
for (int i = 0; i < OrdersTotal(); 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);
    }
}
}






OrderCloseBy Closes an open order by an opposite open order.
bool OrderCloseBy(int ticket, int opposite, color Color=CLR_NONE)
Returns TRUE if OrderCloseBy succeeds and the open trade is closed, and FALSE if OrderCloseBy fails and the order doesn't close. Detailed error information may be retrieved on failure with the GetLastError function.

Note: lot sizes must be the same for both orders.

Parameters:
int ticket    Order ticket number of order to close
int opposite  Ticket number of the opposite order.
color Color   (Optional) Color of the closing arrow on the chart.
              The default value is CLR_NONE or no arrow drawn.

Example:
if (iRSI(Symbol(), 0, 30, PRICE_CLOSE, 0) < 50) {
    if( OrderCloseBy(ticket, opposite, White) == true) {
        return(-1);
    } else {
        Print("OrderCloseBy failed. Ticket #" + ticket + " opposite #" + opposite + "Error# " + GetLastError());
        return(0);
    }
}

OrderDelete Deletes previously opened pending order.
bool OrderDelete(int ticket, color Color=CLR_NONE)
Returns TRUE if OrderDelete succeeds and the order is deleted, otherwise FALSE if OrderDelete fails. Detailed error information may be retrieved on failure with the GetLastError function.

Parameters:
int ticket    Order ticket number of pending order to delete.
color Color   (Optional) Color of the closing arrow on the chart.
              The default value is CLR_NONE or no arrow drawn.

Example: Routine to delete all buy stop orders for the current symbol with given OrderMagicNumber.
void DeleteThis_BUYSTOP(int MagicNumber) {
bool deleted;
for (int i = 0; i < OrdersTotal(); i++) {
    OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
    while(IsTradeContextBusy()) Sleep(100);
    if (OrderType() == OP_BUYSTOP && MagicNumber == OrderMagicNumber()
     && OrderSymbol() == Symbol() ) {           deleted = OrderDelete(OrderTicket(), CLR_NONE);
         if(deleted == false) {
             Print("Error deleting buy stop order " + OrderTicket() + " Err#:" GetLastError());
         }
    }
} }



OrderModify Modifies a pending order or open trade.
bool OrderModify(int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE)
Returns TRUE if OrderModify succeeds and the order is modified otherwise FALSE if OrderModify fails. Detailed error information may be retrieved on failure with the GetLastError function.

Note: Price and expiration may only be changed on pending orders.  Error #1 (ERR_NO_RESULT) will be generated if  unchanged values are passed as function parameters. Some trade servers may disable pending order expiration time. If the broker has disabled expiration time, error #147 (ERR_TRADE_EXPIRATION_DENIED) will occur.

Parameters:
int ticket          Order ticket number of pending order to modify.
double price        Requested order price.
double stoploss     Requested stop loss level.
double takeprofit   Requested take profit level (profit target).
datetime expiration Pending order expiration time.
color arrow_color   (Optional) Color to show stoploss/takeprofit modification arrow on the chart. 
                    The default value is CLR_NONE or no arrow drawn.

Example: Function to modify a newly entered MT4 order to add the stoploss and takeprofit fields with a given ticket called OrderModify. This MQL4 function is taken from SnowRoller_1_008.
bool ModifyOrder(int ticket) {
   if(ticket == -1) return(false);
   bool dotp = false;
   double sl = 0.0, tp = 0.0;
   int repeats = 0;
   ordernumber +=1;
   if (MathMod(ordernumber,2) == 0) {
      dotp =true;
   }
   bool result = false;
  
      RefreshRates();
      while(!IsTradeAllowed()) Sleep(100);
      if (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES) == true) {
         Print("Order Selected " + ticket);
         if(OrderType() == OP_BUY) {
            sl = NormalizeDouble(OrderOpenPrice() - stoploss * Point * NormalizeLots, Digits);
            if (takeprofit > 0 && dotp == true ) {
               tp = NormalizeDouble(takeprofit * Point * NormalizeLots + OrderOpenPrice(), Digits);
            } else {
               tp = 0.0;
            }
         }
         if(OrderType() == OP_SELL) {
            sl = NormalizeDouble(stoploss * Point * NormalizeLots + OrderOpenPrice(), Digits);
            if (takeprofit > 0 && dotp == true) {
               tp = NormalizeDouble(-takeprofit * Point * NormalizeLots + OrderOpenPrice(), Digits);
            } else {
               tp = 0.0;
            }
         }
         Print("minimum: " + MarketInfo(Symbol() , MODE_STOPLEVEL) +   " Order Type: " + OrderType() + " Entry Price: " + OrderOpenPrice() +  " Moving SL to: " + sl + " and TP to " + tp);
         result = OrderModify(ticket, NormalizeDouble(OrderOpenPrice(), Digits), sl, tp, OrderExpiration(), CLR_NONE);
         if (result == true) return (true);
      } else
      repeats += 1;
      if (repeats > 5) {
         Print("Unable to select ticket # " + ticket);
         return(false); // failure
      }
}



OrderSend Creates a new order and sends it to the Metatrader broker.
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)
Returns the ticket number of the order if the OrderSend function succeeds, otherwise returns -1 on failure of the OrderSend function. Detailed error information may be retrieved on failure with the GetLastError function.

Notes
MT4 requires the latest Bid (for OP_SELL orders) or Ask (for OP_BUY orders) for price. Volume is referred to in other functions as Lots. These terms are synonymous.

Use the MarketInfo function to retrieve Bid (MODE_BID) or Ask (MODE_ASK) prices for symbols other than the currently selected symbol. Prices used to open (or close) trades must be normalized using the NormalizeDouble function with Digits as the second parameter.

To reference Digits for other symbols, use the MarketInfo function to retrieve Digits (MODE_DIGITS). Failure to normalize prices will trigger error# 129 (ERR_INVALID_PRICE). Stale quotes will trigger error# 138 (ERR_REQUOTE) independent of the slippage parameter.

Use the RefreshRates function before any OrderSend function call to ensure up-to-date prices are held in the Bid/Ask variables. If price on the broker's server moves since the last variable update, on the MT4 terminal client, but is within the slippage amount entered, the order will be filled, otherwise error# 138 (ERR_REQUOTE) will trigger.

Due to U.S. brokerage rules, the best practice is to enter orders without an attached stoploss or takeprofit, then use the OrderModify function to edit the order and attach a stoploss and takeprofit amount as is shown in the ModifyOrder function example.

StopLoss, TakeProfit, and pending order levels may not be placed closer than the distance indicated by the MarketInfo function with MODE_STOPLEVEL parameter. If stop levels are too close or are not properly normalized, error# 130 (ERR_INVALID_STOPS) will be triggered.

Some brokers have disabled the expiration time on their trade servers. Transmitting a non-zero expiration parameter to a broker with disabled expiration time will lead to error# 147 (ERR_TRADE_EXPIRATION_DENIED).

If your broker limits the total number of pending and open orders and trades, error# 148 (ERR_TRADE_TOO_MANY_ORDERS) may be triggered if your order would exceed the broker's order limit.

Parameters:
string symbol       Trade symbol name.
int cmd             Trade operation type. This may be any trade operation enumeration.
double volume       Amount of Lots for order.
double price        Requested order price.
int slippage        Amount of slippage in pips (for 4/2 digit brokers) or pippettes (for 5/3 digit brokers)   
double stoploss     Requested stop loss level.
double takeprofit   Requested take profit level (profit target).
string comment      (Optional) Comment attached to order. This may be used to differentiate between orders.
                    The default value is NULL.
int magic           (Optional) Magic number attached to order. May be used to differentiate between orders.
                    The defalut value is 0.
datetime expiration (Optional) Pending order expiration time.
                    The default value is 0 (no expiration).
color arrow_color   (Optional) Color to show the opening order arrow on the chart. 
                    The default value is CLR_NONE or no arrow drawn.

Trade Operation Constants used in the OrderSend function.
Constant        Value        Description
OP_BUY          0            Buy order
OP_SELL         1            Sell order
OP_BUYLIMIT     2            Buy limit pending order
OP_SELLLIMIT    3            Sell limit pending order
OP_BUYSTOP      4            Buy stop pending order
OP_SELLSTOP     5            Sell stop pending order


Example: SendTrade function taken from SnowRoller_1_008. This function takes the trade operation as the type parameter, and returns the ticket number if the OrderSend function succeeds, otherwise -1 if OrderSend fails. On failure, use the Print routine with the GetLastError function to return the error number such as:
if(ticket == -1) Print("Error Opening Buy Order: " + GetLastError());

The ticket number returned by the OrderSend function is then sent to the ModifyOrder function (see code) to attach a stoploss and takeprofit via the OrderModify function. Normally, error checking should be done after OrderSend returns a ticket number with -1.
int SendTrade(int type)
{
   bool dotrades = false;
   int expiry = 0;
   color clr = Red;
   bool result = false;
   if (type == OP_BUY || type == OP_BUYSTOP) clr = Green;
   int ticket = -1;
  
   while(!IsTradeAllowed()) Sleep(100);
   RefreshRates();
   MaxEquity = GlobalVariableGet("SRMaxEquity");
   if (OpenTrades >= MaxTradesThis) return;
  
   if ((type == OP_BUY )) {
         if(Position == 0) {
            initialAnchor = Close[0];
         }
         if(Close[0] < initialAnchor - MaxNegExcursion * Point * NormalizeLots) return;
         if(Ask - Bid > MaxSpread * Point * NormalizeLots) return;
         ticket = OrderSend(Symbol(), type, (MinLotSize * lotsize * LotMultiplier), NormalizeDouble(Ask,Digits), Slippage * NormalizeLots, 0, 0, comment, MN, expiry, clr);
         return(ticket);
   }
   if ((type == OP_SELL)) {
         if(Position == 0) {
            initialAnchor = Close[0];
         }
         if(Close[0] > initialAnchor + MaxNegExcursion * Point * NormalizeLots) return;
         if(Ask - Bid > MaxSpread * Point * NormalizeLots) return;
         ticket = OrderSend(Symbol(), type, (MinLotSize * lotsize * LotMultiplier), NormalizeDouble(Bid,Digits), Slippage * NormalizeLots, 0, 0, comment, MN, expiry, clr);
         return(ticket);
   }
   return(-1);
}