EA to open position based on consecutive PSAR values

 

Hi there,

I am new to MQL4 programming and came across the following practice problem online: create an EA which checks the previous N = 10 candles and if PSAR is consecutively above than iOpen() for all these N = 10 candles, open a sell position; if PSAR is consecutively below iOpen() for N = 10 candles, open a buy position. Additional external variables are TP and SL pips. 

My approach was to first only focus on one side: the sell branch. I created an infinite while loop that loops from N=0 to N=10 and checks the PSAR and iOpen values for each candle. If PSAR >= iOpen, it increases the count by 1, all the way till N=10. When it's N=10, it opens the sell position. I added an error handling snippet there as well. And in other scenarios (i.e. when one of the previous candles did not meet the PSAR >= iOpen condition), the loop breaks.

However, the code doesn't run as expected. It seems to halt and very strangely, even though I have M1 set in my input, at each run the code seems to gets executed on the default H1 chart. 

Any suggestions would be highly appreciated as I would like to learn more and improve! Thanks a lot for your help. :)

My code currently: 

#include <stdlib.mqh>

enum TimeFrame { M1, M5, M15, H1, H4, D1, W1, MN1 };

input int  TakeProfitPips = 500;
input int  StopLossPips   = 500;
input double PSAR_step    = 0.02;

input  double PSAR_max     = 0.20;
input int    BarsNumber   = 10;
input double Lots         = 0.1;
input TimeFrame currentTF = M1;
int BarsCount;

int OnInit()
  {
   BarsCount = Bars; 
   return(INIT_SUCCEEDED);
  }

void OnTick()
{
   if(Bars > BarsCount) {
      
      int count = 0;
      while(1){
         
         double sar  = iSAR(Symbol(),currentTF,PSAR_step,PSAR_max,count);
         double open = iOpen(Symbol(),currentTF,count);
         
         if(sar >= open && count < BarsNumber) {
            count++;
         }
         else if(count == BarsNumber) {
            int sellticket = OrderSend(Symbol(),OP_SELL,Lots,Bid,3,Bid+StopLossPips*Point,Bid-TakeProfitPips*Point,"20200714",12345,0,Red);
            
            if(sellticket < 0) {  Alert("OrderSend Error: ", GetLastError());                            } 
            else {                Alert("Order Sent Successfully, Ticket # is: " + string(sellticket));  }
         }
         else{
            break;
         }  
      }
   }    
     
  BarsCount = Bars;
  
}
 
I know that it is not obvious, but topics concerning MT4 and MQL4 have their own section.
In future please post in the correct section.
I will move your topic to the MQL4 and Metatrader 4 section.
 
  1. On MT4: Unless the current chart is that specific symbol(s)/TF(s) referenced, you must handle 4066/4073 errors before accessing candle/indicator values.
              Download history in MQL4 EA - Forex Calendar - MQL4 programming forum - Page 3 #26 № 4 2019.05.20

  2. You buy at the Ask and sell at the Bid.

    1. Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using the Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?

    2. Your sell order's TP/SL (or Buy Stop's/Buy Limit's entry) will be triggered when the Ask / OrderClosePrice reaches it. To trigger at a specific Bid price, add the average spread.
                MODE_SPREAD (Paul) - MQL4 programming forum - Page 3 #25

    3. The charts show Bid prices only. Turn on the Ask line to see how big the spread is (Tools → Options (control+O) → charts → Show ask line.)
      Most brokers with variable spread widen considerably at end of day (5 PM ET) ± 30 minutes. My GBPJPY (OANDA) shows average spread = 26 points, but average maximum spread = 134.

  3. For a new bar test, Bars is unreliable (a refresh/reconnect can change number of bars on chart,) volume is unreliable (miss ticks,) Price is unreliable (duplicate prices and The == operand. - MQL4 programming forum.) Always use time.
              New candle - MQL4 programming forum #3 2014.04.04

    I disagree with making a new bar function, because it can only be called once per tick. A variable can be tested multiple times.

 

Hi William,

Thank you for your answer, I appreciate your help and insights! I tried my best to understand your comments. 

Could you please explain this a bit more thoroughly though? I don't understand what you mean here by "unless the current chart is that specific symbol(s)/TF(s) referenced". I specifically passed: currentTF = M1 to my iSAR() and iOpen() functions. What do you mean by the current chart not being the specific symbol referenced? The current chart should be the one I define, i.e. the M1 in this case, shouldn't it?

  • You buy at the Ask and sell at the Bid...

Good point, thank you! So if I'm not mistaken, the correct TP and SL values for a BUY order would be: BuyTP = Bid + 50pips, BuySL = Bid - 50pips, and the correct TP and SL values for a SELL order would be: SellTP = Ask - 50pips, SellSL = Ask + 50pips. Am I on the right track with this?

  • For a new bar test, Bars is unreliable... Always use time.

Very nice, thank you! I replaced Bars and added a new isNewCandle() boolean function to do the trick, based on your suggestion. 

Also, I added a part that checks the total number of orders using the OrdersTotal(). This way, I can make sure one order will get opened at a time. 

My whole code currently looks like this: 

#include <stdlib.mqh>

enum TimeFrame { M1, M5, M15, H1, H4, D1, W1, MN1 };


input int  TakeProfitPips = 500;
input int  StopLossPips   = 500;
input double PSAR_step    = 0.02;
input double PSAR_max     = 0.20;
input char    BarsNumber   = 10;
input double Lots         = 0.01;
input TimeFrame currentTF = M1;

datetime NewCandleTime=TimeCurrent();


// true if this is a new candle, false if still in formation
bool IsNewCandle(){

   if(NewCandleTime==iTime(Symbol(),0,0)) return false;
   
   else {
      NewCandleTime=iTime(Symbol(),0,0);
      return true;
   }
}

int OnInit()
  {
   return(INIT_SUCCEEDED);
  }

void OnTick()
{
   if(IsNewCandle()) {   
      int count = 0;
      while(1){
         
         double sar  = iSAR(Symbol(),currentTF,PSAR_step,PSAR_max,count);
         double open = iOpen(Symbol(),currentTF,count);
         
         if(sar >= open && count < BarsNumber) {
            count++;
         }
         else if(count == BarsNumber) {
            if(OrdersTotal() == 0) {
               int sellticket = OrderSend(Symbol(),OP_SELL,Lots,Bid,3,Ask+StopLossPips*Point,Ask-TakeProfitPips*Point,"akukaya-2009-05-03",12345,0,Red);
               
               if(sellticket < 0) {  Alert("OrderSend Error: ", GetLastError());                            } 
               else {                Alert("Order Sent Successfully, Ticket # is: " + string(sellticket));  }
            }
         }
         else{
            break;
         }  
      }
   }
}

However, the program still halts when I want to try it on the strategy tester. The first sell position opens and the tester stops and doesn't run any more. There is no error message in the Journal, I get the "Order Sent Successfully" alert with the ticket number. I am puzzled as to how to make this EA work. Could you please advise? 

 

Also, as a last note, just out of curiosity: Are you sure you meant to write this comment too? 

  • "I disagree with making a new bar function, because it can only be called once per tick. A variable can be tested multiple times."
I didn't have any "new bar function", nor did I mention wanting to write one, so I am not really sure what you wanted to say with this. :)
 
  1. Levente Csibi: I don't understand what you mean here by "unless the current chart is that specific symbol(s)/TF(s) referenced". I specifically passed: currentTF = M1 

    You are running on the H1. The M1 is not your specific TF. What is not understandable to you?

  2. Levente Csibi: Also, as a last note, just out of curiosity: Are you sure you meant to write this comment too? 

    • "I disagree with making a new bar function, because it can only be called once per tick. A variable can be tested multiple times."
    I didn't have any "new bar function", nor did I mention wanting to write one, so I am not really sure what you wanted to say with this. :)
    Absolutely. You didn't have one initially. You added it. You've been warned about a problem.
 
William RoederWhat is not understandable to you?

I don't understand why my EA is run on the H1 if I specified that I want to operate with M1 data using my currentTF enum value.

Furthermore, I don't understand how can I handle the 4066/4073 errors mentioned by you if I don't have these errors popping up when running the above code. Which line would throw these errors?  

 
So, William Roeder? What did you mean?
Reason: