//+------------------------------------------------------------------+ //| L1VolatilityNormalized.mq5 | //| Copyright 2000-2026, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2000-2026, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 1 #property indicator_plots 1 #property indicator_label1 "L1VolatilityNormalized" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_width1 2 //--- input int BarsToShow = 1000; // Number of bars to calculate L1 input double CoefLambda = 0.015; // Lambda in lambda_max units //--- double VolNormalized[]; //--- //+------------------------------------------------------------------+ //| Indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- prepare SetIndexBuffer(0, VolNormalized, INDICATOR_DATA); ArrayInitialize(VolNormalized, EMPTY_VALUE); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); IndicatorSetInteger(INDICATOR_DIGITS, _Digits); //--- return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Indicator iteration function | //+------------------------------------------------------------------+ 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[]) { //--- check bars static bool warned=false; if(rates_total < BarsToShow) { if(!warned) { Print("Waiting for enough bars: ",BarsToShow); warned=true; } ArrayInitialize(VolNormalized,EMPTY_VALUE); return 0; } //--- check new bar static datetime last_bar_time=0; bool new_bar=(time[0]!=last_bar_time); bool need_recalc= (prev_calculated==0) || new_bar || (rates_total!=prev_calculated); if(!need_recalc) return prev_calculated; last_bar_time=time[0]; int start = rates_total - BarsToShow; //--- for(int i = 0; i < start; i++) VolNormalized[i] = EMPTY_VALUE; //--- copy close prices vector price(BarsToShow); for(int i = 0; i < BarsToShow; i++) price[i] = close[start + i]; //--- vector l1(BarsToShow); price.L1TrendFilter(l1, CoefLambda, true); //--- compute normalized volatility double mean = 0; double stddev = 0; for(int i = 0; i < BarsToShow; i++) mean += close[start + i] - l1[i]; mean /= BarsToShow; //--- for(int i = 0; i < BarsToShow; i++) stddev += MathPow(close[start + i] - l1[i] - mean, 2); stddev = MathSqrt(stddev / BarsToShow); //--- for(int i = 0; i < BarsToShow; i++) VolNormalized[start + i] = stddev > 0 ? (close[start + i] - l1[i]) / stddev : 0; //--- return rates_total; } //+------------------------------------------------------------------+