How can I add a signal to enter/exit trades on this indicator?

 

Hello everyone!

How can I add signal/buffer to this indicator to open and exit trades? I tried to add another buffer and read it, but I get numbers like "2.3454682334345 e-308" or just 0.

 
Pedro Severin:

Hello everyone!

How can I add signal/buffer to this indicator to open and exit trades? I tried to add another buffer and read it, but I get numbers like "2.3454682334345 e-308" or just 0.

Perhaps you could post the code where you've made the changes? That way people here will be better able to help...

 
Seng Joo Thio:

Perhaps you could post the code where you've made the changes? That way people here will be better able to help...

Hi Seng,

Sure...But I didn't change much of it. I will put it in yellow background for easier understanding. This is the full code, which can be found in the codebase.

My idea was to add a buffer that can give me a signal when the indicator generates signals. I also ran the indicator in backtest mode to see how many signals the indicator gives itself in 3 years (used the daily chart) and surprisingly it gave like 3-4 signals.

Any idea why?


//+------------------------------------------------------------------+
//|                                       Waddah_Attar_Explosion.mq4 |
//|                              Copyright © 2006, Eng. Waddah Attar |
//|                                          waddahattar@hotmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, Eng. Waddah Attar"
#property link "waddahattar@hotmail.com" 
//---- indicator version
#property version   "1.00"
//---- drawing the indicator in a separate window
#property indicator_separate_window 
//---- number of indicator buffers 4
#property indicator_buffers 5
 
//---- only three plots are used
#property indicator_plots   3
//+-----------------------------------+
//|  Indicator drawing parameters     |
//+-----------------------------------+
//---- drawing the indicator as a three-color histogram
#property indicator_type1 DRAW_COLOR_HISTOGRAM
//---- Gray, Lime and Magenta colors are used for the three-color histogram
#property indicator_color1 clrGray,clrLime,clrRed
//---- indicator line is a solid one
#property indicator_style1 STYLE_SOLID
//---- indicator line width is equal to 2
#property indicator_width1 2
//---- displaying the indicator label
#property indicator_label1 "MACD"

//---- drawing the indicator as a line
#property indicator_type2 DRAW_LINE
//---- use blue color for the line
#property indicator_color2 Blue
//---- indicator line is a solid curve
#property indicator_style2 STYLE_SOLID
//---- indicator line width is equal to 2
#property indicator_width2 2
//---- displaying the signal line label
#property indicator_label2  "Signal Line"

//---- drawing the indicator as a line
#property indicator_type3 DRAW_LINE
//---- use red color for the line
#property indicator_color3 clrGold
//---- the indicator line is a dash-dotted curve
#property indicator_style3 STYLE_DASHDOTDOT
//---- indicator line width is equal to 1
#property indicator_width3 1
//---- displaying the signal line
#property indicator_label3  "DeadZonePip Level"

#property  indicator_minimum 0.0
//+------------------------------------+
//|  Indicator input parameters        |
//+------------------------------------+
input int Fast_MA = 20;       // Period of the fast MACD moving average
input int Slow_MA = 40;       // Period of the slow MACD moving average
input int BBPeriod=20;        // Bollinger period
input double BBDeviation=2.0; // Number of Bollinger deviations
input int  Sensetive=150;
input int  DeadZonePip=400;
input int  ExplosionPower=15;
input int  TrendPower=150;
input bool AlertWindow=false;
input int  AlertCount=2;
input bool AlertLong=false;
input bool AlertShort=false;
input bool AlertExitLong=false;
input bool AlertExitShort=false;
//+-----------------------------------+
//---- declaration of the integer variables for the start of data calculation
int min_rates_total;
//---- declaration of integer variables for the indicators handles
int MACD_Handle,BB_Handle;
//---- declaration of global variables
double bask,bbid;
int LastTime1,LastTime2,LastTime3,LastTime4,Status,PrevStatus;
//---- declaration of dynamic arrays that
//---- will be used as indicator buffers
double IndBuffer1[],ColorIndBuffer1[],IndBuffer2[],IndBuffer3[];
double signalTrades[];
//+------------------------------------------------------------------+    
//| MACD indicator initialization function                           | 
//+------------------------------------------------------------------+  
void OnInit()
  {
//---- initialization of variables of the start of data calculation
   min_rates_total=BBPeriod+1;
//---- initialization of variables
   LastTime1=1;
   LastTime2=1;
   LastTime3=1;
   LastTime4=1;
   Status=0;
   PrevStatus=-1;
//---- getting handle of the iMACD indicator
   MACD_Handle=iMACD(NULL,0,Fast_MA,Slow_MA,9,PRICE_CLOSE);
   if(MACD_Handle==INVALID_HANDLE)Print(" Failed to get handle of the iMACD indicator");
//---- getting handle of the iBands indicator
   BB_Handle=iBands(NULL,0,BBPeriod,0,BBDeviation,PRICE_CLOSE);
   if(BB_Handle==INVALID_HANDLE)Print(" Failed to get handle of the iBands indicator");

//---- set IndBuffer1[] dynamic array as an indicator buffer
   SetIndexBuffer(0,IndBuffer1,INDICATOR_DATA);
//---- performing the shift of the beginning of the indicator drawing
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- setting the indicator values that won't be visible on a chart
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//---- indexing the elements in buffers as timeseries   
   ArraySetAsSeries(IndBuffer1,true);

//---- set ColorIndBuffer1[] as a colored index buffer   
   SetIndexBuffer(1,ColorIndBuffer1,INDICATOR_COLOR_INDEX);
//---- performing the shift of the beginning of the indicator drawing
   PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,min_rates_total);
//---- indexing the elements in buffers as timeseries   
   ArraySetAsSeries(ColorIndBuffer1,true);

//---- set IndBuffer2[] as an indicator buffer
   SetIndexBuffer(2,IndBuffer2,INDICATOR_DATA);
//---- performing the shift of the beginning of the indicator drawing
   PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,min_rates_total);
//---- setting the indicator values that won't be visible on a chart
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0.0);
//---- indexing the elements in buffers as timeseries   
   ArraySetAsSeries(IndBuffer2,true);

//---- set IndBuffer3[] as an indicator buffer
   SetIndexBuffer(3,IndBuffer3,INDICATOR_DATA);
//---- performing the shift of the beginning of the indicator drawing
   PlotIndexSetInteger(3,PLOT_DRAW_BEGIN,min_rates_total);
//---- setting the indicator values that won't be visible on a chart
   PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,0.0);
//---- indexing the elements in buffers as timeseries   
   ArraySetAsSeries(IndBuffer3,true);
   
   SetIndexBuffer(4,signalTrades);
   ArraySetAsSeries(signalTrades,true);

//---- creating a name for displaying in a separate sub-window and in a tooltip
   IndicatorSetString(INDICATOR_SHORTNAME,"Waddah Attar Explosion");
//---- determination of accuracy of displaying the indicator values
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
//---- initialization end
  }
//+------------------------------------------------------------------+  
//| MACD iteration function                                          | 
//+------------------------------------------------------------------+  
int OnCalculate(const int rates_total,     // number of bars in history at the current tick
                const int prev_calculated, // number of bars calculated at previous call
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---- checking the number of bars to be enough for the calculation
   if(BarsCalculated(MACD_Handle)<rates_total
      || BarsCalculated(BB_Handle)<rates_total
      || rates_total<min_rates_total)
      return(0);
//---- declarations of local variables 
   int limit,to_copy,bar;
   double MACD[],BandsUp[],BandsDn[];
   double Trend1,Trend2,Explo1,Explo2,Dead;
   double pwrt,pwre,Ask,Bid;
   string SirName;
//---- indexing elements in arrays as timeseries  
   ArraySetAsSeries(spread,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(MACD,true);
   ArraySetAsSeries(BandsUp,true);
   ArraySetAsSeries(BandsDn,true);
   
//---- calculation of the 'first' starting index for the bars recalculation loop
   if(prev_calculated>rates_total || prev_calculated<=0) // checking for the first start of the indicator calculation
     {
      limit=rates_total-min_rates_total-1; // starting index for calculation of all bars
     }
   else
     {
      limit=rates_total-prev_calculated;   // starting index for calculation of new bars
     }

   to_copy=limit+2;
//--- copy newly appeared data in the arrays
   if(CopyBuffer(BB_Handle,1,0,to_copy,BandsUp)<=0) return(0);
   if(CopyBuffer(BB_Handle,2,0,to_copy,BandsDn)<=0) return(0);
   to_copy+=2;
   if(CopyBuffer(MACD_Handle,0,0,to_copy,MACD)<=0) return(0);

//---- main indicator calculation loop
   for(bar=limit; bar>=0; bar--)
     {
      Trend1=(MACD[bar] - MACD[bar+1])*Sensetive;
      Trend2=(MACD[bar+2] - MACD[bar+3])*Sensetive;
      Explo1=BandsUp[bar] - BandsDn[bar];
      Explo2=BandsUp[bar+1] - BandsDn[bar+1];

      Dead=_Point*DeadZonePip;

      IndBuffer1[bar]=MathAbs(Trend1);

      Bid=close[bar];
      Ask=Bid+spread[bar];

      if(Trend1>0) ColorIndBuffer1[bar]=1;
      if(Trend1<0) ColorIndBuffer1[bar]=2;
      IndBuffer2[bar]=Explo1;
      IndBuffer3[bar]=Dead;
      if(bar==0)
        {
         if(Trend1>0 && Trend1>Explo1 && Trend1>Dead && 
            Explo1>Dead && Explo1>Explo2 && Trend1>Trend2 && 
            LastTime1<AlertCount && AlertLong==true && Ask!=bask)
           {
            pwrt=100*(Trend1 - Trend2)/Trend1;
            pwre=100*(Explo1 - Explo2)/Explo1;
            bask=Ask;
            if(pwre>=ExplosionPower && pwrt>=TrendPower)
              {
              signalTrades[0]=1.0;
             
               SirName="";
               StringConcatenate(SirName,LastTime1,"- ",Symbol()," - BUY "," (",
                                 DoubleToString(bask,_Digits),") Trend PWR ",
                                 DoubleToString(pwrt,0)," - Exp PWR ",DoubleToString(pwre,0));

               if(AlertWindow==true) Alert(SirName);
               else                  Print(SirName);

               LastTime1++;
              }
            Status=1;
           }
         if(Trend1<0 && MathAbs(Trend1)>Explo1 && MathAbs(Trend1)>Dead && 
            Explo1>Dead && Explo1>Explo2 && MathAbs(Trend1)>MathAbs(Trend2) && 
            LastTime2<AlertCount && AlertShort==true && Bid!=bbid)
           {
            pwrt=100*(MathAbs(Trend1) - MathAbs(Trend2))/MathAbs(Trend1);
            pwre=100*(Explo1 - Explo2)/Explo1;
            bbid=Bid;
            if(pwre>=ExplosionPower && pwrt>=TrendPower)
              {
              signalTrades[0]=2.0;
               SirName="";
               StringConcatenate(SirName,LastTime2,"- ",Symbol()," - Sell "," (",
                                 DoubleToString(bask,_Digits),") Trend PWR ",
                                 DoubleToString(pwrt,0)," - Exp PWR ",DoubleToString(pwre,0));

               if(AlertWindow==true) Alert(SirName);
               else                  Print(SirName);

               LastTime2++;
              }

            Status=2;
           }
         if(Trend1>0 && Trend1<Explo1 && Trend1<Trend2 && Trend2>Explo2 && 
            Trend1>Dead && Explo1>Dead && LastTime3<=AlertCount && 
            AlertExitLong==true && Bid!=bbid)
           {
            bbid=Bid;
            SirName="";
            StringConcatenate(SirName,LastTime3,"- ",Symbol()," - Exit BUY "," ",DoubleToString(bbid,_Digits));
            signalTrades[0]=-1.0;
            
            if(AlertWindow==true) Alert(SirName);
            else                  Print(SirName);

            Status=3;
            LastTime3++;
           }
         if(Trend1<0 && MathAbs(Trend1)<Explo1 && 
            MathAbs(Trend1)<MathAbs(Trend2) && MathAbs(Trend2)>Explo2 && 
            Trend1>Dead && Explo1>Dead && LastTime4<=AlertCount && 
            AlertExitShort==true && Ask!=bask)
           {
            bask=Ask;
            SirName="";
            StringConcatenate(SirName,LastTime4,"- ",Symbol()," - Exit SELL "," ",DoubleToString(bask,_Digits));
            signalTrades[0]=-2.0;
            if(AlertWindow==true) Alert(SirName);
            else                  Print(SirName);

            Status=4;
            LastTime4++;
           }
         PrevStatus=Status;
        }
      if(Status!=PrevStatus)
        {
         LastTime1=1;
         LastTime2=1;
         LastTime3=1;
         LastTime4=1;
        }
     }
//----     
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
Pedro Severin:

Hi Seng,

Sure...But I didn't change much of it. I will put it in yellow background for easier understanding. This is the full code, which can be found in the codebase.

My idea was to add a buffer that can give me a signal when the indicator generates signals. I also ran the indicator in backtest mode to see how many signals the indicator gives itself in 3 years (used the daily chart) and surprisingly it gave like 3-4 signals.

Any idea why?


Ok, I did some tests, and found that 

   SetIndexBuffer(4,signalTrades);
   ArraySetAsSeries(signalTrades,true);

should be changed to:

   SetIndexBuffer(4,signalTrades,INDICATOR_CALCULATIONS);
   PlotIndexSetInteger(4,PLOT_SHOW_DATA,false);
   ArraySetAsSeries(signalTrades,true);

before I'm able to retrieve the values of signalTrades in my test EA.

Next, I realised I need to set these flags to true for signalTrades to be filled:

input bool AlertLong=true;
input bool AlertShort=true;
input bool AlertExitLong=true;
input bool AlertExitShort=true;

Lastly, you're right that signals are rare, but you can lower the values of DeadZonePip, ExplosionPower and TrendPower to get more signals.

 
Seng Joo Thio:

Ok, I did some tests, and found that 

should be changed to:

before I'm able to retrieve the values of signalTrades in my test EA.

Next, I realised I need to set these flags to true for signalTrades to be filled:

Lastly, you're right that signals are rare, but you can lower the values of DeadZonePip, ExplosionPower and TrendPower to get more signals.

Thank you Seng!

It worked in someway, but for some reason if I run a backtest from, lets say 2011 up to now, I get like 2-3 signals.

Then if I run the same test but this time from 2019 up to now, I get only 2 signals.

This happens even if I try backtesting the pure indicator. I'm backtesting in OHLC mode to save some time.

This is how I'm getting the signal from the buffer.


int wae()
  {

   CopyBuffer(wHandle,4,0,1,wSignal2);     //signal buffer

   if(wSignal2[0]==1) return 1; //buy
   if(wSignal2[0]==2) return 2; //sell
   if(wSignal2[0]==-1) return -1; //exit buy
   if(wSignal2[0]==-2) return -2; //exit sell

   return 0;
  }


I also changed the default parameters to some lower ones that can give me more signals, but it does not seems to work in backtest.

Its like in backtest, when it gives the first signal, it remains "trapped" in some point. I checked the code of the indicator, but couldn't figure it out.

Any idea why this happens?

 

In fact, I don't know if the indicator is ment to give signals everytime the bars goes over the line, but I would like to use this like a volume indicator/exit indicator (I think its designed for volume, but honstly I think it shows entry points and exits pretty well)

How can I incorporate this into an EA? Maybe just putting the logic of the indicator as a function?

 
Pedro Severin:

Thank you Seng!

It worked in someway, but for some reason if I run a backtest from, lets say 2011 up to now, I get like 2-3 signals.

Then if I run the same test but this time from 2019 up to now, I get only 2 signals.

This happens even if I try backtesting the pure indicator. I'm backtesting in OHLC mode to save some time.

This is how I'm getting the signal from the buffer.



I also changed the default parameters to some lower ones that can give me more signals, but it does not seems to work in backtest.

Its like in backtest, when it gives the first signal, it remains "trapped" in some point. I checked the code of the indicator, but couldn't figure it out.

Any idea why this happens?

You're right. The problem lies with these status flags:

int LastTime1,LastTime2,LastTime3,LastTime4,Status,PrevStatus;

Looking at the code, I seriously think that they were not being set/reset properly. E.g. "PrevStatus=Status;" must not be called right after the 4 big 'ifs' that checks the open/close conditions. So that is likely the direction you should head towards in checking through the execution.

 
Pedro Severin:

In fact, I don't know if the indicator is ment to give signals everytime the bars goes over the line, but I would like to use this like a volume indicator/exit indicator (I think its designed for volume, but honstly I think it shows entry points and exits pretty well)

How can I incorporate this into an EA? Maybe just putting the logic of the indicator as a function?

It can be done, just remove all indicator-specific lines and group the remaining lines into a function in your EA. May not be necessary to debug the status flags issues if you're going to EA path, because in EA, you'll have access to other means to check order/trade status.

 
Seng Joo Thio:

It can be done, just remove all indicator-specific lines and group the remaining lines into a function in your EA. May not be necessary to debug the status flags issues if you're going to EA path, because in EA, you'll have access to other means to check order/trade status.

Hmm I see...so the status thing is messing around.

What do you think of this? All buffer arrays are set as series.

I want to use this indicator as exit indicator, but it seems that it can be a good entry/volume indicator too. Thoughts?

int wae()
  {
   CopyBuffer(macdHandle,0,0,6,macd);
   CopyBuffer(bbHandle,1,0,6,bbUp);
   CopyBuffer(bbHandle,2,0,6,bbDown);

   double Trend1=(macd[0]-macd[1])*Sensetive;
   double Trend2=(macd[2] - macd[3])*Sensetive;
   double Explo1=bbUp[0] - bbDown[0];
   double Explo2=bbUp[1] - bbDown[1];
   Ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   Bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   double pwrt,pwre;

   double Dead=_Point*DeadZonePip;

   int retVal=0;

   if(Trend1>0 && Trend1>Explo1 && Trend1>Dead && 
      Explo1>Dead && Explo1>Explo2 && Trend1>Trend2 && 
      Ask!=bask)
     {
      pwrt=100*(Trend1 - Trend2)/Trend1;
      pwre=100*(Explo1 - Explo2)/Explo1;
      bask=Ask;
      if(pwre>=ExplosionPower && pwrt>=TrendPower)
        {
         retVal=1;//BUY
         
        }
      }
   if(Trend1<0 && MathAbs(Trend1)>Explo1 && MathAbs(Trend1)>Dead && 
      Explo1>Dead && Explo1>Explo2 && MathAbs(Trend1)>MathAbs(Trend2) && 
      Bid!=bbid)
     {
      pwrt=100*(MathAbs(Trend1) - MathAbs(Trend2))/MathAbs(Trend1);
      pwre=100*(Explo1 - Explo2)/Explo1;
      bbid=Bid;
      if(pwre>=ExplosionPower && pwrt>=TrendPower)
        {
         retVal=2;//SELL
                   
        }
     }
   if(Trend1>0 && Trend1<Explo1 && Trend1<Trend2 && Trend2>Explo2 && 
      Trend1>Dead && Explo1>Dead && Bid!=bbid)
     {
      bbid=Bid;
      retVal=-1;//Exit BUY
               
     }
   if(Trend1<0 && MathAbs(Trend1)<Explo1 && 
      MathAbs(Trend1)<MathAbs(Trend2) && MathAbs(Trend2)>Explo2 && 
      Trend1>Dead && Explo1>Dead && Ask!=bask)
     {
      bask=Ask;
      retVal=-2;//Exit SELL
     }

   return retVal;
  }
 
Pedro Severin:

Hmm I see...so the status thing is messing around.

What do you think of this? All buffer arrays are set as series.

I want to use this indicator as exit indicator, but it seems that it can be a good entry/volume indicator too. Thoughts?

I think you're almost done :). Here're my thoughts:

- Consider looking from bar 1 onwards, not 0... because 0 refers to the current bar, and will still change before the the next bar. So i would change all my references to macd, bbup, bbdown to use their indexes from 1 onwards.

- I won't call wae every tick. instead, i'll keep track of the latest bar start time, to make sure that i call wae only when the bar changes.

static datetime latestbartime = 0;

if (latestbartime<iTime(NULL,0,0))
{
   // call wae
   latestbartime = iTime(NULL,0,0);
}

- There is probably no need for bbid and bask anymore.

 
Seng Joo Thio:

I think you're almost done :). Here're my thoughts:

- Consider looking from bar 1 onwards, not 0... because 0 refers to the current bar, and will still change before the the next bar. So i would change all my references to macd, bbup, bbdown to use their indexes from 1 onwards.

- I won't call wae every tick. instead, i'll keep track of the latest bar start time, to make sure that i call wae only when the bar changes.

- There is probably no need for bbid and bask anymore.

Like this?


int wae()
  {
   CopyBuffer(macdHandle,0,0,6,macd);
   CopyBuffer(bbHandle,1,0,6,bbUp);
   CopyBuffer(bbHandle,2,0,6,bbDown);

   double Trend1=(macd[1]-macd[2])*Sensetive;
   double Trend2=(macd[3] - macd[4])*Sensetive;
   double Explo1=bbUp[1] - bbDown[1];
   double Explo2=bbUp[2] - bbDown[2];
   //Ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   //Bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   double pwrt,pwre;

   double Dead=_Point*DeadZonePip;

   int retVal=0;

   if(Trend1>0 && Trend1>Explo1 && Trend1>Dead && 
      Explo1>Dead && Explo1>Explo2 && Trend1>Trend2 && 
      /*Ask!=bask*/)
     {
      pwrt=100*(Trend1 - Trend2)/Trend1;
      pwre=100*(Explo1 - Explo2)/Explo1;
      //bask=Ask;
      if(pwre>=ExplosionPower && pwrt>=TrendPower)
        {
         retVal=1;//BUY
         
        }
      }
   if(Trend1<0 && MathAbs(Trend1)>Explo1 && MathAbs(Trend1)>Dead && 
      Explo1>Dead && Explo1>Explo2 && MathAbs(Trend1)>MathAbs(Trend2) /*&& 
      Bid!=bbid*/)
     {
      pwrt=100*(MathAbs(Trend1) - MathAbs(Trend2))/MathAbs(Trend1);
      pwre=100*(Explo1 - Explo2)/Explo1;
      //bbid=Bid;
      if(pwre>=ExplosionPower && pwrt>=TrendPower)
        {
         retVal=2;//SELL
                   
        }
     }
   if(Trend1>0 && Trend1<Explo1 && Trend1<Trend2 && Trend2>Explo2 && 
      Trend1>Dead && Explo1>Dead /*&& Bid!=bbid*/)
     {
      //bbid=Bid;
      retVal=-1;//Exit BUY
               
     }
   if(Trend1<0 && MathAbs(Trend1)<Explo1 && 
      MathAbs(Trend1)<MathAbs(Trend2) && MathAbs(Trend2)>Explo2 && 
      Trend1>Dead && Explo1>Dead /*&& Ask!=bask*/)
     {
      //bask=Ask;
      retVal=-2;//Exit SELL
     }

   return retVal;
  }

I used the part that I posted in the last post and got this results, lol:

It seems that, for some reason I have a valid setup to enter, but at the same time it gets wiped out because of wae. Maybe because I was using the current bar 0?

Reason: