• No results found

// Buy Order

if(FastMA > SlowMA && BuyTicket == 0 && BuyOrderCount(Symbol(),MagicNumber) == 0) {

// Buy order code omitted for brevity }

// Sell Order

if(FastMA < SlowMA && SellTicket == 0 && SellOrderCount(Symbol(),MagicNumber) == 0) {

// Sell order code omitted for brevity }

} // End trade block

There are many more ways to create timers – for example, you could use the day of the week instead of the month and day, or set trade times relative to the current day. We'll leave it to you, the reader, to create a timer that is appropriate for your needs.

Execute On Bar Open

By default, expert advisors run in real-time, on every tick. But in some cases, it may be better to check trading conditions only once per bar. By waiting for the current bar to close, we can be sure that the condition has occurred and that the signal is valid. In comparison, by executing trades in real-time, we may be more susceptible to false signals.

Trading once per bar also means that the results in the Strategy Tester will be more accurate and relevant. Due to the inherent limitations of MetaTrader's Strategy Tester, using "Every tick" as the testing model will produce unreliable back testing results, due to the fact that ticks are often modeled

from M1 data. The trades that occur in live trading will not necessarily correspond to trade made in the Strategy Tester.

But by placing our trades on the close on the bar and using "Open prices only" as the testing model, we can get testing results that more accurately reflect real-time trades. The disadvantage of trading once per bar is that trades may be executed late, especially if there is a lot of price movement over the course of the bar. It's basically a trade-off between responsiveness and reliability.

To check the trade conditions once per bar, we must examine the time stamp of the current bar. We will save this time stamp to a global variable. Upon each execution of the expert advisor, we will compare the saved time stamp to the current time stamp. Once the time stamp of the current bar changes, indicating that a new bar has opened, we will then check the trading conditions.

We must also adjust the shift parameter of our indicator functions, price functions and arrays to return the value of the previous bar. If an indicator function or price array is set to check the current bar, we will shift the bar index by 1 to check the previous bar instead. All indicators and price arrays must have their shift parameters incremented by 1.

Technically, we are checking trading conditions on the first tick of a new bar, while examining the closing value of the previous bar. We do not check the currently opened bar when executing once per bar.

Here is the code to check for the opening of a new bar. First, we declare an external variable named CheckOncePerBar to turn this feature on and off. Then we declare a datetime global variable to store the time stamp of the current bar – this will be CurrentTimeStamp.

In the init() function, we will assign the time stamp of the current bar to CurrentTimeStamp. This will delay the trade condition check until the opening of the next bar:

// External variables

extern bool CheckOncePerBar = true;

// Global variables

datetime CurrentTimeStamp;

// Init function int init()

{

CurrentTimeStamp = Time[0];

}

Here is the code that goes at the beginning of our start() function, just after the timer. The integer variable BarShift will determine whether to set the Shift value of our indicator and price functions to the current bar or the previous bar. The boolean variable NewBar will determine whether we will check our trade conditions:

if(CheckOncePerBar == true) {

int BarShift = 1;

if(CurrentTimeStamp != Time[0]) {

CurrentTimeStamp = Time[0];

bool NewBar = true;

}

else NewBar = false;

} else

{

NewBar = true;

BarShift = 0;

}

If CheckOncePerBar is set to true, we will first set BarShift to 1. This will set the Shift parameter of all indicator and price functions/arrays to the previous bar.

Next, we compare the value of CurrentTimeStamp variable to Time[0], which is the time stamp of the current bar. If the two values do not match, we will assign the value of Time[0] to

CurrentTimeStamp and set NewBar to true. The trading conditions will be checked shortly thereafter.

On subsequent runs, CurrentTimeStamp and Time[0] will match, which means that NewBar will be set to false. The trade conditions will not be checked until a new bar opens. Once a new bar opens, Time[0] will be a different value than CurrentTimeStamp, and NewBar will be set to true once again.

If CheckOncePerBar is set to false, NewBar will automatically be set to true, and BarShift will be set to 0. This will check the trading conditions on every tick, as before.

The BarShift variable will need to be assigned to the Shift parameter of any indicator functions, price functions or arrays that reference the most recent bar. Here are some examples of how this would be applied:

double FastMA = iMA(NULL,0,FastMAPeriod,0,0,0,BarShift);

if(Close[BarShift] > Open[BarShift]) double UseLow = iLow(NULL,0,BarShift);

You should recognize these examples from before. Instead of checking the current bar, we will check the bar that just closed, i.e. the previous bar. If you need to reference a bar previous to the last closed bar, simply add the current shift parameter to BarShift:

double LastFastMA = iMA(NULL,0,FastMAPeriod,0,0,0,BarShift+1);

If you don't anticipate ever needing to run your expert advisor once per bar, you won't need to add this code. But for many indicator-based trading systems, this can make your trading and back testing results more reliable.

To control the execution of trades, we need to check the value of NewBar before the order placement routines. We can do this using the if block we placed earlier for the timer:

// Begin trade block

if(TradeAllowed == true && NewBar == true) {

// Buy Order

if(FastMA > SlowMA && BuyTicket == 0 && BuyOrderCount(Symbol(),MagicNumber) == 0) {

// Buy order code omitted for brevity }

// Sell Order

if(FastMA < SlowMA && SellTicket == 0 && SellOrderCount(Symbol(),MagicNumber) == 0) {

// Sell order code omitted for brevity }

} // End trade block

Chapter 8

Related documents