My custom indicator has display incorrectly

 

Hi guy, i'm writting a LSMA indicator but it display incorrectly, it work well except the at the first bar.

here is my plot display ***

I find out when i compile the OnCalculate() will be run 2 times, i try to console log the rates_total and prev_calculated and the result is: ***

It lead to this error but i dont know how to fix that, can anyone tell me a way to solve this problem? please, i need your help.

i have attached these images below.

My code below (sorry for my bad English)

#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com"
#property version   "1.00"
#property description "Least Square Moving Average"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   1

#property indicator_label1  "LSMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrViolet
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

//--- indicator buffers
double         BufferLSMA[];
double         BufferMA[];
//--- global variables
int            period_ma;
int            LSMAHandle;

double            L2;
double            LengthVar;
double            FixPeriod;

//--- Enum
enum Applied_price_ { //Type of constant
    PRICE_CLOSE_,        //Close
    PRICE_OPEN_,         //Open
    PRICE_HIGH_,         //High
    PRICE_LOW_,          //Low
    PRICE_MEDIAN_,       //Median Price (HL/2)
    PRICE_TYPICAL_,      //Typical Price (HLC/3)
    PRICE_WEIGHTED_     //Weighted Close (HLCC/4)
};

//--- input parameters
input uint LSMA_Period =  15;            // Period
input Applied_price_ LSMA_Applied_Price = PRICE_CLOSE;   // Applied price

//+------------------------------------------------------------------+
//| Custom i
int OnInit() {
    LSMA();
//---
    return(INIT_SUCCEEDED);
}

void LSMA() {
    period_ma = (int) LSMA_Period;
    LengthVar = (period_ma + 1) / 3.0;
    L2 = period_ma * (period_ma + 1) / 6;
    FixPeriod = period_ma - LengthVar;
    
//--- indicator buffers mapping
    SetIndexBuffer(0, BufferLSMA, INDICATOR_DATA);
    SetIndexBuffer(1, BufferMA, INDICATOR_CALCULATIONS);
    
//--- setting indicator parameters
    IndicatorSetString(INDICATOR_SHORTNAME, "LSMA(" + (string)period_ma + ")");
    IndicatorSetInteger(INDICATOR_DIGITS, Digits());

//--- setting buffer arrays as timeseries
    ArraySetAsSeries(BufferLSMA, true);
    ArraySetAsSeries(BufferMA, true);
    
//--- create MA's handle
    ResetLastError();

    LSMAHandle = iMA(NULL, PERIOD_CURRENT ,1 , 0, MODE_SMA, LSMA_Applied_Price);
    if(LSMAHandle == INVALID_HANDLE) {
        Print("The iMA(1) object was not created: Error ", GetLastError());
    }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    if(LSMAHandle != INVALID_HANDLE) IndicatorRelease(LSMAHandle);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, // amount of history in bars at the current tick
                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[]) {
                
    double sum;           
    int temp = 0;

    if(rates_total < period_ma) return 0;
    if(BarsCalculated(LSMAHandle) < rates_total) return (0);

    
    int limit = rates_total - prev_calculated;
    if(limit > 1) {
        limit = rates_total - period_ma - 1;
        ArrayInitialize(BufferLSMA, EMPTY_VALUE);
        ArrayInitialize(BufferMA, 0);
    }
    
    int copied = 0, count = (limit == 0 ? 1 : rates_total);
    copied = CopyBuffer(LSMAHandle, 0, 0, count, BufferMA);
    if(copied != count) return 0;

    
    for(int i = limit; i >= 0 && !IsStopped(); i--) {
        sum = 0.0;
        
        for(int j = 0; j < period_ma; j++) {
            sum += (FixPeriod - j) * CustomPrice(LSMA_Applied_Price, temp + period_ma - j, open, low, high, close);
        }
        BufferLSMA[i] = sum / L2;
        temp++;
    }
//--- return value of prev_calculated for next call
    return(rates_total);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CustomPrice( uint applied_price, // Price constant
                    uint bar, // Shift index relative to the current bar by a specified number of periods backward or forward).
                    const double &Open[],
                    const double &Low[],
                    const double &High[],
                    const double &Close[]) {
    switch(applied_price) {
    case  PRICE_OPEN:
        return(Open[bar]);
    case  PRICE_HIGH:
        return(High[bar]);
    case  PRICE_LOW:
        return(Low[bar]);
    case  PRICE_MEDIAN:
        return((High[bar] + Low[bar]) / 2.0);
    case  PRICE_TYPICAL:
        return((Close[bar] + High[bar] + Low[bar]) / 3.0);
    case  PRICE_WEIGHTED:
        return((2 * Close[bar]+High[bar]+Low[bar]) / 4.0);
    default: // PRICE_CLOSE_
        return(Close[bar]);
    }
}
//+------------------------------------------------------------------+
 

Please don't use external URLs for adding screenshots. Please re-edit your post and use the Image icon on the toolbar to add images directly to your post.


 

First off, I would like to point out that using just a Simple Moving Average (SMA) is not the correct way to calculate an Least Square Moving Average (LSMA). Using moving averages to calculate Linear Regression is as follows:

You have to use both an SMA and a LWMA to calculate an LSMA end-point ("b = 3 * LWMA - 2 * SMA" in the above image). Someone else also described something similar in the following article (but did not provide all the equations):

So, I have also attached a ZIP file with both a PDF as well as the original MathCAD sheet of my equations showing the proof of how to calculate Linear Regression using only moving averages.


Files:
 
Fernando Carreiro:

First off, I would like to point out that using just a Simple Moving Average (SMA) is not the correct way to calculate an Least Square Moving Average (LSMA). Using moving averages to calculate Linear Regression is as follows:

You have to use both an SMA and a LWMA to calculate an LSMA end-point ("b = 3 * LWMA - 2 * SMA" in the above image). Someone else also described something similar in the following article (but did not provide all the equations):

So, I have also attached a ZIP file with both a PDF as well as the original MathCAD sheet of my equations showing the proof of how to calculate Linear Regression using only moving averages.


Thanks for your reply,
i want to solve the problem that OnCalculate function is worked incorrectly too, are you have any suggestion for me?
 
Fernando Carreiro:

Please don't use external URLs for adding screenshots. Please re-edit your post and use the Image icon on the toolbar to add images directly to your post.


idk why but mine dont have that icon in navbar
 
nocpinmylf: idk but my dont have that icon in navbar

It looks like new users or low ranking users don't get the "image" icon on their toolbar! I did not know that!

 
nocpinmylf: Thanks for your reply, i want to solve the problem that OnCalculate function is worked incorrectly too, are you have any suggestion for me?

I will rewrite your code correctly and post it here later.

 
Fernando Carreiro:

I will rewrite your code correctly and post it here later.

Thank you so much!
 
nocpinmylf: Thank you so much!

Here is the simplified code using LWMA and SMA to calculate a LSMA (please note that there is no need to calculate the Applied Price since MQL5 already does that with the second form of OnCalculate):

#property version             "1.000"
#property description         "Least Square Moving Average"

#property indicator_chart_window
#property indicator_buffers   3
#property indicator_plots     3

#property indicator_label1    "LSMA"
#property indicator_type1     DRAW_LINE
#property indicator_color1    clrYellow
#property indicator_style1    STYLE_SOLID
#property indicator_width1    2

#property indicator_label2    "LWMA"
#property indicator_type2     DRAW_LINE
#property indicator_color2    clrViolet
#property indicator_style2    STYLE_DOT
#property indicator_width2    1

#property indicator_label3    "SMA"
#property indicator_type3     DRAW_LINE
#property indicator_color3    clrCyan
#property indicator_style3    STYLE_DOT
#property indicator_width3    1

#include  <MovingAverages.mqh>   // Include Moving Average Calculation Functions

//--- Indicator Parameters
   input int input_period = 15;  // Period (Bars)

//--- Indicator Buffers
   double buffer_LSMA[], buffer_LWMA[], buffer_SMA[];

//--- Initialise Buffer Index and other Properties
   int OnInit( void )
   {
      // Validate Input Parameters
         if( input_period < 1 )
         {
            Print( "Error: Invalid Period!" ); 
            return INIT_PARAMETERS_INCORRECT;
         };
   
      // Initialise Buffer Objects
         SetIndexBuffer( 0, buffer_LSMA, INDICATOR_DATA );
         SetIndexBuffer( 1, buffer_LWMA, INDICATOR_DATA );
         SetIndexBuffer( 2, buffer_SMA,  INDICATOR_DATA );
      
      IndicatorSetInteger( INDICATOR_DIGITS, _Digits );  // Set Number of Significant Digits (Precision)
      return INIT_SUCCEEDED;                             // Successful Initialisation of Indicator
   };

//--- Calculate Indicator Values for Applied Price
   int OnCalculate( const int rates_total, const int prev_calculated, const int begin, const double &price[] )
   {
      // Apply LWMA & SMA Calculations
         LinearWeightedMAOnBuffer( rates_total, prev_calculated, begin, input_period, price, buffer_LWMA );
         SimpleMAOnBuffer(         rates_total, prev_calculated, begin, input_period, price, buffer_SMA  );
      
      // Calculate LSMA using the LWMA & SMA Data
         int start_position = begin + input_period;
         if( prev_calculated < start_position )
            ArrayInitialize( buffer_LSMA, EMPTY_VALUE );
         else
            start_position = prev_calculated - 1;
         for( int i = start_position; i < rates_total; i++ )
            buffer_LSMA[ i ] = 3.0 * buffer_LWMA[ i ] - 2.0 * buffer_SMA[ i ];
      
      return rates_total;  // Return value of prev_calculated for next call
   };

 
Fernando Carreiro:

Here is the simplified code using LWMA and SMA to calculate a LSMA (please note that there is no need to calculate the Applied Price since MQL5 already does that with the second form of OnCalculate):


Thanks for your help, i appriciate that.
 
nocpinmylf: Thanks for your help, i appriciate that.
You are welcome!
Reason: