From 986de5026af457795f77b72d6f02146a62430cca Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Sun, 21 Jun 2026 15:11:16 +0200 Subject: [PATCH] refactor: Integrated double-volume array translation to support VWMA Signal lines --- Indicators/MyIndicators/Quant/ZScore_Pro.mq5 | 171 ++++++++++++++----- 1 file changed, 132 insertions(+), 39 deletions(-) diff --git a/Indicators/MyIndicators/Quant/ZScore_Pro.mq5 b/Indicators/MyIndicators/Quant/ZScore_Pro.mq5 index e084e2d..c1266ab 100644 --- a/Indicators/MyIndicators/Quant/ZScore_Pro.mq5 +++ b/Indicators/MyIndicators/Quant/ZScore_Pro.mq5 @@ -3,64 +3,83 @@ //| Copyright 2026, xxxxxxxx| //+------------------------------------------------------------------+ #property copyright "Copyright 2026, xxxxxxxx" -#property version "1.40" // Upgraded with dynamic MA type selectors and volume support -#property description "Statistical Z-Score Oscillator." +#property version "1.70" // Integrated double-volume array translation to support VWMA Signal lines +#property description "Statistical Z-Score Oscillator with dynamic Signal Line." #property description "Displays deviations from any selected Moving Average in Sigma units." #property indicator_separate_window -#property indicator_buffers 2 -#property indicator_plots 1 +#property indicator_buffers 3 +#property indicator_plots 2 -//--- Institutional Levels Configuration (Sigma boundaries) +//--- Institutional Levels Configuration (6 Sigma boundaries) #property indicator_level1 2.0 #property indicator_level2 -2.0 -#property indicator_level3 3.0 -#property indicator_level4 -3.0 +#property indicator_level3 2.5 +#property indicator_level4 -2.5 +#property indicator_level5 3.0 +#property indicator_level6 -3.0 #property indicator_levelcolor clrSilver #property indicator_levelstyle STYLE_DOT -//--- Plot: Z-Score Histogram (Colored) +//--- Plot 1: Z-Score Histogram (5-Zone Thermal Palette) #property indicator_label1 "Z-Score" #property indicator_type1 DRAW_COLOR_HISTOGRAM -// Color Index: 0=Normal, 1=High(Red), 2=Low(Lime) -#property indicator_color1 clrGray, clrOrangeRed, clrSpringGreen +// 5-Color Palette: +// 0: Noise/Neutral (Gray) +// 1: Warning High (Coral) +// 2: Extreme High (OrangeRed) +// 3: Warning Low (LightSkyBlue) +// 4: Extreme Low (DeepSkyBlue) +#property indicator_color1 clrGray, clrCoral, clrOrangeRed, clrLightSkyBlue, clrDeepSkyBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 2 +//--- Plot 2: Optional Signal Line (Wyckoff Reversal Trigger) +#property indicator_label2 "Signal" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrFireBrick +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + #include -//--- Input Parameters -input int InpPeriod = 20; // Lookback Period -input ENUM_MA_TYPE InpMAType = SMA; // Moving Average Type -input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; // Applied Price +//--- Input Parameters --- +input int InpPeriod = 20; // Z-Score Lookback Period +input ENUM_MA_TYPE InpMAType = SMA; // Z-Score MA Type +input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; // Z-Score Applied Price -//--- Buffers +//--- Signal Line Parameters +input bool InpShowSignal = true; // Show Signal Line? +input int InpSignalPeriod= 5; // Signal Line Period +input ENUM_MA_TYPE InpSignalType = SMA; // Signal Line MA Type + +//--- Buffers --- double BufferZ[]; double BufferColors[]; +double BufferSignal[]; -//--- Global Calculator Object -CZScoreCalculator *g_calculator; +//--- Volume Cache to support Volume-Weighted types (VWMA) on custom arrays +double g_double_volume[]; + +//--- Global Calculator Objects --- +CZScoreCalculator *g_calculator; +CMovingAverageCalculator *g_signal_calculator; //+------------------------------------------------------------------+ //| OnInit | //+------------------------------------------------------------------+ int OnInit() { - SetIndexBuffer(0, BufferZ, INDICATOR_DATA); +//--- Bind Buffers + SetIndexBuffer(0, BufferZ, INDICATOR_DATA); SetIndexBuffer(1, BufferColors, INDICATOR_COLOR_INDEX); + SetIndexBuffer(2, BufferSignal, INDICATOR_DATA); - ArraySetAsSeries(BufferZ, false); + ArraySetAsSeries(BufferZ, false); ArraySetAsSeries(BufferColors, false); + ArraySetAsSeries(BufferSignal, false); -//--- Dynamically set the indicator name based on MA selection - string ma_name = EnumToString(InpMAType); - StringToUpper(ma_name); - - string short_name = StringFormat("ZScore(%d, %s)", InpPeriod, ma_name); - IndicatorSetString(INDICATOR_SHORTNAME, short_name); - PlotIndexSetString(0, PLOT_LABEL, "Z-Score"); - IndicatorSetInteger(INDICATOR_DIGITS, 2); // Z-Score usually has 2 decimals (e.g., 1.96) - +//--- Configure Core Z-Score Calculator g_calculator = new CZScoreCalculator(); if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod, InpMAType)) { @@ -68,6 +87,47 @@ int OnInit() return INIT_FAILED; } +//--- Configure Optional Signal Line Calculator + if(InpShowSignal) + { + // Explicitly restore DRAW_LINE & Label in case it was previously disabled + PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE); + PlotIndexSetString(1, PLOT_LABEL, "Signal"); + + g_signal_calculator = new CMovingAverageCalculator(); + if(CheckPointer(g_signal_calculator) == POINTER_INVALID || !g_signal_calculator.Init(InpSignalPeriod, InpSignalType)) + { + Print("Error: Failed to initialize Signal Line Calculator."); + return INIT_FAILED; + } + } + else + { + // Set DRAW_NONE and clear Label to fully purge it from the MT5 Data Window + PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_NONE); + PlotIndexSetString(1, PLOT_LABEL, NULL); + } + +//--- Dynamically set the indicator short name + string ma_name = EnumToString(InpMAType); + StringToUpper(ma_name); + + string short_name = ""; + if(InpShowSignal) + { + string sig_name = EnumToString(InpSignalType); + StringToUpper(sig_name); + short_name = StringFormat("ZScore(%d, %s) %s(%d)", InpPeriod, ma_name, sig_name, InpSignalPeriod); + } + else + { + short_name = StringFormat("ZScore(%d, %s)", InpPeriod, ma_name); + } + + IndicatorSetString(INDICATOR_SHORTNAME, short_name); + PlotIndexSetString(0, PLOT_LABEL, "Z-Score"); + IndicatorSetInteger(INDICATOR_DIGITS, 2); + return(INIT_SUCCEEDED); } @@ -78,6 +138,8 @@ void OnDeinit(const int reason) { if(CheckPointer(g_calculator) != POINTER_INVALID) delete g_calculator; + if(CheckPointer(g_signal_calculator) != POINTER_INVALID) + delete g_signal_calculator; } //+------------------------------------------------------------------+ @@ -100,7 +162,22 @@ int OnCalculate(const int rates_total, //--- Determine best volume array (Use Real Volume if available, otherwise fallback to Tick Volume) long volume_limit = (long)SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT); -//--- Route calculations dynamically to support volume-weighted types (VWMA) +//--- Convert long volume to double cache array in O(1) incrementally + ArrayResize(g_double_volume, rates_total); + int start_sync = (prev_calculated > 0) ? prev_calculated - 1 : 0; + + if(volume_limit > 0) + { + for(int i = start_sync; i < rates_total; i++) + g_double_volume[i] = (double)volume[i]; + } + else + { + for(int i = start_sync; i < rates_total; i++) + g_double_volume[i] = (double)tick_volume[i]; + } + +//--- 1. Calculate Core Z-Score (Handles VWMA volume integration dynamically) if(volume_limit > 0) { g_calculator.Calculate(rates_total, prev_calculated, InpPrice, open, high, low, close, volume, BufferZ); @@ -110,24 +187,40 @@ int OnCalculate(const int rates_total, g_calculator.Calculate(rates_total, prev_calculated, InpPrice, open, high, low, close, tick_volume, BufferZ); } -//--- 2. Apply Dynamic Coloring Logic (O(1) incremental) +//--- 2. Calculate Optional Signal Line on top of Z-Score values + if(InpShowSignal && CheckPointer(g_signal_calculator) != POINTER_INVALID) + { + // Source start index is 'InpPeriod - 1' since Z-Score before that index is invalid/empty + // FIXED: Passed g_double_volume down to ensure VWMA signal line type calculates correctly + g_signal_calculator.CalculateOnArray(rates_total, prev_calculated, BufferZ, g_double_volume, BufferSignal, InpPeriod - 1); + } + +//--- 3. Apply 5-Zone Thermal Coloring Logic (O(1) incremental) int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0; for(int i = start_index; i < rates_total; i++) { double z = BufferZ[i]; - // Color Logic: - // > 2.0 -> OrangeRed (Extreme High / Overbought) - // < -2.0 -> SpringGreen (Extreme Low / Oversold) - // Else -> Gray (Normal Noise Zone) - if(z > 2.0) - BufferColors[i] = 1.0; // Index 1: OrangeRed + // 5-Zone Thermal Coloring: + // Z > 2.5 -> OrangeRed (Extreme High / Sell Reversal Zone) + // Z > 2.0 -> Coral (Warning High / Caution Zone) + // Z < -2.5 -> DeepSkyBlue (Extreme Low / Buy Reversal Zone) + // Z < -2.0 -> LightSkyBlue (Warning Low / Caution Zone) + // Else -> Gray (Neutral Noise Zone) + if(z > 2.5) + BufferColors[i] = 2.0; // Index 2: OrangeRed else - if(z < -2.0) - BufferColors[i] = 2.0; // Index 2: SpringGreen + if(z > 2.0) + BufferColors[i] = 1.0; // Index 1: Coral else - BufferColors[i] = 0.0; // Index 0: Gray + if(z < -2.5) + BufferColors[i] = 4.0; // Index 4: DeepSkyBlue + else + if(z < -2.0) + BufferColors[i] = 3.0; // Index 3: LightSkyBlue + else + BufferColors[i] = 0.0; // Index 0: Gray } return(rates_total);