From 55556b0f0c3132e136cba040f78c5667076d5ebe Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Sat, 6 Dec 2025 17:50:00 +0100 Subject: [PATCH] refactor: Reverted to Full Recalc for consistency --- Include/MyIncludes/MAMA_Calculator.mqh | 380 +++++++++++++------------ 1 file changed, 204 insertions(+), 176 deletions(-) diff --git a/Include/MyIncludes/MAMA_Calculator.mqh b/Include/MyIncludes/MAMA_Calculator.mqh index 797da1c..9d90862 100644 --- a/Include/MyIncludes/MAMA_Calculator.mqh +++ b/Include/MyIncludes/MAMA_Calculator.mqh @@ -1,23 +1,34 @@ //+------------------------------------------------------------------+ //| MAMA_Calculator.mqh | -//| Calculation engine for the John Ehlers' MAMA and FAMA. | +//| VERSION 1.20: Reverted to Full Recalc for consistency. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #include -//+==================================================================+ -//| | -//| CLASS 1: CMAMACalculator (Base Class) | -//| | //+==================================================================+ class CMAMACalculator { protected: double m_fast_limit; double m_slow_limit; + + //--- Buffers double m_price[]; + // We keep internal buffers as members to avoid reallocation, + // but we will overwrite them every time. + double m_smooth_buf[]; + double m_detrender_buf[]; + double m_I1_buf[], m_Q1_buf[]; + double m_jI_buf[], m_jQ_buf[]; + double m_I2_buf[], m_Q2_buf[]; + double m_Re_buf[], m_Im_buf[]; + double m_period_buf[]; + double m_smooth_period_buf[]; + double m_phase_buf[]; + double m_mama_buf[]; + double m_fama_buf[]; virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); @@ -26,6 +37,8 @@ public: virtual ~CMAMACalculator(void) {}; bool Init(double fast_limit, double slow_limit); + + //--- Reverted: No prev_calculated needed void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &mama_buffer[], double &fama_buffer[]); }; @@ -42,211 +55,226 @@ bool CMAMACalculator::Init(double fast_limit, double slow_limit) void CMAMACalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &mama_buffer[], double &fama_buffer[]) { - if(rates_total < 50) // MAMA needs a significant warmup period + if(rates_total < 50) return; + +//--- Always Full Recalculation + +//--- Resize Internal Buffers + if(ArraySize(m_price) != rates_total) + { + ArrayResize(m_price, rates_total); + ArrayResize(m_smooth_buf, rates_total); + ArrayResize(m_detrender_buf, rates_total); + ArrayResize(m_I1_buf, rates_total); + ArrayResize(m_Q1_buf, rates_total); + ArrayResize(m_jI_buf, rates_total); + ArrayResize(m_jQ_buf, rates_total); + ArrayResize(m_I2_buf, rates_total); + ArrayResize(m_Q2_buf, rates_total); + ArrayResize(m_Re_buf, rates_total); + ArrayResize(m_Im_buf, rates_total); + ArrayResize(m_period_buf, rates_total); + ArrayResize(m_smooth_period_buf, rates_total); + ArrayResize(m_phase_buf, rates_total); + ArrayResize(m_mama_buf, rates_total); + ArrayResize(m_fama_buf, rates_total); + } + +// Initialize buffers with 0 (important for full recalc) + ArrayInitialize(m_smooth_buf, 0); + ArrayInitialize(m_detrender_buf, 0); + ArrayInitialize(m_I1_buf, 0); + ArrayInitialize(m_Q1_buf, 0); + ArrayInitialize(m_jI_buf, 0); + ArrayInitialize(m_jQ_buf, 0); + ArrayInitialize(m_I2_buf, 0); + ArrayInitialize(m_Q2_buf, 0); + ArrayInitialize(m_Re_buf, 0); + ArrayInitialize(m_Im_buf, 0); + ArrayInitialize(m_period_buf, 0); + ArrayInitialize(m_smooth_period_buf, 0); + ArrayInitialize(m_phase_buf, 0); +// MAMA/FAMA init with price later + if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) return; -// --- State variables for full recalculation loop --- - double smooth=0, detrender=0, I1=0, Q1=0; - double jI=0, jQ=0, I2=0, Q2=0, Re=0, Im=0; - double period=0, smooth_period=0, phase=0, delta_phase=0; - - double I1_p[7]= {0}, Q1_p[7]= {0}, detrender_p[7]= {0}, smooth_p[5]= {0}; - double I2_p[2]= {0}, Q2_p[2]= {0}; - double Re_p[2]= {0}, Im_p[2]= {0}; - double period_p[2]= {0}, smooth_period_p[2]= {0}; - double phase_p[2]= {0}; - double mama_prev=0, fama_prev=0; - -// --- Full recalculation loop for stability --- +//--- Main Loop (From 0 to Total) for(int i = 0; i < rates_total; i++) { - // Shift history - for(int k=6; k>0; k--) - { - I1_p[k]=I1_p[k-1]; - Q1_p[k]=Q1_p[k-1]; - detrender_p[k]=detrender_p[k-1]; - } - for(int k=4; k>0; k--) - { - smooth_p[k]=smooth_p[k-1]; - } - I2_p[1]=I2_p[0]; - Q2_p[1]=Q2_p[0]; - Re_p[1]=Re_p[0]; - Im_p[1]=Im_p[0]; - period_p[1]=period_p[0]; - smooth_period_p[1]=smooth_period_p[0]; - phase_p[1]=phase_p[0]; - - // --- Calculation starts after a few bars --- - if(i > 5) - { - // 1. Smoothing - smooth = (4*m_price[i] + 3*m_price[i-1] + 2*m_price[i-2] + m_price[i-3]) / 10.0; - smooth_p[0] = smooth; - - // 2. Detrender (Band-pass filter) - detrender = (0.0962*smooth_p[0] + 0.5769*smooth_p[2] - 0.5769*smooth_p[4] - 0.0962*smooth_p[0]) * (0.075*period_p[1] + 0.54); - detrender_p[0] = detrender; - - // 3. InPhase and Quadrature components - Q1 = (0.0962*detrender_p[0] + 0.5769*detrender_p[2] - 0.5769*detrender_p[4] - 0.0962*detrender_p[6]) * (0.075*period_p[1] + 0.54); - I1 = detrender_p[3]; - I1_p[0] = I1; - Q1_p[0] = Q1; - - // 4. Phase advance - jI = (0.0962*I1_p[0] + 0.5769*I1_p[2] - 0.5769*I1_p[4] - 0.0962*I1_p[6]) * (0.075*period_p[1] + 0.54); - jQ = (0.0962*Q1_p[0] + 0.5769*Q1_p[2] - 0.5769*Q1_p[4] - 0.0962*Q1_p[6]) * (0.075*period_p[1] + 0.54); - - // 5. Phasor addition and smoothing - I2 = I1 - jQ; - Q2 = Q1 + jI; - I2 = 0.2*I2 + 0.8*I2_p[1]; - Q2 = 0.2*Q2 + 0.8*Q2_p[1]; - I2_p[0] = I2; - Q2_p[0] = Q2; - - // 6. Homodyne Discriminator - Re = I2*I2_p[1] + Q2*Q2_p[1]; - Im = I2*Q2_p[1] - Q2*I2_p[1]; - Re = 0.2*Re + 0.8*Re_p[1]; - Im = 0.2*Im + 0.8*Im_p[1]; - Re_p[0] = Re; - Im_p[0] = Im; - - // 7. Cycle Period Measurement - if(Im!=0.0 && Re!=0.0) - period = 360.0 / (atan(Im/Re) * 180.0/M_PI); - if(period > 1.5*period_p[1]) - period = 1.5*period_p[1]; - if(period < 0.67*period_p[1]) - period = 0.67*period_p[1]; - if(period < 6) - period = 6; - if(period > 50) - period = 50; - period = 0.2*period + 0.8*period_p[1]; - smooth_period = 0.33*period + 0.67*smooth_period_p[1]; - period_p[0] = period; - smooth_period_p[0] = smooth_period; - - // 8. Delta Phase - if(I1 != 0.0) - phase = atan(Q1/I1) * 180.0/M_PI; - delta_phase = phase_p[1] - phase; - if(delta_phase < 1.0) - delta_phase = 1.0; - phase_p[0] = phase; - - // 9. Adaptive Alpha - double alpha = m_fast_limit / delta_phase; - if(alpha < m_slow_limit) - alpha = m_slow_limit; - - // 10. MAMA and FAMA Calculation - mama_buffer[i] = alpha * m_price[i] + (1.0 - alpha) * mama_prev; - fama_buffer[i] = 0.5 * alpha * mama_buffer[i] + (1.0 - 0.5 * alpha) * fama_prev; - } - else + // Initialization for first few bars + if(i < 7) { + m_mama_buf[i] = m_price[i]; + m_fama_buf[i] = m_price[i]; mama_buffer[i] = m_price[i]; fama_buffer[i] = m_price[i]; + continue; } - mama_prev = mama_buffer[i]; - fama_prev = fama_buffer[i]; + // 1. Smoothing + m_smooth_buf[i] = (4*m_price[i] + 3*m_price[i-1] + 2*m_price[i-2] + m_price[i-3]) / 10.0; + + // 2. Detrender + double period_prev = m_period_buf[i-1]; + m_detrender_buf[i] = (0.0962*m_smooth_buf[i] + 0.5769*m_smooth_buf[i-2] - 0.5769*m_smooth_buf[i-4] - 0.0962*m_smooth_buf[i-6]) * (0.075*period_prev + 0.54); + + // 3. InPhase and Quadrature + m_Q1_buf[i] = (0.0962*m_detrender_buf[i] + 0.5769*m_detrender_buf[i-2] - 0.5769*m_detrender_buf[i-4] - 0.0962*m_detrender_buf[i-6]) * (0.075*period_prev + 0.54); + m_I1_buf[i] = m_detrender_buf[i-3]; + + // 4. Phase advance + m_jI_buf[i] = (0.0962*m_I1_buf[i] + 0.5769*m_I1_buf[i-2] - 0.5769*m_I1_buf[i-4] - 0.0962*m_I1_buf[i-6]) * (0.075*period_prev + 0.54); + m_jQ_buf[i] = (0.0962*m_Q1_buf[i] + 0.5769*m_Q1_buf[i-2] - 0.5769*m_Q1_buf[i-4] - 0.0962*m_Q1_buf[i-6]) * (0.075*period_prev + 0.54); + + // 5. Phasor addition + double I2 = m_I1_buf[i] - m_jQ_buf[i]; + double Q2 = m_Q1_buf[i] + m_jI_buf[i]; + + m_I2_buf[i] = 0.2*I2 + 0.8*m_I2_buf[i-1]; + m_Q2_buf[i] = 0.2*Q2 + 0.8*m_Q2_buf[i-1]; + + // 6. Homodyne Discriminator + double Re = m_I2_buf[i]*m_I2_buf[i-1] + m_Q2_buf[i]*m_Q2_buf[i-1]; + double Im = m_I2_buf[i]*m_Q2_buf[i-1] - m_Q2_buf[i]*m_I2_buf[i-1]; + + m_Re_buf[i] = 0.2*Re + 0.8*m_Re_buf[i-1]; + m_Im_buf[i] = 0.2*Im + 0.8*m_Im_buf[i-1]; + + // 7. Cycle Period + double period = 0; + if(m_Im_buf[i]!=0.0 && m_Re_buf[i]!=0.0) + period = 360.0 / (atan(m_Im_buf[i]/m_Re_buf[i]) * 180.0/M_PI); + + if(period > 1.5*m_period_buf[i-1]) + period = 1.5*m_period_buf[i-1]; + if(period < 0.67*m_period_buf[i-1]) + period = 0.67*m_period_buf[i-1]; + if(period < 6) + period = 6; + if(period > 50) + period = 50; + + m_period_buf[i] = 0.2*period + 0.8*m_period_buf[i-1]; + m_smooth_period_buf[i] = 0.33*m_period_buf[i] + 0.67*m_smooth_period_buf[i-1]; + + // 8. Delta Phase + double phase = 0; + if(m_I1_buf[i] != 0.0) + phase = atan(m_Q1_buf[i]/m_I1_buf[i]) * 180.0/M_PI; + + double delta_phase = m_phase_buf[i-1] - phase; + if(delta_phase < 1.0) + delta_phase = 1.0; + m_phase_buf[i] = phase; + + // 9. Adaptive Alpha + double alpha = m_fast_limit / delta_phase; + if(alpha < m_slow_limit) + alpha = m_slow_limit; + + // 10. MAMA and FAMA + m_mama_buf[i] = alpha * m_price[i] + (1.0 - alpha) * m_mama_buf[i-1]; + m_fama_buf[i] = 0.5 * alpha * m_mama_buf[i] + (1.0 - 0.5 * alpha) * m_fama_buf[i-1]; + + mama_buffer[i] = m_mama_buf[i]; + fama_buffer[i] = m_fama_buf[i]; } } //+------------------------------------------------------------------+ bool CMAMACalculator::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) { - ArrayResize(m_price, rates_total); - switch(price_type) +// Full copy + for(int i = 0; i < rates_total; i++) { - case PRICE_CLOSE: - ArrayCopy(m_price, close, 0, 0, rates_total); - break; - case PRICE_OPEN: - ArrayCopy(m_price, open, 0, 0, rates_total); - break; - case PRICE_HIGH: - ArrayCopy(m_price, high, 0, 0, rates_total); - break; - case PRICE_LOW: - ArrayCopy(m_price, low, 0, 0, rates_total); - break; - case PRICE_MEDIAN: - for(int i=0; i