feat: add RVScore_Pro

This commit is contained in:
Toh4iem9
2026-09-14 16:39:43 +02:00
parent aafc8dcc80
commit 809ed2db91
3 changed files with 1082 additions and 0 deletions
+172
View File
@@ -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 <MyIncludes\Rolling_VWAP_Calculator.mqh>
//+==================================================================+
//| 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
//+------------------------------------------------------------------+
@@ -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 <MyIncludes\RVScore_Calculator.mqh>
#include <MyIncludes\MovingAverage_Engine.mqh>
#include <MyIncludes\DataSync_Tools.mqh>
//--- 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);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
@@ -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 <MyIncludes\Rolling_VWAP_Calculator.mqh>
#include <MyIncludes\MovingAverage_Engine.mqh>
//--- 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"));
}
//+------------------------------------------------------------------+
```