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?
This website uses cookies. Learn more about our Cookies Policy.