Help with Custom Indicator and Copy Buffer!

 

Hi all,

I've created a custom lorentz curve indicator inspired from one of them in TradingView however, when I use it in my EA with iCustom() and I copy the CopyBuffer(hLorentz, 3, 1, SIGNAL_BUFFER_SIZE, stateBuf) != SIGNAL_BUFFER_SIZE), it says the 0 index values are different for both? I'm not sure if I did something wrong with the CopyBuffer or making a custom indicator so that it can read the values.

In my EA console log, I can see it printing the following (I've taken snippets from the log to show what I:

2025.07.06 18:49:01.406 2025.02.04 15:57:20   Indicator: Bullish
2025.07.06 18:49:01.406 2025.02.04 15:57:18   EA: Bearish
2025.07.06 18:49:01.406 2025.02.04 15:57:22   Indicator: Bullish
2025.07.06 18:49:01.406 2025.02.04 15:57:22   EA: Bearish
2025.07.06 18:49:01.407 2025.02.04 15:57:24   Indicator: Bullish
2025.07.06 18:57:28.412 2025.02.04 16:05:59   Indicator: Bullish
2025.07.06 18:57:28.412 2025.02.04 16:05:59   EA: Bullish
2025.07.06 18:57:29.467 2025.02.04 16:06:08   Indicator: Bearish
2025.07.06 18:57:29.467 2025.02.04 16:06:08   EA: Bullish
2025.07.06 18:57:29.639 2025.02.04 16:06:10   Indicator: Bearish
2025.07.06 18:57:29.639 2025.02.04 16:06:10   EA: Bullish
2025.07.06 18:57:29.837 2025.02.04 16:06:11   Indicator: Bearish
2025.07.06 18:57:29.837 2025.02.04 16:06:11   EA: Bullish
2025.07.06 18:57:30.017 2025.02.04 16:06:13   Indicator: Bearish
2025.07.06 18:57:30.017 2025.02.04 16:06:13   EA: Bullish
2025.07.06 18:57:30.187 2025.02.04 16:06:15   Indicator: Bearish
2025.07.06 18:57:30.187 2025.02.04 16:06:15   EA: Bullish
2025.07.06 18:57:30.384 2025.02.04 16:06:17   Indicator: Bearish
2025.07.06 18:57:30.384 2025.02.04 16:06:17   EA: Bullish

Any advice would be greatly appreciated. Thanks!


#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots 2

//--- plot #1: bullish (green)
#property indicator_label1 "Kernel Estimate ▲"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrLime
#property indicator_width1 2
//--- plot #2: bearish (red)
#property indicator_label2 "Kernel Estimate ▼"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrRed
#property indicator_width2 2

//--- Inputs
input string IndicatorName = "LDC Kernel Estimate";
input bool UseFilterMethod = false;
input bool InpShowKernelEstimate = true;
input bool InpUseKernelSmoothing = false;
input int InpLookbackWindow = 8;
input double InpRelativeWeighting = 8.0;
input int InpRegressionLevel = 25;
input int InpLag = 2;

input double InpMinSlope = 0.25;
input double InpUpperHyst = 0.0002;
input double InpLowerHyst = -0.0002;
input int InpDebounceBars = 5;
input int InpATRPeriod = 14;
input double InpMinATR = 0.0001;

//--- Buffers
double bullBuf[];
double bearBuf[];
double rqBuf[];
double stateBuf[];

//--- Persistent state
static bool lastState = false;
static int debounceCnt = 0;

//+------------------------------------------------------------------+
int OnInit()
{
   IndicatorSetString(INDICATOR_SHORTNAME, IndicatorName);
   SetIndexBuffer(0, bullBuf, INDICATOR_DATA);
   SetIndexBuffer(1, bearBuf, INDICATOR_DATA);
   SetIndexBuffer(2, rqBuf, INDICATOR_CALCULATIONS);
   SetIndexBuffer(3, stateBuf, INDICATOR_CALCULATIONS);

   // mark unused plot2-buffer points as empty
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
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[])
{
   int recalcDepth = 20;
   int start = (prev_calculated == 0)
                   ? 0
                   : MathMax(0, rates_total - recalcDepth - InpLookbackWindow);

   for (int i = start; i < rates_total; i++)
   {
      if (!InpShowKernelEstimate)
      {
         bullBuf[i] = EMPTY_VALUE;
         bearBuf[i] = EMPTY_VALUE;
         rqBuf[i] = 0.0;
         continue;
      }

      // –– 1. Kernel Regression (RQ)
      double sumW1 = 0.0, sumWY1 = 0.0;
      for (int j = 0; j < InpLookbackWindow; j++)
      {
         int idx = i - j;
         if (idx < 0)
            break;
         double d = (double)j;
         double s = (double)InpRegressionLevel;
         double α = InpRelativeWeighting;
         double w = MathPow(1.0 + (d * d) / (2.0 * α * s * s), -α);
         sumW1 += w;
         sumWY1 += w * close[idx];
      }
      double yhat1 = (sumW1 > 0.0) ? (sumWY1 / sumW1) : close[i];
      rqBuf[i] = yhat1;

      // –– 2. Optional Gaussian NW smoothing
      double yhat2 = yhat1;
      if (InpUseKernelSmoothing)
      {
         int win2 = MathMax(1, InpLookbackWindow - InpLag);
         double sumW2 = 0.0, sumWY2 = 0.0;
         for (int j = 0; j < win2; j++)
         {
            int idx = i - j;
            if (idx < 0)
               break;
            double d = (double)j;
            double s = (double)InpRegressionLevel;
            double w = MathExp(-0.5 * (d * d) / (s * s));
            sumW2 += w;
            sumWY2 += w * close[idx];
         }
         yhat2 = (sumW2 > 0.0) ? (sumWY2 / sumW2) : yhat1;
      }

      // –– 3. Slope + ATR
      double delta = (i > 0) ? (rqBuf[i] - rqBuf[i - 1]) : 0.0;
      double atr = iATR(_Symbol, _Period, InpATRPeriod);

      if (UseFilterMethod)
      {
         bool signal = lastState;
         if (atr >= InpMinATR && MathAbs(delta) >= InpMinSlope)
         {
            if (delta >= InpUpperHyst)
               signal = true;
            else if (delta <= InpLowerHyst)
               signal = false;
         }

         if (signal != lastState)
         {
            debounceCnt++;
            if (debounceCnt >= InpDebounceBars)
            {
               lastState = signal;
               debounceCnt = 0;
            }
         }
         else
         {
            debounceCnt = 0;
         }

         if (lastState)
         {
            bullBuf[i] = yhat1;
            bearBuf[i] = EMPTY_VALUE;
         }
         else
         {
            bearBuf[i] = yhat1;
            bullBuf[i] = EMPTY_VALUE;
         }
      }
      else
      {
         bool bullish = (i > 0 && rqBuf[i] >= rqBuf[i - 1]);
         if (InpUseKernelSmoothing)
            bullish = (yhat2 >= yhat1);

         bullBuf[i] = EMPTY_VALUE;
         bearBuf[i] = EMPTY_VALUE;

         stateBuf[i] = (bullish ? 1.0 : -1.0);

         if (bullish)
         {
            bullBuf[i] = yhat1;
         }
         else
         {
            bearBuf[i] = yhat1;
         }
      }

      // –– Optional debug
      if (i == start)
      {
         if (stateBuf[i] > 0)
            Print("Indicator: Bullish");
         else
            Print("Indicator: Bearish");
      }
   }

   return rates_total;
}
//+------------------------------------------------------------------+


Discover new MetaTrader 5 opportunities with MQL5 community and services
Discover new MetaTrader 5 opportunities with MQL5 community and services
  • 2025.07.06
  • www.mql5.com
MQL5: language of trade strategies built-in the MetaTrader 5 Trading Platform, allows writing your own trading robots, technical indicators, scripts and libraries of functions
 

because if you copy more than one bar via copybuffer in the EA, you NEED to set the buffers as series in the EA

as example:

input int MA_Period = 20;

double ma_buf[];

int handle = INVALID_HANDLE;


int OnInit() {
    handle = iMA(_Symbol, _Period, MA_Period, 0, MODE_EMA, PRICE_CLOSE);

    ArraySetAsSeries(ma_buf, true);   // <<<<<<<<<<<<<<<<
    
    return (INIT_SUCCEEDED);
}

void OnDeinit(const int reason){

    IndicatorRelease(handle);
    Comment("");

}

void OnTick() {

    if (CopyBuffer(handle, 0, 0, 2, ma_buf)==-1) {
        Print("problem loading EMA");
        GetLastError();
    }


    double ema_latest_bar = ma_buf[0];
    double ema_penultimate_bar = ma_buf[1];
    
    string str = "EMA value on the current bar: " + DoubleToString(ema_latest_bar) + "\n" + "EMA value on the second last bar: " + DoubleToString(ema_penultimate_bar);
    
    Comment(str);
}
 
Conor Mcnamara #:

because if you copy more than one bar via copybuffer in the EA, you NEED to set the buffers as series in the EA

as example:

Oh gotcha! That makes a lot of sense and seems to be working now. Thanks!