Problem with PSAR Trailing Stop EA

 

Hello everyone,


I am quite new to MQL programming, but I am basically reading through every tutorial I can find these days. However, now that I have a version of an EA, I noticed it does not work as anticipated. Right now I have no idea why this is the case, so maybe someone can explain where I went wrong.


Short explanation for how it is supposed to work:

- if TotalOrders = 0, check for Buy/Sell Signals

- if Total Order = 1, move Trailing Stop (which already limits the amount of orders open at the time to 1)


Buy/Sell Signals (I know my code can be shortened quite a bit, but for the start I wanted to keep it as simple as possible):

- if current iSARs are below current opening price --> BUY

- if current iSARs are above current opening price --> SELL

- Filter: Both iSARs in previous period should be opposite (therefore only a change if both iSARs entirely changed)


Problems I ran into:

- EA does not stick to the Buy/Sell signals and seems to "randomly" open orders

- Trailing Stop does not actually put the StopLoss to iSAR value


Picture for the "weird signals":

as you can see it doesn't set the StopLoss on iSAR (see red lines under) and also doesn't follow my filter rules (both iSARs had to change)


Can anybody explain to my why this the case? I'll attach the code below.

Thank you very much!



Code:

//+------------------------------------------------------------------+
//|                                                   PSAR_Trail.mq4 |
//|                                                            Chris |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Chris"
#property version   "1.00"
#property strict

// Global Variables
extern int     MagicNumber    = 0;
extern double  LotSize        = 1.0;
extern int     Slippage       = 10;

// PSAR Variables
extern double  PSAR_Step      = 0.02;
extern double  PSAR_Max       = 0.2;
extern double  PSAR_Step2     = 0.01;
extern double  PSAR_Max2      = 0.1;

// Function declaration
double PSAR = iSAR(NULL,0,PSAR_Step,PSAR_Max,0);
double PSAR_2 = iSAR(NULL,0,PSAR_Step2,PSAR_Max2,0);

// Filter Function
double PSAR_filter_1 = iSAR(NULL,0,PSAR_Step,PSAR_Max,1);
double PSAR_filter_2 = iSAR(NULL,0,PSAR_Step2,PSAR_Max2,1);

bool result=false;
bool ticket=false;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
  int itotal;
  itotal = OrdersTotal();
  
  if(Volume[0]==1)                       // new bar
     if(itotal==1)
        MoveStopsToPSAR();
     if(itotal==0)
        Signals();
  }

// BUY & SELL Functions
void Signals()
  {
  // BUY Function
  if(PSAR<Open[0] && PSAR_2<Open[0])
     {
     if(PSAR_filter_1>Open[1] && PSAR_filter_2>Open[1])
        {
        ticket=OrderSend(Symbol(),OP_BUY,LotSize,Ask,Slippage,NormalizeDouble(PSAR,Digits),0,"BUY",MagicNumber,0,Green);
        }
     }
     
  // SELL Function
  if(PSAR>Open[0] && PSAR_2>Open[0])
     {
     if(PSAR_filter_1<Open[1] && PSAR_filter_2<Open[1])
        {
        ticket=OrderSend(Symbol(),OP_SELL,LotSize,Bid,Slippage,NormalizeDouble(PSAR,Digits),0,"SELL",MagicNumber,0,Red);
        }
     }
  }

// Trailing Stop Loss Function
void MoveStopsToPSAR()
  {
  if(OrderSelect(1,SELECT_BY_POS,MODE_TRADES)==true)
     {
     
     // Move for BUY
     if(OrderType()==OP_BUY)
     {
        if(NormalizeDouble(PSAR,Digits)<Close[1] && NormalizeDouble(PSAR,Digits)!=OrderStopLoss())
           result=OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(PSAR,Digits),OrderTakeProfit(),0,Green);
     }
     
     // Move for SELL
     if(OrderType()==OP_SELL)
     {
        if(NormalizeDouble(PSAR,Digits)>Close[1] && NormalizeDouble(PSAR,Digits)!=OrderStopLoss())
           result=OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(PSAR,Digits),OrderTakeProfit(),0,Red);
     }
     }
  }

 
  1. double PSAR = iSAR(NULL,0,PSAR_Step,PSAR_Max,0);
    double PSAR_2 = iSAR(NULL,0,PSAR_Step2,PSAR_Max2,0);
    
    // Filter Function
    double PSAR_filter_1 = iSAR(NULL,0,PSAR_Step,PSAR_Max,1);
    double PSAR_filter_2 = iSAR(NULL,0,PSAR_Step2,PSAR_Max2,1);
    
    These variables never change. Assign them in your function.

  2. if(Volume[0]==1)                       // new bar
         if(itotal==1)
            MoveStopsToPSAR();
         if(itotal==0)
            Signals();
    
    You have two indented if statements, but only the first one is part of "new bar."
  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 and MetaTrader 4 - MQL4 programming forum.) Always use time.
    I disagree with making a new bar function, because it can only be called once per tick. A variable can be tested multiple times.
              New candle - MQL4 and MetaTrader 4 - MQL4 programming forum

  4. ticket=OrderSend(
    result=OrderModify(
    Check your return codes for errors and report them.
              What are Function return values ? How do I use them ? - MQL4 and MetaTrader 4 - MQL4 programming forum
              Common Errors in MQL4 Programs and How to Avoid Them - MQL4 Articles

  5. if(NormalizeDouble(PSAR,Digits)<Close[1] && NormalizeDouble(PSAR,Digits)!=OrderStopLoss())
    Do NOT use NormalizeDouble, EVER. For ANY Reason. It's a kludge, don't use it. It's use is always wrong

  6. Doubles are rarely equal.
              The == operand. - MQL4 and MetaTrader 4 - MQL4 programming forum

  7. if(OrderSelect(1,SELECT_BY_POS,MODE_TRADES)==true)
    How do you know that the second order in the list is from your EA and on the current chart? Using OrdersTotal directly and/or no Magic number filtering on your OrderSelect loop means your code is incompatible with every EA (including itself on other charts and manual trading.)
              Symbol Doesn't equal Ordersymbol when another currency is added to another seperate chart . - MQL4 and MetaTrader 4 - MQL4 programming forum

  8. You should be able to read your code out loud and have it make sense. You would never write if( (2+2 == 4) == true) would you? if(2+2 == 4) is sufficient. So don't write if(bool == true), just use if(bool) or if(!bool). Code becomes self documenting when you use meaningful variable names, like bool isLongEnabled where as Long_Entry sounds like a trigger price or a ticket number and "if long entry" is an incomplete sentence.
 
whroeder1:
  1. These variables never change. Assign them in your function.

  2. You have two indented if statements, but only the first one is part of "new bar."
  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 and MetaTrader 4 - MQL4 programming forum.) Always use time.
    I disagree with making a new bar function, because it can only be called once per tick. A variable can be tested multiple times.
              New candle - MQL4 and MetaTrader 4 - MQL4 programming forum

  4. Check your return codes for errors and report them.
              What are Function return values ? How do I use them ? - MQL4 and MetaTrader 4 - MQL4 programming forum
              Common Errors in MQL4 Programs and How to Avoid Them - MQL4 Articles

  5. Do NOT use NormalizeDouble, EVER. For ANY Reason. It's a kludge, don't use it. It's use is always wrong

  6. Doubles are rarely equal.
              The == operand. - MQL4 and MetaTrader 4 - MQL4 programming forum

  7. How do you know that the second order in the list is from your EA and on the current chart? Using OrdersTotal directly and/or no Magic number filtering on your OrderSelect loop means your code is incompatible with every EA (including itself on other charts and manual trading.)
              Symbol Doesn't equal Ordersymbol when another currency is added to another seperate chart . - MQL4 and MetaTrader 4 - MQL4 programming forum

  8. You should be able to read your code out loud and have it make sense. You would never write if( (2+2 == 4) == true) would you? if(2+2 == 4) is sufficient. So don't write if(bool == true), just use if(bool) or if(!bool). Code becomes self documenting when you use meaningful variable names, like bool isLongEnabled where as Long_Entry sounds like a trigger price or a ticket number and "if long entry" is an incomplete sentence.

Wow, thank you very much for this comprehensive help! I will work on it some more, but might come back for further questions

Reason: