Download MetaTrader 5
To add comments, please log in or register
Write your articles using our editor. It is convenient!
Nick
21
Nick 2014.03.02 02:42 

I'm fairly new to automated trading and trying to create an EA that will trade a strategy that I use with Bollinger Bands and RSI. So far I have the coded the EA to trade off of bollinger bands. The program works fine the first round through when I tested it. One trade is opened and on the next new bar the program just stops. Could anyone help me out with why my EA isn't running the whole time through my strategy tester? My code is below. Thanks.


//--- input parameters
extern int      bands_period=14;     // Bollinger Bands Period
extern int      bands_shift=0;       // Bollinger Bands Shift
extern int      deviation=2;         // Standard Deviation
extern double   Lot=0.1;             // Lots to trade
//--- global variables
double BolBandsUpper;               // Bollinger Bands upper
double BolBandsLower;               // Bollinger Bands lower
//+------------------------------------------------------------------+
//| Expert inttialization function                                   |
//+------------------------------------------------------------------+
void OnInit()
{
   // check for chart history and trading
   if(Bars(_Symbol,_Period) < 60 && IsTradeAllowed() == false)
   {
      Alert("There are less than 60 bars on the chart, EA terminated!");
      return;
   }
   
   // get handle of the indicators
   BolBandsUpper = iBands(NULL,0,bands_period,deviation,bands_shift,PRICE_CLOSE,MODE_UPPER,0);
   BolBandsLower = iBands(NULL,0,bands_period,deviation,bands_shift,PRICE_CLOSE,MODE_LOWER,0);

   // check for invalid handles
   if(BolBandsUpper < 0 || BolBandsLower < 0)
   {
      Alert("Error in creation of indicators - error: ",GetLastError(),"!");
      return;
   }
   
   // check account margin 
   if(!CalculateAccountMargin())
   {
      Alert("Insufficient funds! Free Margin: ",AccountFreeMargin());
      return;
   }    
}
//+------------------------------------------------------------------+
//| Expert Tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{  
   static datetime oldTime = 0;   // serves as the bar time
   datetime newTime = Time[0];       // current bar time at each OnTick execution
   bool IsNewBar = false;     // check to see that there is a new tick
  
   // check if data copied successfully
   if(newTime > oldTime)    
   {
      IsNewBar = true;
      oldTime = newTime;
   }
   
   // EA only checks for trade if there is a new bar
   if(!IsNewBar)
     return;
   
   // store prices, volumes, and spreads of each bar
   MqlRates mrate[];
   
   // rates arrays
   ArraySetAsSeries(mrate,true);
   
   // get details of the latest 3 bars
   if(CopyRates(_Symbol,_Period,0,3,mrate) < 0)
   {
      Alert("Error copying rates/history data - error: ",GetLastError(),"!");
      return;
   }
   
   int total = 0;
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false)
         break;
      if(OrderSymbol() == Symbol() && OrderMagicNumber() == MAGICNUM)
         total++;
   }
   if(total == 0 && CalculateAccountMargin())
   {
      // Buy Conditiion, bull candle crosses Lower Band from below to above
      // and MA is growing
      if(mrate[1].close > BolBandsLower && mrate[1].open < BolBandsLower)
      {
         OrderSend(Symbol(),OP_BUY,Lot,Ask,3,0,0,NULL,MAGICNUM,0,clrBlue);
      }
      // Sell Condition, bear candle crosses Upper Band from above to below
      // and MA is falling
      if(mrate[1].close < BolBandsUpper && mrate[1].open > BolBandsUpper)
      {
         OrderSend(Symbol(),OP_SELL,Lot,Bid,3,0,0,NULL,MAGICNUM,0,clrRed);
      }
   }
   if(total >= 1)
   {
      // Buy Close, bear candle crosses Upper Band from above to below
      if(mrate[1].close < BolBandsUpper && mrate[1].open > BolBandsUpper)
      {
         OrderClose(OrderTicket(),OrderLots(),Bid,3,clrWhite);
      }
      // Sell Close, bull candle crosses Lower Band from below to above
      if(mrate[1].close > BolBandsLower && mrate[1].open < BolBandsLower)
      {
         OrderClose(OrderTicket(),OrderLots(),Ask,3,clrWhite);
      }
   }
}
//+------------------------------------------------------------------+
//| Check Account Margin function                                    |
//+------------------------------------------------------------------+
bool CalculateAccountMargin()
{
   bool MarginAvailable;
   double MarginRequired = AccountFreeMargin();
   // determine MarginRequired for specific pair
   if(Symbol() == "USDJPY" || Symbol() == "USDCAD" 
      || Symbol() == "NZDJPY" || Symbol() == "NZDUSD")
   {
      MarginRequired = Lot * 2000;
   }
   if(Symbol() == "AUDUSD" || Symbol() == "AUDJPY"
           || Symbol() == "AUDNZD")
   {
      MarginRequired = Lot * 2400;
   }
   if(Symbol() == "EURUSD" || Symbol() == "EURGBP"
           || Symbol() == "EURJPY")
   {
      MarginRequired = Lot * 3200;
   }
   if(Symbol() == "GBPUSD" || Symbol() == "GBPJPY")
   {
      MarginRequired = Lot * 3800;
   }
   if((Symbol() != "USDJPY") && (Symbol() != "USDCAD") && (Symbol() != "NZDJPY") && (Symbol() != "NZDUSD")
      && (Symbol() != "AUDUSD") && (Symbol() != "AUDJPY") && (Symbol() != "AUDNZD")
      && (Symbol() != "EURUSD") && (Symbol() != "EURGBP") && (Symbol() != "EURJPY")
      && (Symbol() != "GBPUSD") && (Symbol() != "GBPJPY"))
   {
      Alert("Margin not calculated for pair, EA terminated!");
      MarginAvailable = false;
   }
   else
   {   
      // determine is enough free margin to trade
      if(AccountFreeMargin() > (MarginRequired + 30))
         MarginAvailable = true;
      else
         MarginAvailable = false;
   }
   
   return(MarginAvailable);
}

Luciano Ola
996
Luciano Ola 2014.03.02 02:54  

It may be a critcal error, whenever this happens to me, failure to preform global initialisation or a "zero divide" is the cause. Is this a multi-currency EA? It may help to know what your journal is saying when the crash occurs.

Keith Watford
Moderator
7907
Keith Watford 2014.03.02 03:58  

Please Edit your post and put your code in a single SRC box. It is very difficult to read

I don't understand why you have created the array newTime with just 1 element, there is no point at all.

As well as that your logic is faulty,

static datetime oldTime; // serves as the bar time
datetime newTime[1]; // current bar time at each OnTick execution
bool IsNewBar = false; // check to see that there is a new tick
// copy saved bar time to newTime[0]
int copied = CopyTime(_Symbol,_Period,0,1,newTime);
// check if data copied successfully
if(copied > 0)//------------------------------Just because copied is >0 it doesn't mean that this is a new bar
{
IsNewBar = true;
oldTime = newTime[0];
}

Use something like this - much simpler

static datetime oldTime =0; // serves as the bar time
datetime newTime=Time[0]; // current bar time at each OnTick execution
bool IsNewBar = false; 
if(newTime>oldTime)
{
IsNewBar = true;
oldTime = newTime;
}
Keith Watford
Moderator
7907
Keith Watford 2014.03.02 04:41  

You declare the arrays BBUp[] and BBLow[]

But I don't see anywhere that you ReSize the arrays or assign a value to them.

When you try to get the values for BBUp[1] and BBLow[1], you will get Critical error - "Array out of range"

Nick
21
Nick 2014.03.02 05:39  

Thank you for your help. I fixed up my code with some of your suggestions and made it easier to read.

I removed the BBUp[] and BBLow[] from the program, they were from an older version I tried before I did some fixes.

The EA runs the whole way through my backtesting, but orders are not being executed correctly. I'm aiming for the EA to go long after a bar opens below the Lower Bound and closes above, and then closes the order when a bar opens above the Upper Bound and closes below, and vice-versa for short orders. On a 15-min chart, positions are being held for days at a time, when they be being held for only a few hours. Not sure if this is a problem with my order execution or indicators.

Keith Watford
Moderator
7907
Keith Watford 2014.03.02 06:08  
if(newTime > oldTime)    
   {
      IsNewBar = true;
      oldTime = newTime;
   }
   else
   {
      Alert("Error in copying historical times data - error: ", GetLastError());
      ResetLastError();
      return;
   }

Remove the highlighted code - it is not necessary

James Hodges
2782
James Hodges 2014.03.02 06:50  
1468714724:

Thank you for your help. I fixed up my code with some of your suggestions and made it easier to read.

I removed the BBUp[] and BBLow[] from the program, they were from an older version I tried before I did some fixes.

The EA runs the whole way through my backtesting, but orders are not being executed correctly. I'm aiming for the EA to go long after a bar opens below the Lower Bound and closes above, and then closes the order when a bar opens above the Upper Bound and closes below, and vice-versa for short orders. On a 15-min chart, positions are being held for days at a time, when they be being held for only a few hours. Not sure if this is a problem with my order execution or indicators.

Sounds like you are making some progress and learning to code better. I want to mention that the following lines where you get the bollinger band values.
 // get handle of the indicators
   BolBandsUpper = iBands(NULL,0,bands_period,deviation,bands_shift,PRICE_CLOSE,MODE_UPPER,0);
   BolBandsLower = iBands(NULL,0,bands_period,deviation,bands_shift,PRICE_CLOSE,MODE_LOWER,0);

Are in the OnInitt() function. Bear in mind that OnInit() only runs when the Expert initializes. You need to get these values with each new candle so you will need to move this code into the OnTick function. Also I just noticed that you are getting the values of candle zero which is still in progress. You may want to get the values from finished candle 1 since your trader triggers are based on mrate[1].

The second thing I wanted to mention was your order closing code.

 if(mrate[1].close < BolBandsUpper && mrate[1].open > BolBandsUpper)
      {
         OrderClose(OrderTicket(),OrderLots(),Bid,3,clrWhite);
      }
Here you need to use OrderSelect() before you call for the OrderTicket(). I know that above you have a for loop that is going through the trades looking to see how many trades are open ..
int total = 0;
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false)
         break;
      if(OrderSymbol() == Symbol() && OrderMagicNumber() == MAGICNUM)
         total++;
   }

If you have two trades open and the first one was of the proper Magicnumber and the second order selected was not. You may show only one order open on this pair however the ticketnumber of the last order selected is the one that will be closed. It's best to do an OrderSelect just before you ask for the ticket number to insure you are closing the proper order. This of course is not an issue in strategy tester but can cause real problems in actual use on a real platform trading multiple pairs. Hope this helps you a little...PipPip....Jimdandy.

p.s . You mentioned that your program stops.. keep in mind that it is only going to run on the first tick of each candle so it will stop.. for 15m and then run for 1 tick. Not sure what you mean by 'it stops' I guess.

whroeder1
13610
whroeder1 2014.03.02 13:56  
GumRai: Use something like this - much simpler
static datetime oldTime =0; // serves as the bar time
datetime newTime=Time[0]; // current bar time at each OnTick execution
bool IsNewBar = false; 
if(newTime>oldTime)
{
IsNewBar = true;
oldTime = newTime;
}
Simplified, more:
static datetime newTime =0; datetime oldTime=newTime; 
newTime=Time[0];            bool     isNewBar = newTime != oldTime; 
Don't use ">", use "!=" in case server clock is off and gets reset back (There is a post on this happening, EA stopped functioning for days) or end of DST.
Remember statics don't reset on TF changes.
/
To add comments, please log in or register