Custom indicator's moving-average calc degenerates to raw price (identity) for specific inputs, while an identical code pattern with different inputs works correctly

 

I have a custom indicator with a reusable CMA class ( Setup() + Compute() ) that computes one of 14 selectable moving-average types. Two different input-variable pairs feed separate instances of this exact same class/method:

  • baseMAType  /  baseLength  → feeds 4 instances ( maBaseClose ,  maBaseSrc ,  maBaseHigh ,  maBaseLow )
  • SSL2Type  /  len2  → feeds 2 instances ( maSSL2High ,  maSSL2Low )

Both pairs are declared the same way ( input E_MA_TYPE ...; input int ...; ), passed into Setup() identically, and computed via the identical Compute() method. The baseMAType / baseLength -fed instances always return the raw input price unchanged (i.e. the MA has zero smoothing — output == close[i] exactly, every bar), while the SSL2Type / len2 -fed instances compute correctly (verified: 166 bull / 134 bear state changes across 300 bars — clearly not degenerate).

This happens even using the compiled-in default values ( baseMAType=MAT_HMA default, baseLength=60 default) — not only when overriding via iCustom() . So it isn't specifically about parameter overrides; the base computation itself is broken for this one variable pair.

Minimal repro of the relevant code

enum E_MA_TYPE { MAT_SMA, MAT_EMA, MAT_DEMA, MAT_TEMA, MAT_LSMA, MAT_WMA, MAT_MF,
                  MAT_VAMA, MAT_TMA, MAT_HMA, MAT_JMA, MAT_KIJUN2, MAT_EDSMA, MAT_MCGINLEY };

input E_MA_TYPE baseMAType = MAT_HMA;
input int    baseLength = 60;
input E_MA_TYPE SSL2Type = MAT_JMA;
input int    len2 = 5;
// ... a few more inputs (src_price, multy, useTrueRange, SSL3Type, len3, atrlen, atr_smoothing, risk_lookback) ...

class CMA
  {
public:
   E_MA_TYPE m_type;
   int       m_len;
   double    out[], a1[], a2[], a3[];
   void Setup(E_MA_TYPE t, int l) { m_type=t; m_len=MathMax(1,l); }
   void Resize(int total) { if(ArraySize(out)!=total){ArrayResize(out,total);ArrayResize(a1,total);ArrayResize(a2,total);ArrayResize(a3,total);} }
   double Compute(int i, const double &src[], const double &hi[], const double &lo[]);
  };

double CMA::Compute(int i, const double &src[], const double &hi[], const double &lo[])
  {
   int length = m_len;
   double r = src[i];
   switch(m_type)
     {
      // ... SMA/EMA/DEMA/... cases ...
      case MAT_HMA:
        {
         int half = MathMax(1,length/2);
         int sq   = MathMax(1,(int)MathRound(MathSqrt(length)));
         a1[i] = 2*WMAat(src,half,i) - WMAat(src,length,i);
         r = WMAat(a1,sq,i);
         break;
        }
      // ... JMA/etc ...
     }
   out[i]=r;
   return r;
  }

CMA maBaseClose, maBaseSrc, maBaseHigh, maBaseLow;   // fed by baseMAType/baseLength -> ALWAYS BROKEN
CMA maSSL2High, maSSL2Low;                            // fed by SSL2Type/len2       -> ALWAYS CORRECT

int OnInit()
  {
   maBaseClose.Setup(baseMAType,baseLength);
   maBaseSrc.Setup(baseMAType,baseLength);
   maBaseHigh.Setup(baseMAType,baseLength);
   maBaseLow.Setup(baseMAType,baseLength);
   maSSL2High.Setup(SSL2Type,len2);
   maSSL2Low.Setup(SSL2Type,len2);
   return(INIT_SUCCEEDED);
  }

int OnCalculate(...)
  {
   for(int i=start; i<rates_total; i++)
     {
      double bbmc = maBaseClose.Compute(i,close,high,low);   // == close[i] exactly, every bar
      BufBBMC[i]=bbmc;
      double maHigh = maSSL2High.Compute(i,high,high,low);   // correct, smoothed
      ...
     }
  }

Symptom, verified with independent cross-checks

  • BufBBMC[i]  (from  maBaseClose ) equals  close[i]  exactly, to 5 decimals, on every bar tested. A genuine  HMA(close,60)  computed independently (by hand, from raw  CopyClose / CopyHigh / CopyLow  data using the same WMA formula) gives clearly different, properly-smoothed values (e.g.  4024.88  vs raw close  4072.41 ).
  • ATR ( atrlen / atr_smoothing , computed via a plain function, not the  CMA  class) matches an independently-computed WMA(TrueRange,14) exactly — so at least some other positionally-passed inputs work fine.
  • Hlv2 /SSL2 state (fed by  SSL2Type / len2 , same  CMA  class) shows correct 1/-1 variation across 300 bars (166/134 split) — not stuck.
  • Hlv  (SSL1 state, fed by  baseMAType / baseLength ) is stuck at  0  for 300/300 bars — consistent with  maBaseHigh / maBaseLow  also degenerating to raw  high[i] / low[i] .

What I've ruled out (all retested after each change, all still broken)

  1. iCustom argument count — tested 13, 15, 17, 19, 22 positional override arguments; failure is independent of count (a different, much simpler 0-plot/14-buffer indicator broke at just 13 args, while a more complex 8-plot/31-buffer indicator worked fine at 15 args in earlier testing — so it's not a fixed count threshold either).
  2. Argument position — added 11 dummy leading  input int  params before  baseMAType / baseLength  (both in the indicator's declaration and the caller's positional list) to push them later in the list; no change.
  3. Variable naming collision — renamed  maType → baseMAType ,  len → baseLength  throughout; grepped the (large, ~330KB) shared include library for any global-scope  len / maType  declaration or  #define ; none found; rename made no difference.
  4. Enum type as first positional argument — explicitly cast to  (int)  for every enum-typed argument passed via  iCustom(...) ; no change.
  5. Caller context — reproduced identically from both a  Script  ( OnStart ) and an  EA  ( OnInit / OnTick ); both fail the same way.
  6. indicator_plots 0 vs 1 — the indicator has  #property indicator_plots 0  (all buffers  INDICATOR_CALCULATIONS , called only via  iCustom , never displayed). Adding a real plot for the affected buffer didn't fix the value bug, and additionally made that specific buffer unreadable via  CopyBuffer  ( error 4806 ) while the indicator was never actually shown on a chart subwindow — reverted.
  7. Confirmed via  GetLastError()  after every failing  CopyBuffer / iCustom  call — never non-zero except in the plots=1 experiment above.
Please help me!!!