refactor: Upgraded with selectable MA smoothing types (including VWMA support)

This commit is contained in:
Toh4iem9
2026-08-18 17:12:07 +02:00
parent 805431af8a
commit 465b11406e
+93 -18
View File
@@ -3,9 +3,8 @@
//| Copyright 2026, xxxxxxxx| //| Copyright 2026, xxxxxxxx|
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
#property copyright "Copyright 2026, xxxxxxxx" #property copyright "Copyright 2026, xxxxxxxx"
#property version "3.10" // Upgraded with dynamic high-performance Standard/MTF support #property version "3.20" // Upgraded with selectable MA smoothing types (including VWMA support)
#property description "Professional Stochastic Momentum Index (SMI) with a signal line and" #property description "Professional Stochastic Momentum Index (SMI) with dynamic MTF and MA selections."
#property description "selectable candle source (Standard or Heikin Ashi)."
//--- Indicator Window and Level Properties --- //--- Indicator Window and Level Properties ---
#property indicator_separate_window #property indicator_separate_window
@@ -54,7 +53,9 @@ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // Tar
input group "--- SMI Settings ---" input group "--- SMI Settings ---"
input int InpLengthK = 10; // %K Length input int InpLengthK = 10; // %K Length
input int InpLengthD = 3; // %D Length (for double smoothing) input int InpLengthD = 3; // %D Length (for double smoothing)
input ENUM_MA_TYPE InpSlowingType = EMA; // Double Smoothing MA Type
input int InpLengthEMA = 3; // EMA Length (for signal line) input int InpLengthEMA = 3; // EMA Length (for signal line)
input ENUM_MA_TYPE InpSignalType = EMA; // Signal Line MA Type
input ENUM_CANDLE_SOURCE InpCandleSource = CANDLE_STANDARD; input ENUM_CANDLE_SOURCE InpCandleSource = CANDLE_STANDARD;
//--- Indicator Buffers --- //--- Indicator Buffers ---
@@ -62,7 +63,7 @@ double BufferSMI[];
double BufferSignal[]; double BufferSignal[];
//--- Internal HTF Data Caches //--- Internal HTF Data Caches
double h_open[], h_high[], h_low[], h_close[]; double h_open[], h_high[], h_low[], h_close[], h_volume[];
double h_res_smi[], h_res_sig[]; double h_res_smi[], h_res_sig[];
datetime h_time[]; datetime h_time[];
@@ -116,7 +117,7 @@ int OnInit()
break; break;
} }
if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpLengthK, InpLengthD, InpLengthEMA)) if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpLengthK, InpLengthD, InpSlowingType, InpLengthEMA, InpSignalType))
{ {
Print("Critical Error: Failed to create or initialize SMI Calculator object."); Print("Critical Error: Failed to create or initialize SMI Calculator object.");
return(INIT_FAILED); return(INIT_FAILED);
@@ -190,7 +191,21 @@ int OnCalculate(const int rates_total,
//=================================================================== //===================================================================
if(!g_is_mtf_mode) if(!g_is_mtf_mode)
{ {
g_calculator.Calculate(rates_total, prev_calculated, open, high, low, close, BufferSMI, BufferSignal); long volume_limit = (long)SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT);
bool is_vwma = (InpSlowingType == VWMA || InpSignalType == VWMA);
if(is_vwma)
{
if(volume_limit > 0)
g_calculator.Calculate(rates_total, prev_calculated, open, high, low, close, volume, BufferSMI, BufferSignal);
else
g_calculator.Calculate(rates_total, prev_calculated, open, high, low, close, tick_volume, BufferSMI, BufferSignal);
}
else
{
g_calculator.Calculate(rates_total, prev_calculated, open, high, low, close, BufferSMI, BufferSignal);
}
return(rates_total); return(rates_total);
} }
@@ -223,13 +238,14 @@ int OnCalculate(const int rates_total,
g_htf_count = MathMin(htf_bars, 3000); // Guard rails to prevent memory overload g_htf_count = MathMin(htf_bars, 3000); // Guard rails to prevent memory overload
// Resize all HTF caching arrays // Resize all HTF caching arrays
ArrayResize(h_time, g_htf_count); ArrayResize(h_time, g_htf_count);
ArrayResize(h_open, g_htf_count); ArrayResize(h_open, g_htf_count);
ArrayResize(h_high, g_htf_count); ArrayResize(h_high, g_htf_count);
ArrayResize(h_low, g_htf_count); ArrayResize(h_low, g_htf_count);
ArrayResize(h_close, g_htf_count); ArrayResize(h_close, g_htf_count);
ArrayResize(h_res_smi, g_htf_count); ArrayResize(h_volume, g_htf_count);
ArrayResize(h_res_sig, g_htf_count); ArrayResize(h_res_smi, g_htf_count);
ArrayResize(h_res_sig, g_htf_count);
// Force chronological structure on high-level arrays // Force chronological structure on high-level arrays
ArraySetAsSeries(h_time, false); ArraySetAsSeries(h_time, false);
@@ -237,8 +253,9 @@ int OnCalculate(const int rates_total,
ArraySetAsSeries(h_high, false); ArraySetAsSeries(h_high, false);
ArraySetAsSeries(h_low, false); ArraySetAsSeries(h_low, false);
ArraySetAsSeries(h_close, false); ArraySetAsSeries(h_close, false);
ArraySetAsSeries(h_res_smi, false); ArraySetAsSeries(h_volume, false);
ArraySetAsSeries(h_res_sig, false); ArraySetAsSeries(h_res_smi, false);
ArraySetAsSeries(h_res_sig, false);
// Copy basic pricing data // Copy basic pricing data
if(CopyTime(_Symbol, g_calc_timeframe, 0, g_htf_count, h_time) != g_htf_count || if(CopyTime(_Symbol, g_calc_timeframe, 0, g_htf_count, h_time) != g_htf_count ||
@@ -251,8 +268,41 @@ int OnCalculate(const int rates_total,
return 0; return 0;
} }
// Copy proper volume types for VWMA supporting
long vol_limit = (long)SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT);
if(vol_limit > 0)
{
long temp_vol[];
if(CopyRealVolume(_Symbol, g_calc_timeframe, 0, g_htf_count, temp_vol) == g_htf_count)
{
for(int i = 0; i < g_htf_count; i++)
h_volume[i] = (double)temp_vol[i];
}
}
else
{
long temp_vol[];
if(CopyTickVolume(_Symbol, g_calc_timeframe, 0, g_htf_count, temp_vol) == g_htf_count)
{
for(int i = 0; i < g_htf_count; i++)
h_volume[i] = (double)temp_vol[i];
}
}
//--- Calculate core indicators directly on high timeframe (Initial setup) //--- Calculate core indicators directly on high timeframe (Initial setup)
g_calculator.Calculate(g_htf_count, 0, h_open, h_high, h_low, h_close, h_res_smi, h_res_sig); bool is_vwma = (InpSlowingType == VWMA || InpSignalType == VWMA);
if(is_vwma)
{
long h_vol_long[];
ArrayResize(h_vol_long, g_htf_count);
for(int i=0; i<g_htf_count; i++)
h_vol_long[i] = (long)h_volume[i];
g_calculator.Calculate(g_htf_count, 0, h_open, h_high, h_low, h_close, h_vol_long, h_res_smi, h_res_sig);
}
else
{
g_calculator.Calculate(g_htf_count, 0, h_open, h_high, h_low, h_close, h_res_smi, h_res_sig);
}
g_data_ready = true; g_data_ready = true;
} }
@@ -265,6 +315,7 @@ int OnCalculate(const int rates_total,
if(live_idx >= required_bars) if(live_idx >= required_bars)
{ {
double o[1], h[1], l[1], c[1]; double o[1], h[1], l[1], c[1];
long v[1];
int shift = iBarShift(_Symbol, g_calc_timeframe, htf_time_current, false); int shift = iBarShift(_Symbol, g_calc_timeframe, htf_time_current, false);
if(shift >= 0 && if(shift >= 0 &&
CopyOpen(_Symbol, g_calc_timeframe, shift, 1, o) == 1 && CopyOpen(_Symbol, g_calc_timeframe, shift, 1, o) == 1 &&
@@ -277,8 +328,32 @@ int OnCalculate(const int rates_total,
h_low[live_idx] = l[0]; h_low[live_idx] = l[0];
h_close[live_idx] = c[0]; h_close[live_idx] = c[0];
// Stateful, O(1) mock update for the live bar long vol_limit = (long)SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT);
g_calculator.Calculate(g_htf_count, g_htf_count, h_open, h_high, h_low, h_close, h_res_smi, h_res_sig); if(vol_limit > 0)
{
if(CopyRealVolume(_Symbol, g_calc_timeframe, shift, 1, v) == 1)
h_volume[live_idx] = (double)v[0];
}
else
{
if(CopyTickVolume(_Symbol, g_calc_timeframe, shift, 1, v) == 1)
h_volume[live_idx] = (double)v[0];
}
// Stateful, O(1) mock update for the live HTF bar
bool is_vwma = (InpSlowingType == VWMA || InpSignalType == VWMA);
if(is_vwma)
{
long h_vol_long[];
ArrayResize(h_vol_long, g_htf_count);
for(int i=0; i<g_htf_count; i++)
h_vol_long[i] = (long)h_volume[i];
g_calculator.Calculate(g_htf_count, g_htf_count, h_open, h_high, h_low, h_close, h_vol_long, h_res_smi, h_res_sig);
}
else
{
g_calculator.Calculate(g_htf_count, g_htf_count, h_open, h_high, h_low, h_close, h_res_smi, h_res_sig);
}
} }
} }