Code not behaving as expected in EA

 

I've been working on an EA that only trades in the daily time frame. I'll only talk long trades so hopefully someone can spot what I have done wrong.

The idea is to enter into a trade, when the 5 ema is above the 20, and a seller bar happens that is between the lower upper envelope and bottom envelope. You enter in on the bar following that seller day, so long as the day today price passes the high of yesterday. I was trying to use pending orders on this, as it did seem easier but then it was hard to trace when the EA had entered. So I made it enter at market, and set flags to keep tract of where it was at, but this isn't working :(

extern int     PeriodSlow=20;
extern int     PeriodFast=5;
extern double  Envelope1=0.6;
extern double  Envelope2=1.2;
extern int     StopLossBuffer=5;
extern int     EntryBuffer=5;
extern double  FixedLotSize=0.1;
extern int     Slippage=0;
extern int     AccountRisk=0;

//define globals
int            TradeTicket=0;
datetime       CurrentBarTimeStamp;
int            MagicNumber=163;
double         BuyEntryPrice=0;
double         SellEntryPrice=0;
bool           ValidActivatorLong=false;
double         TakeProfit;
int            StopLoss;
double         Lots;           

int init()
  {
   if(PeriodFast<2) PeriodFast=5;    //ensure no silly ema period specified
   if(PeriodSlow<2) PeriodSlow=20;    //ensure no silly ema period specified
   return(0);
  }


int deinit()
  {
   return(0);
  }

int start()
  {
  double EMALong, EMAShort, FirstUpperEma, SecondUpperEma, FirstLowerEma, SecondLowerEma;
  // see if trade needs update on stop loss if we are in one
  if (Period()==PERIOD_D1)
  {
     string CommentString;
     CommentString = "Income Generator Active ";
     //see if in a trade and the the check for an activator has not already been made.
     if (TradeTicket==0 && CurrentBarTimeStamp !=Time[0]) 
     {
         //set that the check has been made for an activator last bar.
         CurrentBarTimeStamp = Time[0];
         //fetch everything needed for calculations
         EMALong = iMA(NULL,0, PeriodSlow, 0, MODE_EMA, PRICE_CLOSE,1);
         EMAShort = iMA(NULL,0, PeriodFast, 0, MODE_EMA, PRICE_CLOSE,1);
         FirstUpperEma = (1+Envelope1/100)*EMAShort;
         SecondUpperEma = (1+Envelope2/100)*EMAShort;
         FirstLowerEma = (1-Envelope1/100)*EMAShort;
         SecondLowerEma = (1-Envelope2/100)*EMAShort;
         //See if yesterday was a valid activator and set flag to see if entry happens and work out trade conditions
         double StopLossPips;
         if ( EMALong < EMAShort && High[1] < FirstUpperEma && Low[1] > SecondLowerEma && Close[1]<Open[1])
         {
            ValidActivatorLong = true;
            BuyEntryPrice = High[1] + (EntryBuffer * PipPoint(Symbol()));
            //have to work out the StopLoss first
            double BuyStopLoss = Low[1] - (StopLossBuffer * PipPoint(Symbol()));
            //now work out the total pips between current price and the stop
            StopLoss = MathAbs(BuyEntryPrice-BuyStopLoss)/PipPoint(Symbol());
            Lots = CalcLots (Symbol(), AccountRisk, StopLoss, AccountEquity(), FixedLotSize);
         }
      }
      //check if valid activator has been set and if so check price for an entry
      if (ValidActivatorLong && TradeTicket==0 && Ask > BuyEntryPrice)
         TradeTicket = OpenMarketBuy(Symbol(), Lots, Slippage, MagicNumber, StopLoss, TakeProfit);
      //check to see if the trade was stopped out and if so clear ticket number
      if (!OrderSelect(TradeTicket,SELECT_BY_TICKET) && TradeTicket > 0)
      {
         ValidActivatorLong=false;  //no order present, so set variables to start checks again
         CurrentBarTimeStamp=0;     //force re-check of activator Bar
         TradeTicket=0;             //no more trade ticket, it will have closed on stop
         Print("Ticket Not applicable anymore");
      }
      //put a little status info on the screen
      CommentString = StringConcatenate(CommentString, "\nLots=",Lots,"\nStopLoss=",
            StopLoss,"\nTicket=",TradeTicket);
      Comment(CommentString);
   }
   return(0);
  }

All runs well until a trade happens, and then that trades gets stopped out, and the trade ticket does not clear in the section of code that checks to see if it can select the trade ticket and that the tradeticket>0. ie it has seen one before.

if (!OrderSelect(TradeTicket,SELECT_BY_TICKET) && TradeTicket > 0)

So in other words see if the trade was closed due to other reasons, such as a stop, and if so start checking for activator bars again.

This is the EURUSD data from forextester, and it can be seen that the comment has not updated to show that the ticket has been cleared, so it seems the orderselect is still returning a true but the trade has been stopped out.

Does anybody spot anything here?

Another more important question: Does it seem like I am going about this in the correct way, or should I swap back to pending orders?

Any comments much appreciated

Cheers

 
midworld08:


So in other words see if the trade was closed due to other reasons, such as a stop, and if so start checking for activator bars again.

This is the EURUSD data from forextester, and it can be seen that the comment has not updated to show that the ticket has been cleared, so it seems the orderselect is still returning a true but the trade has been stopped out.

Does anybody spot anything here?

Does OpenMarketBuy return the Ticket number or the Position number ? looks like it's the Position number, if it is then this is wrong . . .

if (!OrderSelect(TradeTicket,SELECT_BY_TICKET) && TradeTicket > 0)

if you use the Position number and you are looking at closed trades you need to use . . .

if (!OrderSelect(TradeTicket,SELECT_BY_TICKET,MODE_HISTORY) && TradeTicket > 0)
 

No OpenMarketbuy returns ticket number. Sorry forgot about the include file, I've only recently graduated to separating out the commonly used functions of EA's.

int OpenMarketBuy(string TradeSymbol, double TradeLots, int TradeSlippage, int TradeMagicNumber, int TradeStopLoss, int TradeTakeProfit)
{
   while (IsTradeContextBusy())  //chill for a moment if context is busy
      Sleep(50);
   int Ticket = OrderSend(TradeSymbol, OP_BUY, TradeLots, MarketInfo(TradeSymbol,MODE_ASK), 
      TradeSlippage, 0, 0, "Buy Order", TradeMagicNumber,0, Green);
   if (Ticket < 0)
   {
      Print("OrderSend failed with error #", GetLastError());
      Ticket=0;
   }
   else     //now enter in the SL and TP via OrderModify to make compatible with ECN broker
   {
      if (OrderSelect(Ticket, SELECT_BY_TICKET))
      {
         while (IsTradeContextBusy())  //chill for a moment if context is busy
            { Sleep(50); }
         if (TradeStopLoss > 0) double BuyStopLoss = MarketInfo(TradeSymbol,MODE_ASK) - (TradeStopLoss * PipPoint(TradeSymbol));    //work out the stop loss
         if (TradeTakeProfit > 0) double BuyTP = MarketInfo(TradeSymbol,MODE_ASK) + (TradeTakeProfit * PipPoint(TradeSymbol));      //work out the take profit
         if (!OrderModify(Ticket, MarketInfo(TradeSymbol,MODE_ASK), BuyStopLoss, BuyTP, 0, Green)) 
            Print("OrderModify failed with error #", GetLastError());
      }
      else { Print("Could not select Buy order"); }
   }
   return(Ticket);
 

OK I think I found it after looking at OrderSelect after seeing your comment on history, I never realised you could select trades out of the history. I assumed once they closed you could not select them. Updating the code to check the close time fixed it;

if (TradeTicket>0 && OrderSelect(TradeTicket,SELECT_BY_TICKET))  //select the ticket of the trade, if one exists
      {
         if (OrderCloseTime()>0)
         {
            ValidActivatorLong=false;  //no order present, so set variables to start checks again
            CurrentBarTimeStamp=0;     //force re-check of activator Bar
            TradeTicket=0;             //no more trade ticket, it will have closed on stop
            Print("Ticket Not applicable anymore");
         }
      }

Thanks for looking at it, I've spent quite some time trying to nut this one.

 
Your screen grab shows Ticket = 1 which suggests that it is the Position number . . ?
 
midworld08:
No OpenMarketbuy returns ticket number. Sorry forgot about the include file, I've only recently graduated to separating out the commonly used functions of EA's.
   if (Ticket < 0)
   {
      ...
   }
   else     //now enter in the SL and TP via OrderModify to make compatible with ECN broker
   {
      if (OrderSelect(Ticket, SELECT_BY_TICKET))
      {
With this pattern you'll find you'll get very indented code. Unnecessary
   if (Ticket < 0)
   {
      ..
   }
   //now enter in the SL and TP via OrderModify to make compatible with ECN broker
   else /*{*/if (OrderSelect(Ticket, SELECT_BY_TICKET))
   {
      ..
   }
   else { Print("Could not select Buy order"); }
/*   }*/
   return(Ticket);
 
midworld08:
OK I think I found it after looking at OrderSelect after seeing your comment on history, I never realised you could select trades out of the history. I assumed once they closed you could not select them. Updating the code to check the close time fixed it;
if (TradeTicket>0 && OrderSelect(TradeTicket,SELECT_BY_TICKET))  //select the ticket of the trade, if one exists
      {
         if (OrderCloseTime()>0)
  1. If the orderSelect succeeds, OrderCloseTime will ALWAYS be zero since the order is open. Once the order closes, OrderSelect will ALWAYS fail.
  2. You are NOT selecting out of history, that's the open order list.
  3.     static datetime lastClose;  
        for(int pos=0; pos < OrdersHistoryTotal(); pos++) if (
            OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY)   // Only orders w/
        &&  OrderCloseTime()    > lastClose                 // not yet processed,
        &&  OrderMagicNumber()  == magic.number             // my magic number
        &&  OrderSymbol()       == Symbol()                 // and my pair.
        &&  OrderType()         <= OP_SELL){// Avoid cr/bal https://www.mql5.com/en/forum/126192
            lastClose = OrderCloseTime();
    

 

@WHRoeder Your comments in 1 and 2 are contrary to how the code is actually behaving??? Before I was trying to find out if an order had been closed on stop, so the EA could then check for another activator bar. The line;

if (!OrderSelect(TradeTicket,SELECT_BY_TICKET) && TradeTicket > 0)

Would never enter and process the commands of the if statement and I always had the situation that the EA would perform 1 trade which got stopped out. Which means the OrderSelect always found the ticket number, as I knew TradeTicket had a value. Turned out this was the first trade it did, so it never traded again. Which to me means that you can select an order out of history with the ticket number, that has been closed, which I didn't think was the case. Looking at the OrderSelect help it does say ;

"To find out from what list the order has been selected, its close time must be analyzed. If the order close time equals to 0, the order is open or pending and taken from the terminal open positions list. ...... If the order close time does not equal to 0, the order is a closed order or a deleted pending order and was selected from the terminal history."

So it seems 2 lists are maintained and OrderSelect does return true for a closed order in the history, as well as an Open order using the Ticket number selection method.

I must admit the help is a little broken, and I thought those comments only meant that you were dealing with using the history pool parameter as a sentence before what I have pasted makes it a little misleading. Don't get me wrong I'm not trying to argue here, I really want to get to the bottom of it and your comments are much appreciated.

Thanks for the comments on formatting. I've just adopted a style that makes it easily readable, as my C++ has been self taught, and I've seen easily a dozen different ways of doing indenting, but I'll give it a try.

@Raptor - For some reason when I run the Strategy tester it always makes the first trade no. 1. I'm using the default MT4, not from a broker, if I run the same EA in my broker MT4 it does not return 1 for the first trade. I think its because this MT4 has not done any other trades, except in the Strategy tester. Either way it makes it nice for tracking the trades :)

Reason: