From 465b11406ed446def92e46f97f6fe6a30bb28b61 Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Tue, 18 Aug 2026 17:12:07 +0200 Subject: [PATCH] refactor: Upgraded with selectable MA smoothing types (including VWMA support) --- Indicators/MyIndicators/SMI_Pro.mq5 | 111 +++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 18 deletions(-) diff --git a/Indicators/MyIndicators/SMI_Pro.mq5 b/Indicators/MyIndicators/SMI_Pro.mq5 index 355eacc..a4243fe 100644 --- a/Indicators/MyIndicators/SMI_Pro.mq5 +++ b/Indicators/MyIndicators/SMI_Pro.mq5 @@ -3,9 +3,8 @@ //| Copyright 2026, xxxxxxxx| //+------------------------------------------------------------------+ #property copyright "Copyright 2026, xxxxxxxx" -#property version "3.10" // Upgraded with dynamic high-performance Standard/MTF support -#property description "Professional Stochastic Momentum Index (SMI) with a signal line and" -#property description "selectable candle source (Standard or Heikin Ashi)." +#property version "3.20" // Upgraded with selectable MA smoothing types (including VWMA support) +#property description "Professional Stochastic Momentum Index (SMI) with dynamic MTF and MA selections." //--- Indicator Window and Level Properties --- #property indicator_separate_window @@ -54,7 +53,9 @@ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // Tar input group "--- SMI Settings ---" input int InpLengthK = 10; // %K Length 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 ENUM_MA_TYPE InpSignalType = EMA; // Signal Line MA Type input ENUM_CANDLE_SOURCE InpCandleSource = CANDLE_STANDARD; //--- Indicator Buffers --- @@ -62,7 +63,7 @@ double BufferSMI[]; double BufferSignal[]; //--- 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[]; datetime h_time[]; @@ -116,7 +117,7 @@ int OnInit() 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."); return(INIT_FAILED); @@ -190,7 +191,21 @@ int OnCalculate(const int rates_total, //=================================================================== 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); } @@ -223,13 +238,14 @@ int OnCalculate(const int rates_total, g_htf_count = MathMin(htf_bars, 3000); // Guard rails to prevent memory overload // 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_res_smi, g_htf_count); - ArrayResize(h_res_sig, g_htf_count); + 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_volume, g_htf_count); + ArrayResize(h_res_smi, g_htf_count); + ArrayResize(h_res_sig, g_htf_count); // Force chronological structure on high-level arrays ArraySetAsSeries(h_time, false); @@ -237,8 +253,9 @@ int OnCalculate(const int rates_total, ArraySetAsSeries(h_high, false); ArraySetAsSeries(h_low, false); ArraySetAsSeries(h_close, false); - ArraySetAsSeries(h_res_smi, false); - ArraySetAsSeries(h_res_sig, false); + ArraySetAsSeries(h_volume, false); + ArraySetAsSeries(h_res_smi, false); + ArraySetAsSeries(h_res_sig, false); // Copy basic pricing data 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; } + // 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) - 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= required_bars) { double o[1], h[1], l[1], c[1]; + long v[1]; int shift = iBarShift(_Symbol, g_calc_timeframe, htf_time_current, false); if(shift >= 0 && 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_close[live_idx] = c[0]; - // Stateful, O(1) mock update for the live bar - g_calculator.Calculate(g_htf_count, g_htf_count, h_open, h_high, h_low, h_close, h_res_smi, h_res_sig); + long vol_limit = (long)SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_LIMIT); + 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