diff --git a/Include/MyIncludes/RVScore_Calculator.mqh b/Include/MyIncludes/RVScore_Calculator.mqh new file mode 100644 index 00000000..e5ddfb7b --- /dev/null +++ b/Include/MyIncludes/RVScore_Calculator.mqh @@ -0,0 +1,172 @@ +//+------------------------------------------------------------------+ +//| RVScore_Calculator.mqh | +//| Engine for Rolling Volume-Weighted Z-Score (RV-Score) | +//| Copyright 2026, xxxxxxxx| +//+------------------------------------------------------------------+ +#property copyright "Copyright 2026, xxxxxxxx" +#property version "1.00" + +#ifndef RVSCORE_CALCULATOR_MQH +#define RVSCORE_CALCULATOR_MQH + +#include + +//+==================================================================+ +//| CLASS: CRVScoreCalculator | +//| Continuous Statistical Dispersion Engine around Rolling VWAP | +//+==================================================================+ +class CRVScoreCalculator + { +protected: + int m_sigma_period; + CRollingVWAPCalculator *m_rolling_vwap_calc; + + // Persistent Buffers for State Preservation + double m_vwap_buf[]; + double m_diff_sq_buf[]; + +public: + CRVScoreCalculator(void); + virtual ~CRVScoreCalculator(void); + + bool Init(const int sigma_period, + const ENUM_ROLLING_TYPE rolling_type, + const int rolling_window, + const ENUM_APPLIED_VOLUME vol_type, + const bool is_heikin_ashi = false); + + void Calculate(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[], + double &out_rvscore[]); + }; + +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CRVScoreCalculator::CRVScoreCalculator(void) : + m_sigma_period(20), + m_rolling_vwap_calc(NULL) + { + ArraySetAsSeries(m_vwap_buf, false); + ArraySetAsSeries(m_diff_sq_buf, false); + } + +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CRVScoreCalculator::~CRVScoreCalculator(void) + { + if(CheckPointer(m_rolling_vwap_calc) != POINTER_INVALID) + { + delete m_rolling_vwap_calc; + m_rolling_vwap_calc = NULL; + } + } + +//+------------------------------------------------------------------+ +//| Engine Initialization | +//+------------------------------------------------------------------+ +bool CRVScoreCalculator::Init(const int sigma_period, + const ENUM_ROLLING_TYPE rolling_type, + const int rolling_window, + const ENUM_APPLIED_VOLUME vol_type, + const bool is_heikin_ashi) + { + m_sigma_period = (sigma_period < 2) ? 2 : sigma_period; + + if(CheckPointer(m_rolling_vwap_calc) != POINTER_INVALID) + { + delete m_rolling_vwap_calc; + m_rolling_vwap_calc = NULL; + } + + if(is_heikin_ashi) + m_rolling_vwap_calc = new CRollingVWAPCalculator_HA(); + else + m_rolling_vwap_calc = new CRollingVWAPCalculator(); + + if(CheckPointer(m_rolling_vwap_calc) == POINTER_INVALID) + return false; + + return m_rolling_vwap_calc.Init(rolling_type, rolling_window, vol_type, true); + } + +//+------------------------------------------------------------------+ +//| Incremental Dispersion Calculation (O(1)) | +//+------------------------------------------------------------------+ +void CRVScoreCalculator::Calculate(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[], + double &out_rvscore[]) + { + if(rates_total < 2 || CheckPointer(m_rolling_vwap_calc) == POINTER_INVALID) + return; + +// 1. Safe Allocation of Internal Registers + if(ArraySize(m_vwap_buf) != rates_total) + { + ArrayResize(m_vwap_buf, rates_total); + ArrayResize(m_diff_sq_buf, rates_total); + ArraySetAsSeries(m_vwap_buf, false); + ArraySetAsSeries(m_diff_sq_buf, false); + } + + if(ArraySize(out_rvscore) != rates_total) + { + ArrayResize(out_rvscore, rates_total); + ArraySetAsSeries(out_rvscore, false); + ArrayInitialize(out_rvscore, 0.0); + } + +// 2. Compute Continuous Underlying Rolling VWAP Stream + m_rolling_vwap_calc.Calculate(rates_total, prev_calculated, time, open, high, low, close, + tick_volume, volume, m_vwap_buf); + + int start = (prev_calculated > 0) ? (prev_calculated - 1) : 0; + +// 3. Compute Squared Deviations + for(int i = start; i < rates_total; i++) + { + double diff = close[i] - m_vwap_buf[i]; + m_diff_sq_buf[i] = diff * diff; + } + +// 4. Compute Normalized Sigma Z-Score + for(int i = start; i < rates_total; i++) + { + double sum_sq = 0.0; + int count = 0; + + // Sliding lookback across continuous series + int lookback_limit = MathMin(i + 1, m_sigma_period); + for(int j = 0; j < lookback_limit; j++) + { + sum_sq += m_diff_sq_buf[i - j]; + count++; + } + + double std_dev = (count > 0) ? MathSqrt(sum_sq / (double)count) : 0.0; + + // Strict Floating-Point Epsilon Guard + if(std_dev > 1.0e-9) + out_rvscore[i] = (close[i] - m_vwap_buf[i]) / std_dev; + else + out_rvscore[i] = 0.0; + } + } + +#endif // RVSCORE_CALCULATOR_MQH +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Quant/RVScore_Pro.mq5 b/Indicators/MyIndicators/Quant/RVScore_Pro.mq5 new file mode 100644 index 00000000..0f22f207 --- /dev/null +++ b/Indicators/MyIndicators/Quant/RVScore_Pro.mq5 @@ -0,0 +1,572 @@ +//+------------------------------------------------------------------+ +//| RVScore_Pro.mq5| +//| Copyright 2026, xxxxxxxx| +//+------------------------------------------------------------------+ +#property copyright "Copyright 2026, xxxxxxxx" +#property version "3.20" +#property description "Statistical RV-Score Oscillator (Rolling VWAP Z-Score)." +#property description "Measures standardized dispersion from continuous Volume-Weighted Average Price." + +#property indicator_separate_window +#property indicator_buffers 3 +#property indicator_plots 2 + +//--- Plot 1: RV-Score Histogram (Institutional Swapped Thermal Matrix) +#property indicator_label1 "RV-Score" +#property indicator_type1 DRAW_COLOR_HISTOGRAM +// Swapped Palette Index: +// 0: Noise/Neutral (Gray) +// 1: Bullish Flow (LightSkyBlue) +// 2: Bullish Climax (DeepSkyBlue) +// 3: Bearish Flow (Coral) +// 4: Bearish Climax (OrangeRed) +#property indicator_color1 clrGray, clrLightSkyBlue, clrDeepSkyBlue, clrCoral, clrOrangeRed +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +//--- Plot 2: Optional Smoothed Signal Line +#property indicator_label2 "Signal" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrFireBrick +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +//--- Included Core Engines & Frameworks +#include +#include +#include + +//--- Candle Source Enum +#ifndef ENUM_CANDLE_SOURCE_DEFINED +#define ENUM_CANDLE_SOURCE_DEFINED +enum ENUM_CANDLE_SOURCE + { + CANDLE_STANDARD, // Standard OHLC Data + CANDLE_HEIKIN_ASHI // Heikin Ashi Smoothed Data + }; +#endif + +//--- Inputs +input group "--- Timeframe Settings ---" +input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // Calculation Timeframe (Current or HTF) + +input group "--- Rolling VWAP Engine ---" +input ENUM_ROLLING_TYPE InpRollingType = ROLLING_BARS; // Rolling Window Type +input int InpRollingWindow = 144; // Rolling Window (Bars or Minutes) +input int InpSigmaPeriod = 20; // Volatility Lookback (Sigma) + +input group "--- Calculation Sources ---" +input ENUM_APPLIED_VOLUME InpVolumeType = VOLUME_TICK; // Applied Volume Type +input ENUM_CANDLE_SOURCE InpCandleSource = CANDLE_STANDARD; // Candle Source + +input group "--- Signal Line Settings ---" +input bool InpShowSignal = true; // Show Signal Line? +input int InpSignalPeriod = 5; // Signal Period +input ENUM_MA_TYPE InpSignalType = EMA; // Signal MA Algorithm +input color InpColorSignal = clrFireBrick; // Signal Line Color + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +input group "--- Indicator Levels (Sigma Multiples) ---" +input double InpLevelFlowHigh = 1.5; // High Warning Level (Bullish Flow) +input double InpLevelFlowLow = -1.5; // Low Warning Level (Bearish Flow) +input double InpLevelClimaxHigh = 2.0; // High Climax Level (Bullish Climax) +input double InpLevelClimaxLow = -2.0; // Low Climax Level (Bearish Climax) +input double InpLevelExtremeHigh = 2.5; // High Exhaustion Level +input double InpLevelExtremeLow = -2.5; // Low Exhaustion Level +input color InpLevelColor = clrSilver; // Levels Color +input ENUM_LINE_STYLE InpLevelStyle = STYLE_DOT; // Levels Style + +//--- Indicator Output Buffers +double ExtRVScoreBuffer[]; +double ExtColorsBuffer[]; +double ExtSignalBuffer[]; + +//--- Volume Internal Cache (For Potential VWMA Signal Calculations) +double g_double_volume[]; + +//--- HTF Synchronized Data Caches +double h_open[], h_high[], h_low[], h_close[]; +long h_tick_vol[], h_vol[]; +double h_res_rvscore[], h_res_color[], h_res_signal[]; +datetime h_time[]; + +//--- Global Dynamic Calculation Pointers +CRVScoreCalculator *g_calc = NULL; +CMovingAverageCalculator *g_signal_calculator = NULL; + +bool g_is_mtf_mode = false; +ENUM_TIMEFRAMES g_calc_timeframe; +bool g_data_ready = false; +bool g_data_synced = false; +int g_htf_count = 0; +datetime g_last_htf_time = 0; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + g_data_ready = false; + g_data_synced = false; + g_htf_count = 0; + g_last_htf_time = 0; + +// 1. Timeframe Resolution & Guard + g_calc_timeframe = InpTimeframe; + if(g_calc_timeframe == PERIOD_CURRENT) + g_calc_timeframe = (ENUM_TIMEFRAMES)Period(); + + if(g_calc_timeframe < Period()) + { + PrintFormat("RV-Score Error: Target timeframe (%s) must be >= current timeframe (%s).", + EnumToString(g_calc_timeframe), EnumToString(Period())); + return INIT_PARAMETERS_INCORRECT; + } + + g_is_mtf_mode = (g_calc_timeframe > Period()); + +// 2. Buffer Bindings + SetIndexBuffer(0, ExtRVScoreBuffer, INDICATOR_DATA); + SetIndexBuffer(1, ExtColorsBuffer, INDICATOR_COLOR_INDEX); + SetIndexBuffer(2, ExtSignalBuffer, INDICATOR_DATA); + + ArraySetAsSeries(ExtRVScoreBuffer, false); + ArraySetAsSeries(ExtColorsBuffer, false); + ArraySetAsSeries(ExtSignalBuffer, false); + + ArrayInitialize(ExtRVScoreBuffer, 0.0); + ArrayInitialize(ExtColorsBuffer, 0.0); + ArrayInitialize(ExtSignalBuffer, EMPTY_VALUE); + + PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); + +// 3. Configure Dynamic Sigma Levels + IndicatorSetInteger(INDICATOR_LEVELS, 6); + IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, InpLevelFlowHigh); + IndicatorSetDouble(INDICATOR_LEVELVALUE, 1, InpLevelFlowLow); + IndicatorSetDouble(INDICATOR_LEVELVALUE, 2, InpLevelClimaxHigh); + IndicatorSetDouble(INDICATOR_LEVELVALUE, 3, InpLevelClimaxLow); + IndicatorSetDouble(INDICATOR_LEVELVALUE, 4, InpLevelExtremeHigh); + IndicatorSetDouble(INDICATOR_LEVELVALUE, 5, InpLevelExtremeLow); + + IndicatorSetInteger(INDICATOR_LEVELCOLOR, InpLevelColor); + IndicatorSetInteger(INDICATOR_LEVELSTYLE, InpLevelStyle); + +// 4. Instantiate Core RV-Score Engine + g_calc = new CRVScoreCalculator(); + if(CheckPointer(g_calc) == POINTER_INVALID) + { + Print("RV-Score Critical Error: Failed to allocate math engine."); + return INIT_FAILED; + } + + bool is_ha = (InpCandleSource == CANDLE_HEIKIN_ASHI); + if(!g_calc.Init(InpSigmaPeriod, InpRollingType, InpRollingWindow, InpVolumeType, is_ha)) + { + Print("RV-Score Critical Error: Engine initialization failed."); + return INIT_FAILED; + } + +// 5. Instantiate Signal Line Smoothing Calculator + if(InpShowSignal) + { + PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE); + PlotIndexSetInteger(1, PLOT_LINE_COLOR, InpColorSignal); + PlotIndexSetString(1, PLOT_LABEL, "Signal"); + + g_signal_calculator = new CMovingAverageCalculator(); + if(CheckPointer(g_signal_calculator) == POINTER_INVALID || + !g_signal_calculator.Init(InpSignalPeriod, InpSignalType)) + { + Print("RV-Score Critical Error: Failed to initialize Signal Engine."); + return INIT_FAILED; + } + } + else + { + PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_NONE); + PlotIndexSetString(1, PLOT_LABEL, NULL); + } + +// 6. Dynamic Indicator Title + string ha_tag = is_ha ? " HA" : ""; + string tf_str = g_is_mtf_mode ? (" [" + EnumToString(g_calc_timeframe) + "]") : ""; + string type_str = (InpRollingType == ROLLING_BARS) ? "Bars" : "Min"; + string sig_str = ""; + if(InpShowSignal) + { + string sig_name = EnumToString(InpSignalType); + StringToUpper(sig_name); + sig_str = StringFormat(" | %s(%d)", sig_name, InpSignalPeriod); + } + + string short_name = StringFormat("RV-Score%s%s(%d %s, %dσ)%s", + ha_tag, tf_str, + InpRollingWindow, type_str, + InpSigmaPeriod, + sig_str); + + IndicatorSetString(INDICATOR_SHORTNAME, short_name); + PlotIndexSetString(0, PLOT_LABEL, "RV-Score"); + + int draw_begin = InpSigmaPeriod + InpSignalPeriod + 5; + if(g_is_mtf_mode) + draw_begin = 0; + + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, draw_begin); + IndicatorSetInteger(INDICATOR_DIGITS, 2); + +// 7. Initialize Asynchronous Timer Daemon for MTF + if(g_is_mtf_mode) + EventSetTimer(1); + + return(INIT_SUCCEEDED); + } + +//+------------------------------------------------------------------+ +//| Custom indicator deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + if(g_is_mtf_mode) + EventKillTimer(); + + if(CheckPointer(g_calc) != POINTER_INVALID) + { + delete g_calc; + g_calc = NULL; + } + + if(CheckPointer(g_signal_calculator) != POINTER_INVALID) + { + delete g_signal_calculator; + g_signal_calculator = NULL; + } + } + +//+------------------------------------------------------------------+ +//| Custom indicator calculation iteration | +//+------------------------------------------------------------------+ +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 required_bars = InpSigmaPeriod + InpSignalPeriod + 10; + if(rates_total < required_bars || CheckPointer(g_calc) == POINTER_INVALID) + return 0; + +// Strict chronological alignment + ArraySetAsSeries(time, false); + ArraySetAsSeries(open, false); + ArraySetAsSeries(high, false); + ArraySetAsSeries(low, false); + ArraySetAsSeries(close, false); + ArraySetAsSeries(tick_volume, false); + ArraySetAsSeries(volume, false); + +//=================================================================== +// MODE 1: Direct Native Timeframe Calculation (Zero-Lag O(1)) +//=================================================================== + if(!g_is_mtf_mode) + { + long volume_limit = (long)SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT); + if(ArraySize(g_double_volume) != rates_total) + { + ArrayResize(g_double_volume, rates_total); + ArraySetAsSeries(g_double_volume, false); + } + + 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 Continuous RV-Score + g_calc.Calculate(rates_total, prev_calculated, time, open, high, low, close, + tick_volume, volume, ExtRVScoreBuffer); + + // 2. Calculate Signal MA Line + if(InpShowSignal && CheckPointer(g_signal_calculator) != POINTER_INVALID) + { + g_signal_calculator.CalculateOnArray(rates_total, prev_calculated, ExtRVScoreBuffer, + g_double_volume, ExtSignalBuffer, InpSigmaPeriod); + } + else + { + for(int i = start_sync; i < rates_total; i++) + ExtSignalBuffer[i] = EMPTY_VALUE; + } + + // 3. Dynamic Swapped Thermal Palette Coloring + int start_idx = (prev_calculated > 0) ? prev_calculated - 1 : InpSigmaPeriod; + for(int i = start_idx; i < rates_total; i++) + { + double v = ExtRVScoreBuffer[i]; + + if(v >= InpLevelClimaxHigh) + ExtColorsBuffer[i] = 2.0; // DeepSkyBlue (Bullish Climax) + else + if(v >= InpLevelFlowHigh) + ExtColorsBuffer[i] = 1.0; // LightSkyBlue (Bullish Flow) + else + if(v <= InpLevelClimaxLow) + ExtColorsBuffer[i] = 4.0; // OrangeRed (Bearish Climax) + else + if(v <= InpLevelFlowLow) + ExtColorsBuffer[i] = 3.0; // Coral (Bearish Flow) + else + ExtColorsBuffer[i] = 0.0; // Gray (Neutral Noise Zone) + } + + return rates_total; + } + +//=================================================================== +// MODE 2: Synchronized MTF Engine +//=================================================================== + int htf_required = (InpRollingType == ROLLING_BARS) ? (InpRollingWindow + InpSigmaPeriod + 10) : (InpSigmaPeriod + 50); + if(!CDataSync::EnsureHTFDataReady(_Symbol, g_calc_timeframe, htf_required)) + { + g_data_synced = false; + return 0; + } + + g_data_synced = true; + + datetime htf_time_current = iTime(_Symbol, g_calc_timeframe, 0); + bool htf_updated = (htf_time_current != g_last_htf_time); + + if(htf_updated || prev_calculated == 0) + { + g_last_htf_time = htf_time_current; + + int htf_bars = iBars(_Symbol, g_calc_timeframe); + if(htf_bars < htf_required) + { + g_data_ready = false; + return 0; + } + + g_htf_count = MathMin(htf_bars, 3000); // Enterprise memory safeguard + + // Resize all HTF caching arrays + ArrayResize(h_time, g_htf_count); + ArrayResize(h_open, g_htf_count); + ArrayResize(h_high, g_htf_count); + ArrayResize(h_low, g_htf_count); + ArrayResize(h_close, g_htf_count); + ArrayResize(h_tick_vol, g_htf_count); + ArrayResize(h_vol, g_htf_count); + ArrayResize(h_res_rvscore, g_htf_count); + ArrayResize(h_res_color, g_htf_count); + ArrayResize(h_res_signal, g_htf_count); + + // Force chronological alignment + ArraySetAsSeries(h_time, false); + ArraySetAsSeries(h_open, false); + ArraySetAsSeries(h_high, false); + ArraySetAsSeries(h_low, false); + ArraySetAsSeries(h_close, false); + ArraySetAsSeries(h_tick_vol, false); + ArraySetAsSeries(h_vol, false); + ArraySetAsSeries(h_res_rvscore, false); + ArraySetAsSeries(h_res_color, false); + ArraySetAsSeries(h_res_signal, false); + + // Copy pricing & volume data + if(CopyTime(_Symbol, g_calc_timeframe, 0, g_htf_count, h_time) != g_htf_count || + CopyOpen(_Symbol, g_calc_timeframe, 0, g_htf_count, h_open) != g_htf_count || + CopyHigh(_Symbol, g_calc_timeframe, 0, g_htf_count, h_high) != g_htf_count || + CopyLow(_Symbol, g_calc_timeframe, 0, g_htf_count, h_low) != g_htf_count || + CopyClose(_Symbol, g_calc_timeframe, 0, g_htf_count, h_close) != g_htf_count || + CopyTickVolume(_Symbol, g_calc_timeframe, 0, g_htf_count, h_tick_vol) != g_htf_count) + { + g_data_ready = false; + return 0; + } + + long vol_limit = (long)SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT); + if(vol_limit > 0) + CopyRealVolume(_Symbol, g_calc_timeframe, 0, g_htf_count, h_vol); + else + ArrayCopy(h_vol, h_tick_vol, 0, 0, g_htf_count); + + // Compute HTF RV-Score Values + g_calc.Calculate(g_htf_count, 0, h_time, h_open, h_high, h_low, h_close, + h_tick_vol, h_vol, h_res_rvscore); + + // Compute HTF Signal Line + if(InpShowSignal && CheckPointer(g_signal_calculator) != POINTER_INVALID) + { + double htf_double_vol[]; + ArrayResize(htf_double_vol, g_htf_count); + ArraySetAsSeries(htf_double_vol, false); + for(int k = 0; k < g_htf_count; k++) + htf_double_vol[k] = (double)h_vol[k]; + + g_signal_calculator.CalculateOnArray(g_htf_count, 0, h_res_rvscore, + htf_double_vol, h_res_signal, InpSigmaPeriod); + } + + // Color HTF Cache + for(int i = 0; i < g_htf_count; i++) + { + double v = h_res_rvscore[i]; + if(v >= InpLevelClimaxHigh) + h_res_color[i] = 2.0; + else + if(v >= InpLevelFlowHigh) + h_res_color[i] = 1.0; + else + if(v <= InpLevelClimaxLow) + h_res_color[i] = 4.0; + else + if(v <= InpLevelFlowLow) + h_res_color[i] = 3.0; + else + h_res_color[i] = 0.0; + } + + g_data_ready = true; + } + + if(!g_data_ready) + return 0; + +// Stateful live-bar update for active forming HTF candle + int live_idx = g_htf_count - 1; + if(live_idx >= htf_required) + { + double o[1], h[1], l[1], c[1]; + datetime t_bar[1]; + long tv[1], v[1]; + + int shift = iBarShift(_Symbol, g_calc_timeframe, htf_time_current, false); + if(shift >= 0 && + CopyTime(_Symbol, g_calc_timeframe, shift, 1, t_bar) == 1 && + CopyOpen(_Symbol, g_calc_timeframe, shift, 1, o) == 1 && + CopyHigh(_Symbol, g_calc_timeframe, shift, 1, h) == 1 && + CopyLow(_Symbol, g_calc_timeframe, shift, 1, l) == 1 && + CopyClose(_Symbol, g_calc_timeframe, shift, 1, c) == 1 && + CopyTickVolume(_Symbol, g_calc_timeframe, shift, 1, tv) == 1) + { + h_time[live_idx] = t_bar[0]; + h_open[live_idx] = o[0]; + h_high[live_idx] = h[0]; + h_low[live_idx] = l[0]; + h_close[live_idx] = c[0]; + h_tick_vol[live_idx] = tv[0]; + + long vol_limit = (long)SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT); + if(vol_limit > 0 && CopyRealVolume(_Symbol, g_calc_timeframe, shift, 1, v) == 1) + h_vol[live_idx] = v[0]; + else + h_vol[live_idx] = tv[0]; + + // Mock update on live bar + g_calc.Calculate(g_htf_count, g_htf_count, h_time, h_open, h_high, h_low, h_close, + h_tick_vol, h_vol, h_res_rvscore); + + if(InpShowSignal && CheckPointer(g_signal_calculator) != POINTER_INVALID) + { + double htf_double_vol[]; + ArrayResize(htf_double_vol, g_htf_count); + ArraySetAsSeries(htf_double_vol, false); + for(int k = 0; k < g_htf_count; k++) + htf_double_vol[k] = (double)h_vol[k]; + + g_signal_calculator.CalculateOnArray(g_htf_count, g_htf_count, h_res_rvscore, + htf_double_vol, h_res_signal, InpSigmaPeriod); + } + + double v_val = h_res_rvscore[live_idx]; + if(v_val >= InpLevelClimaxHigh) + h_res_color[live_idx] = 2.0; + else + if(v_val >= InpLevelFlowHigh) + h_res_color[live_idx] = 1.0; + else + if(v_val <= InpLevelClimaxLow) + h_res_color[live_idx] = 4.0; + else + if(v_val <= InpLevelFlowLow) + h_res_color[live_idx] = 3.0; + else + h_res_color[live_idx] = 0.0; + } + } + +// Forming LTF Block Flat-Force Anchor (The Staircase Solution) + int start = (prev_calculated > 0) ? prev_calculated - 1 : 0; + + int first_bar_of_forming_htf = rates_total - 1; + while(first_bar_of_forming_htf > 0 && + iBarShift(_Symbol, g_calc_timeframe, time[first_bar_of_forming_htf], false) == 0) + { + first_bar_of_forming_htf--; + } + first_bar_of_forming_htf++; + + if(start > first_bar_of_forming_htf) + start = first_bar_of_forming_htf; + +// Chronological Mapping Loop to Chart Timeframe + for(int i = start; i < rates_total; i++) + { + datetime t = time[i]; + int shift_htf = iBarShift(_Symbol, g_calc_timeframe, t, false); + + if(shift_htf >= 0) + { + int idx_htf = g_htf_count - 1 - shift_htf; + if(idx_htf >= 0 && idx_htf < g_htf_count) + { + ExtRVScoreBuffer[i] = h_res_rvscore[idx_htf]; + ExtColorsBuffer[i] = h_res_color[idx_htf]; + ExtSignalBuffer[i] = InpShowSignal ? h_res_signal[idx_htf] : EMPTY_VALUE; + } + else + { + ExtRVScoreBuffer[i] = 0.0; + ExtColorsBuffer[i] = 0.0; + ExtSignalBuffer[i] = EMPTY_VALUE; + } + } + else + { + ExtRVScoreBuffer[i] = 0.0; + ExtColorsBuffer[i] = 0.0; + ExtSignalBuffer[i] = EMPTY_VALUE; + } + } + + return rates_total; + } + +//+------------------------------------------------------------------+ +//| OnTimer Event Handler (Data Synchronization Daemon) | +//+------------------------------------------------------------------+ +void OnTimer() + { + int htf_required = (InpRollingType == ROLLING_BARS) ? (InpRollingWindow + InpSigmaPeriod + 10) : (InpSigmaPeriod + 50); + CDataSync::OnTimerUpdate(_Symbol, g_calc_timeframe, htf_required, g_data_synced); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Quant/RVScore_Pro_Documentation.md b/Indicators/MyIndicators/Quant/RVScore_Pro_Documentation.md new file mode 100644 index 00000000..5c4a7e76 --- /dev/null +++ b/Indicators/MyIndicators/Quant/RVScore_Pro_Documentation.md @@ -0,0 +1,338 @@ +# Rolling Volume-Weighted Z-Score (RV-Score) Pro (v3.20) + +Quantitative Continuous Volume-Weighted Dispersion & Stationary Fair-Value Oscillator + +--- + +## 1. Summary (Introduction) + +**RV-Score Pro** is an institutional-grade statistical momentum oscillator that measures normalized price dispersion from a **continuous Rolling Volume-Weighted Average Price (Rolling VWAP)** in standardized units of standard deviation ($\sigma$). + +While traditional session-anchored indicators (such as standard V-Score) reset their memory at daily or weekly boundaries—causing artificial volatility pinching at session opens and late-day inertia—**RV-Score evaluates price against a continuously moving, volume-weighted institutional liquidity anchor**. + +By calculating dispersion over a rolling historical horizon (e.g., last 144 bars or continuous 24 hours), RV-Score generates a **strictly stationary, zero-boundary oscillator** that eliminates opening-bell distortion while preserving volume-weighted market truth. + +```text + +┌────────────────────────────────────────────────────────────────────────┐ +│ RV-SCORE DISPERSION MODEL │ +├────────────────────────────────────────────────────────────────────────┤ +│ RV-Score(t) = [ Close(t) - RollingVWAP(t) ] / RollingStdDev(t) │ +│ Expressed in standardized Sigma Multiples (σ) │ +│ │ +│ • Continuous Zero-Boundary Horizon (No Session Cutoff Distortion) │ +│ • Amortized O(1) Prefix-Sum Integration │ +└────────────────────────────────────────────────────────────────────────┘ + +``` + +### The Four Z-Score Indicator Paradigms + +- **Z-Score Pro:** Measures Gaussian dispersion from a static Moving Average (Price/Time axis). +- **K-Score Pro:** Measures kinetic elasticity from Kaufman's Adaptive Moving Average (Efficiency/Regime axis). +- **V-Score Pro:** Measures statistical overextension from Anchored/Session VWAP (Session-Volume axis). +- **RV-Score Pro:** Measures continuous statistical dispersion from Rolling VWAP (Stationary Volume-Weighted axis). + +### Key Capabilities + +- **Stationary Volume-Weighted Baseline:** Eliminates session-open false spikes and late-day paralysis by continuously sliding both the VWAP anchor and volatility lookback window. +- **Swapped Thermal 5-Zone Palette:** Visually classifies market states into noise/equilibrium, active institutional flow, and statistical climax exhaustion. +- **Integrated Signal Smoothing Engine:** Direct composition with `CMovingAverageCalculator`, providing 8 advanced smoothing algorithms (SMA, EMA, SMMA, LWMA, TMA, DEMA, TEMA, VWMA) over the raw RV-Score histogram. +- **Unified 2026 MTF Architecture:** Maps higher-timeframe RV-Score histograms (e.g., H1 RV-Score) onto lower-timeframe execution charts (M5, M1) via `DataSync_Tools.mqh` with non-warping staircase flat-force synchronization. + +--- + +## 2. Mathematical Foundations & Continuous Normalization + +```text + + +2.5σ (Extreme Exhaustion / Climax) + ───────────────────────────────────────────────────────────── DeepSkyBlue (Bull Climax) + +1.5σ (Bullish Flow Threshold) + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LightSkyBlue (Bull Flow) + 0.0σ (Rolling VWAP Equilibrium) + ───────────────────────────────────────────────────────────── Gray (Noise / Fair Value) + -1.5σ (Bearish Flow Threshold) + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Coral (Bear Flow) + -2.5σ (Extreme Exhaustion / Climax) + ───────────────────────────────────────────────────────────── OrangeRed (Bear Climax) + +``` + +### 2.1. Continuous Rolling VWAP Baseline ($\mu_{\text{RVWAP}, t}$) + +Calculated via cumulative prefix sums over the sliding window $W$ (bars or elapsed seconds): +$$\mu_{\text{RVWAP}, t} = \frac{\text{SumTPV}_t - \text{SumTPV}_{t - W}}{\text{SumVol}_t - \text{SumVol}_{t - W}}$$ +*where $\text{TP}_k = \frac{H_k + L_k + C_k}{3}$ and $V_k$ is the applied volume.* + +### 2.2. Continuous Deviation Metric ($\text{Diff}_k$) + +$$\text{Diff}_k = C_k - \mu_{\text{RVWAP}, k}$$ + +### 2.3. Rolling Standard Deviation Around Rolling VWAP ($\sigma_{\text{Rolling}, t}$) + +Given the volatility lookback period $P = \text{InpSigmaPeriod}$: +$$\sigma_{\text{Rolling}, t} = \sqrt{\frac{1}{P} \sum_{k=0}^{P - 1} \left( \text{Diff}_{t - k} \right)^2}$$ + +### 2.4. Normalized RV-Score Formulation + +$$\text{RVScore}_t = \begin{cases} \frac{C_t - \mu_{\text{RVWAP}, t}}{\sigma_{\text{Rolling}, t}}, & \text{if } \sigma_{\text{Rolling}, t} > 10^{-9} \\ 0.0, & \text{otherwise} \end{cases}$$ + +--- + +### 2.5. Swapped Thermal 5-Zone Color Palette + +| State Index | Color | Classification | Sigma Level Trigger | Institutional Market Action | +| :---: | :---: | :--- | :--- | :--- | +| **0.0** | `clrGray` | **Noise / Equilibrium** | $\|\text{RVScore}\| \le 1.5\sigma$ | Price oscillating within stationary fair-value bounds. | +| **1.0** | `clrLightSkyBlue` | **Bullish Flow** | $+1.5\sigma < \text{RVScore} \le +2.0\sigma$ | Sustained institutional volume expansion to the upside. | +| **2.0** | `clrDeepSkyBlue` | **Bullish Climax** | $\text{RVScore} > +2.0\sigma$ | Overbought statistical extremity; liquidity absorption warning. | +| **3.0** | `clrCoral` | **Bearish Flow** | $-2.0\sigma \le \text{RVScore} < -1.5\sigma$ | Sustained institutional selling pressure active. | +| **4.0** | `clrOrangeRed` | **Bearish Climax** | $\text{RVScore} < -2.0\sigma$ | Capitulation liquidation floor; high short-squeeze probability. | + +--- + +## 3. MQL5 Architecture & Engineering Standards + +```text + +┌────────────────────────────────────────────────────────┐ +│ RVScore_Calculator.mqh │ +│ (Core Math Engine - Prefix Sums & Dispersion) │ +└──────────────────────────┬─────────────────────────────┘ + │ Outputs RV-Score Values in O(1) + ▼ +┌────────────────────────────────────────────────────────┐ +│ RVScore_Pro.mq5 │ +│ (Unified Wrapper: Native Timeframe & MTF Engine) │ +├──────────────────────────┬─────────────────────────────┤ +│ Buffer Layer (3) │ Centralized Framework │ +│ • ExtRVScoreBuffer │ • Rolling_VWAP_Engine │ +│ • ExtColorsBuffer │ • MovingAverage_Engine │ +│ • ExtSignalBuffer │ • DataSync_Tools.mqh │ +└──────────────────────────┴─────────────────────────────┘ + +``` + +1. **Zero Boundary Artifacts:** Unlike anchored VWAP systems, the absence of session cutoffs completely prevents array index desynchronization and variance pinching. +2. **Separation of Concerns:** `CRVScoreCalculator` embeds `CRollingVWAPCalculator` via composition, maintaining independent memory spaces for volume integration and volatility standard deviation. +3. **2026 MTF Framework (`DataSync_Tools.mqh`):** Higher-timeframe RV-Score histograms are projected onto lower-timeframe charts using flat-force step synchronization, guaranteeing zero repainting on closed candles. + +--- + +## 4. Parameters Reference + +### Timeframe Settings + +- `InpTimeframe` (*default: `PERIOD_CURRENT`*): Calculation timeframe. Set to `PERIOD_CURRENT` for native zero-lag execution, or choose a higher timeframe (e.g., `PERIOD_H1`) to activate the synchronized MTF engine. + +### Rolling VWAP Engine + +- `InpRollingType` (*default: `ROLLING_BARS`*): + - `ROLLING_BARS`: Sliding window of fixed bar length. + - `ROLLING_TIME`: Continuous physical time window in minutes. +- `InpRollingWindow` (*default: `144`*): Window length (bar count or minutes). +- `InpSigmaPeriod` (*default: `20`*): Lookback period ($P$) for computing standard deviation variance around the Rolling VWAP. + +### Calculation Sources + +- `InpVolumeType` (*default: `VOLUME_TICK`*): Applied volume source (`VOLUME_TICK` or `VOLUME_REAL`). +- `InpCandleSource` (*default: `CANDLE_STANDARD`*): Price series source (`CANDLE_STANDARD` or `CANDLE_HEIKIN_ASHI`). + +### Signal Line Settings + +- `InpShowSignal` (*default: `true`*): Toggles visibility of the smoothed Signal MA line. +- `InpSignalPeriod` (*default: `5`*): Lookback period for the signal line. +- `InpSignalType` (*default: `EMA`*): Smoothing algorithm (`SMA`, `EMA`, `SMMA`, `LWMA`, `TMA`, `DEMA`, `TEMA`, `VWMA`). +- `InpColorSignal` (*default: `clrFireBrick`*): Color applied to the signal line plot. + +### Indicator Levels (Sigma Multiples) + +- `InpLevelFlowHigh` (*default: `1.5`*): Bullish Flow threshold boundary. +- `InpLevelFlowLow` (*default: `-1.5`*): Bearish Flow threshold boundary. +- `InpLevelClimaxHigh` (*default: `2.0`*): Bullish Climax threshold (`DeepSkyBlue`). +- `InpLevelClimaxLow` (*default: `-2.0`*): Bearish Climax threshold (`OrangeRed`). +- `InpLevelExtremeHigh` (*default: `2.5`*): Extreme statistical expansion ceiling. +- `InpLevelExtremeLow` (*default: `-2.5`*): Extreme statistical capitulation floor. +- `InpLevelColor` (*default: `clrSilver`*): Color of horizontal level lines. +- `InpLevelStyle` (*default: `STYLE_DOT`*): Line style of horizontal level lines. + +--- + +## 5. Quantitative Trading Playbooks + +```text + +┌────────────────────────────────────────────────────────────────────────┐ +│ RV-SCORE INSTITUTIONAL PLAYBOOKS │ +├────────────────────────────────────────────────────────────────────────┤ +│ 1. Continuous Climax Fade: Fade statistical overextensions when │ +│ RV-Score > +2.0σ and hooks back. │ +│ 2. Volume Flow Expansion: Trend continuation when RV-Score holds │ +│ between +1.5σ and +2.0σ (Flow Zone). │ +│ 3. Signal Line Crossover: Zero-lag trend confirmation upon Signal MA │ +│ crossings inside/outside the flow zones. │ +└────────────────────────────────────────────────────────────────────────┘ + +``` + +### 5.1. Continuous Climax Mean Reversion ($\pm 2.0\sigma \dots \pm 2.5\sigma$) + +- **Context:** Price aggressively expands away from the Rolling VWAP, pushing the RV-Score into the Climax zone ($> +2.0\sigma$, `DeepSkyBlue` or $< -2.0\sigma$, `OrangeRed`). +- **Short Reversal Setup:** + 1. RV-Score exceeds $+2.0\sigma$. + 2. Histogram bar prints lower than the preceding bar and crosses **below** the Signal MA line. + 3. Enter Short targeting the zero-line fair value ($0.0\sigma$). +- **Long Capitulation Bounce:** + 1. RV-Score flushes below $-2.0\sigma$ or $-2.5\sigma$ during a panic selloff. + 2. Histogram prints a higher low and crosses **above** the Signal MA line. + 3. Enter Long targeting the $0.0\sigma$ equilibrium. + +### 5.2. Volume Flow Expansion Continuation ($+1.5\sigma \dots +2.0\sigma$) + +- **Context:** In strong institutional markup/markdown phases, prices stay persistently overextended without snapping back. +- **Bullish Momentum Rule:** + - As long as RV-Score holds between $+1.5\sigma$ (`LightSkyBlue`) and $+2.0\sigma$, maintain long trend-following exposure. + - Exit or tighten trailing stops only when the histogram falls back below $+1.5\sigma$ into the neutral gray zone. + +### 5.3. Multi-Timeframe Alignment (H1 RV-Score on M5 Execution) + +- Load `RVScore_Pro` with `InpTimeframe = PERIOD_H1` on an M5 trading chart. +- If H1 RV-Score is positive and above $+1.5\sigma$: Institutional money flow on the hourly horizon is bullish $\rightarrow$ Filter M5 execution to **Long signals only**. + +--- + +## 6. Indicator Buffer Map (For Developers & EA Integration) + +### Buffer Allocation + +| Buffer Index | Name | Type | Description | +| :---: | :---: | :---: | :--- | +| **0** | `ExtRVScoreBuffer` | `INDICATOR_DATA` | Standardized RV-Score Values in Sigma Units ($\sigma$) | +| **1** | `ExtColorsBuffer` | `INDICATOR_COLOR_INDEX` | Swapped Thermal 5-Zone Palette Index ($0.0 \dots 4.0$) | +| **2** | `ExtSignalBuffer` | `INDICATOR_DATA` | Smoothed Signal Moving Average Plot | + +*All buffers maintain strict chronological indexing (`ArraySetAsSeries = false`), ensuring direct compatibility with Expert Advisors and multi-asset scanner dashboards.* + +--- + +### MQL5 EA Integration Interface Template + +```mql5 +//+------------------------------------------------------------------+ +//| EA_RVScore_Interface.mq5 | +//| Copyright 2026, xxxxxxxx| +//+------------------------------------------------------------------+ +#property copyright "Copyright 2026, xxxxxxxx" +#property version "1.00" +#property strict + +//--- Include Rolling VWAP Window Type Definition +#include +#include + +//--- EA Inputs +input group "=== RV-Score Filter Settings ===" +input ENUM_TIMEFRAMES InpRVTimeframe = PERIOD_CURRENT; // Timeframe +input ENUM_ROLLING_TYPE InpRVType = ROLLING_BARS; // Rolling Type +input int InpRVWindow = 144; // Rolling Window +input int InpRVSigmaPeriod = 20; // Volatility Lookback (Sigma) +input ENUM_APPLIED_VOLUME InpRVVolume = VOLUME_TICK; // Volume Type +input ENUM_CANDLE_SOURCE InpRVSource = CANDLE_STANDARD; // Candle Source +input bool InpShowSignal = true; // Enable Signal Line +input int InpSignalPeriod = 5; // Signal Period +input ENUM_MA_TYPE InpSignalType = EMA; // Signal MA Type + +//--- Global Indicator Handle +int g_rvscore_handle = INVALID_HANDLE; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + if(g_rvscore_handle != INVALID_HANDLE) + IndicatorRelease(g_rvscore_handle); + + // Instantiate handle to RVScore_Pro via iCustom + g_rvscore_handle = iCustom(_Symbol, + InpRVTimeframe, + "RVScore_Pro", + InpRVTimeframe, + InpRVType, + InpRVWindow, + InpRVSigmaPeriod, + InpRVVolume, + InpRVSource, + InpShowSignal, + InpSignalPeriod, + InpSignalType, + clrFireBrick, + 1.5, -1.5, 2.0, -2.0, 2.5, -2.5, + clrSilver, STYLE_DOT); + + if(g_rvscore_handle == INVALID_HANDLE) + { + PrintFormat("EA Error: Failed to create handle for RVScore_Pro. Error Code: %d", GetLastError()); + return INIT_FAILED; + } + + Print("EA Success: RVScore_Pro handle initialized successfully."); + return INIT_SUCCEEDED; + } + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + if(g_rvscore_handle != INVALID_HANDLE) + { + IndicatorRelease(g_rvscore_handle); + g_rvscore_handle = INVALID_HANDLE; + } + } + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + // Query last 2 closed bars and active live bar (3 values) + double score_val[3], color_val[3], signal_val[3]; + ArraySetAsSeries(score_val, true); // Index 0 = Live, 1 = Closed bar + ArraySetAsSeries(color_val, true); + ArraySetAsSeries(signal_val, true); + + // Read Buffer 0 (RV-Score), Buffer 1 (Colors), Buffer 2 (Signal) + if(CopyBuffer(g_rvscore_handle, 0, 0, 3, score_val) < 3 || + CopyBuffer(g_rvscore_handle, 1, 0, 3, color_val) < 3 || + CopyBuffer(g_rvscore_handle, 2, 0, 3, signal_val) < 3) + { + return; + } + + double closed_score = score_val[1]; + double closed_signal = signal_val[1]; + int closed_color = (int)color_val[1]; + + // Quantitative Signals + bool is_bullish_climax = (closed_color == 2); // DeepSkyBlue (> +2.0σ) + bool is_bearish_climax = (closed_color == 4); // OrangeRed (< -2.0σ) + bool is_bullish_flow = (closed_color == 1); // LightSkyBlue (+1.5σ to +2.0σ) + bool is_bearish_flow = (closed_color == 3); // Coral (-1.5σ to -2.0σ) + + // Signal Crossover Execution Logic + bool signal_cross_down = (score_val[2] >= signal_val[2] && score_val[1] < signal_val[1]); + bool signal_cross_up = (score_val[2] <= signal_val[2] && score_val[1] > signal_val[1]); + + // Telemetry Output + Comment(StringFormat("RV-Score [Bar 1]: %.2fσ | Signal: %.2fσ | State: %s\n" + "Climax Fade Short: %s | Climax Fade Long: %s", + closed_score, closed_signal, + is_bullish_climax ? "BULL CLIMAX" : (is_bearish_climax ? "BEAR CLIMAX" : (is_bullish_flow ? "BULL FLOW" : (is_bearish_flow ? "BEAR FLOW" : "EQUILIBRIUM"))), + (is_bullish_climax && signal_cross_down) ? "TRIGGERED" : "NO", + (is_bearish_climax && signal_cross_up) ? "TRIGGERED" : "NO")); + } +//+------------------------------------------------------------------+ +```