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!!!
 
The two omitted pieces are exactly the ones needed to diagnose this: WMAat() and the complete calculation-order/start/Resize code. HMA is not equivalent to the JMA case here. It first writes a1[i], then WMAat(a1,sqrtLen,i) must read already-calculated neighbouring a1 values in the same indexing direction. A price-array/state-array direction mismatch, or starting at an index whose prerequisite a1 history was never populated, can reduce that second stage to its current sample and make the result look like the source.

Before changing iCustom arguments, log the invariant inside Compute for each instance once: m_type, m_len, i, ArrayGetAsSeries(src), ArrayGetAsSeries(a1), ArraySize(a1) and ArraySize(out). Also log WMAat(src,length,i), WMAat(src,half,i), a1[i] and WMAat(a1,sq,i). This will distinguish a bad Setup value from a bad HMA history immediately.

For a real minimal repro, include WMAat(), every Resize()/ArraySetAsSeries() call and the exact start calculation. On the initial pass, calculate in chronological order and populate enough warm-up history for both the length-stage and sqrt(length)-stage; on later passes recompute the overlap required by the state arrays. Set/check the indexing direction explicitly for the OnCalculate price arrays and every internal array instead of relying on defaults.

There is also one useful control: temporarily run MAT_WMA with baseLength=60 through the same base instance. If that smooths correctly while MAT_HMA does not, Setup/iCustom are exonerated and the fault is specifically the a1 second-stage history. If WMA also equals raw price, the fault is in WMAat/indexing itself. Without those omitted functions, selecting among these causes would only be guessing.
 

Posting AI generated posts "silently" is not welcome on this forum. Show clearly what is your input and the AI one.

Thanks.

 
Understood. My previous reply was AI-assisted and should have been labelled. The diagnostic input was to require WMAat(), the exact start/Resize/indexing code and MAT_WMA as a control; AI assistance was used to draft and structure the explanation around that input. I should not have posted it without explicit disclosure. I will label AI-assisted forum text clearly in future. Thank you.