Try to merge a Moving Average with CCI (alternative)

 

I noticed that a MA and a CCI indicator gives some interesting early VISUAL signals if displayed in the same window, but the crossing lines have completely different scales and values. So I got this naive idea to merge the two and then wanted somehow adapt the different scales and use it in my EA.

I used the code from M. Laden "CCI (alternative)" and added a Moving Average code. Got compiler warning:"two OnCalculate are defined. Price data function will be used". Apparently one cant use OnCalculate twice, but it doesnt allow me to put all const in one OnCalculate() neither.

This is the code:

//+------------------------------------------------------------------
#property copyright   "mladen"
#property link        "mladenfx@gmail.com"
#property link        "https://www.mql5.com"
#property description "CCI (alternative)"
//+------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   2
#property indicator_label1  "CCI alternative RS"
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  clrDarkGray,clrSkyBlue,clrDodgerBlue
#property indicator_width1  2
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrYellow

//--- input parameters
input int inpPeriod=50;  // CCI period
input int InpMA2Shift=0;   // Shift
input int InpMA2Period=13; // Period MA2
//input ENUM_MA_METHOD InpMAMethod=MODE_SMMA;  // Method
input ENUM_MA_METHOD InpMA2Method=MODE_LWMA;  // Method Ma2
//--- buffers and global variables declarations
double val[],valc[],prices[];
double ExtLineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,val,INDICATOR_DATA);
   SetIndexBuffer(1,valc,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,prices,INDICATOR_CALCULATIONS);
//---
   IndicatorSetString(INDICATOR_SHORTNAME,"CCI (alternativeRS)("+(string)inpPeriod+")");
   
   //--- indicator buffers mapping   MA CODE
   SetIndexBuffer(3,ExtLineBuffer,INDICATOR_DATA);
//--- set accuracy
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
//--- set first bar from what index will be drawn
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpMA2Period);
   IndicatorSetString(INDICATOR_SHORTNAME,"CCI LWMA"+"("+string(InpMA2Period)+")");
//--- set drawing line empty value
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   return (INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator de-initialization function                      |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                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[])
                                       
  {
   if(Bars(_Symbol,_Period)<rates_total) return(prev_calculated);

   int i=(int)MathMax(prev_calculated-1,1); for(; i<rates_total && !_StopFlag; i++)
     {
      int _start=MathMax(i-inpPeriod+1,0);
      prices[i]=(high[ArrayMaximum(high,_start,inpPeriod)]+low[ArrayMinimum(low,_start,inpPeriod)]+close[i])/3;
      double avg = 0; for(int k=0; k<inpPeriod && (i-k)>=0; k++) avg +=         prices[i-k];      avg /= inpPeriod;
      double dev = 0; for(int k=0; k<inpPeriod && (i-k)>=0; k++) dev += MathAbs(prices[i-k]-avg); dev /= inpPeriod;

      val[i] = (dev!=0) ? (prices[i]-avg)/(0.015*dev) : 0;
      valc[i]=(i>0) ?(val[i]>val[i-1]) ? 1 :(val[i]<val[i-1]) ? 2 : valc[i-1]: 0;
     }
   return (i);
  } 
 // Ma CODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])     
 
   {  
   
    if(rates_total<InpMA2Period-1+begin)
      return(0);
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
     {
      ArrayInitialize(ExtLineBuffer,0);
      PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpMA2Period-1+begin);
     }  
     {
     CalculateLWMA(rates_total,prev_calculated,begin,price); 
     }
  //--- return value of prev_calculated for next call
   return(rates_total);
   // Ma CODE  
  }  
  
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|  linear weighted moving average                                  |
//+------------------------------------------------------------------+
void CalculateLWMA(int rates_total,int prev_calculated,int begin,const double &price[])
  {
   int    weight=0;
   int    i,l,start;
   double sum=0.0,lsum=0.0;
//--- first calculation or number of bars was changed
   if(prev_calculated<=InpMA2Period+begin+2)
     {
      start=InpMA2Period+begin;
      //--- set empty value for first start bars
      for(i=0; i<start; i++)
         ExtLineBuffer[i]=0.0;
     }
   else
      start=prev_calculated-1;

   for(i=start-InpMA2Period,l=1; i<start; i++,l++)
     {
      sum   +=price[i]*l;
      lsum  +=price[i];
      weight+=l;
     }
   ExtLineBuffer[start-1]=sum/weight;
//--- main loop
   for(i=start; i<rates_total && !IsStopped(); i++)
     {
      sum             =sum-lsum+price[i]*InpMA2Period;
      lsum            =lsum-price[i-InpMA2Period]+price[i];
      ExtLineBuffer[i]=sum/weight;
     }
  }

As I said, it gives only a warning, but compiles. Unfortunately the above "indicator" produces no output, only an empty indicator window when added to a chart. Can it be done at all?  Thanks.

 

The issue with your code is that you have defined two OnCalculate functions. You can only have one OnCalculate function in an MQL4 program. One solution to this problem is to merge the two functions into one.

To merge the two functions, you need to add the Moving Average code to the existing OnCalculate function, which already calculates the CCI indicator. Here's an example of how you can do that:

int OnCalculate(const int rates_total,
                const int prev_calculated,
                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[])
                                       
{
   if(Bars(_Symbol,_Period)<rates_total) return(prev_calculated);

   int i=(int)MathMax(prev_calculated-1,1); for(; i<rates_total && !_StopFlag; i++)
   {
      int _start=MathMax(i-inpPeriod+1,0);
      prices[i]=(high[ArrayMaximum(high,_start,inpPeriod)]+low[ArrayMinimum(low,_start,inpPeriod)]+close[i])/3;
      double avg = 0; for(int k=0; k<inpPeriod && (i-k)>=0; k++) avg +=         prices[i-k];      avg /= inpPeriod;
      double dev = 0; for(int k=0; k<inpPeriod && (i-k)>=0; k++) dev += MathAbs(prices[i-k]-avg); dev /= inpPeriod;

      val[i] = (dev!=0) ? (prices[i]-avg)/(0.015*dev) : 0;
      valc[i]=(i>0) ?(val[i]>val[i-1]) ? 1 :(val[i]<val[i-1]) ? 2 : valc[i-1]: 0;
      
      // Moving Average code
      if (i >= InpMA2Period - 1)
      {
         double sum = 0;
         for (int j = 0; j < InpMA2Period; j++)
         {
            sum += val[i - j];
         }
         ExtLineBuffer[i] = iMA(NULL, 0, InpMA2Period, InpMA2Shift, InpMA2Method, PRICE_CLOSE, i) + sum / InpMA2Period;
      }
      else
      {
         ExtLineBuffer[i] = 0;
      }
   }
   return (i);
}

In this merged OnCalculate function, the CCI indicator calculation is the same as in your original code, and the Moving Average code has been added to it. The Moving Average code calculates the sum of the last InpMA2Period CCI values and the iMA function calculates the Moving Average. The result is stored in the ExtLineBuffer array, which you can use in your EA.

Note that you also need to remove the second OnCalculate function, which is no longer needed.

 
Bogdan Ion Puscasu #:

The issue with your code is that you have defined two OnCalculate functions. You can only have one OnCalculate function in an MQL4 program. One solution to this problem is to merge the two functions into one.

To merge the two functions, you need to add the Moving Average code to the existing OnCalculate function, which already calculates the CCI indicator. Here's an example of how you can do that:

In this merged OnCalculate function, the CCI indicator calculation is the same as in your original code, and the Moving Average code has been added to it. The Moving Average code calculates the sum of the last InpMA2Period CCI values and the iMA function calculates the Moving Average. The result is stored in the ExtLineBuffer array, which you can use in your EA.

Note that you also need to remove the second OnCalculate function, which is no longer needed.

Thank you!  It is an MQL5 indicator.

I cant get it to work, compiler error message "iMA wrong parameter count" and unfortunately your code is over my pay grade.

If I remove the "i" in the iMA it compiles but no plots in the indicator window. The MA is basically only at the zero line.

Probably one should create a SMA  of the CCI values and of the draw the MA on top of the CCI plot.

Thanks again for your help.

 
irinacfd #: Thank you!  It is an MQL5 indicator. I cant get it to work, compiler error message "iMA wrong parameter count" and unfortunately your code is over my pay grade.If I remove the "i" in the iMA it compiles but no plots in the indicator window. The MA is basically only at the zero line.Probably one should draw the MA of the CCI values on top of the CCI plot. Thanks again for your help.
  1. You can't have more than one OnCalculate() event handler (be it MQL5 or MQL4).
  2. Please ignore Post #1 as it is for MQL4 which is not compatible with MQL5.
 
@Bogdan Ion Puscasu #: The issue with your code is that you have defined two OnCalculate functions. You can only have one OnCalculate function in an MQL4 program. One solution to this problem is to merge the two functions into one. To merge the two functions, you need to add the Moving Average code to the existing OnCalculate function, which already calculates the CCI indicator. Here's an example of how you can do that: In this merged OnCalculate function, the CCI indicator calculation is the same as in your original code, and the Moving Average code has been added to it. The Moving Average code calculates the sum of the last InpMA2Period CCI values and the iMA function calculates the Moving Average. The result is stored in the ExtLineBuffer array, which you can use in your EA. Note that you also need to remove the second OnCalculate function, which is no longer needed.
Please do not reply to a question about MQL5 with an answer about MQL4. Your code is not applicable.