//+------------------------------------------------------------------+ //| ConditionalVolatility_forecaster.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include #property indicator_separate_window #property indicator_buffers 2 #property indicator_plots 2 //--- plot Forecast #property indicator_label1 "Forecast" #property indicator_type1 DRAW_LINE #property indicator_color1 clrRed #property indicator_style1 STYLE_DOT #property indicator_width1 1 //--- plot Mean #property indicator_label2 "Vol_Zscore" #property indicator_type2 DRAW_LINE #property indicator_color2 clrLimeGreen #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- input parameters input int BarsToDraw = 50; input int HistoryLen = 200; input double Num_Stds = 1.5; input double ScaleFactor=100.; input ENUM_MEAN_MODEL MeanModel = MEAN_CONSTANT; input bool MeanConstant = false; input string MeanLags =""; input ENUM_VOLATILITY_MODEL VolatilityModel = VOL_TARCH; input ulong _P_ = 1; input ulong _O_ = 1; input ulong _Q_ = 1; input int Volatility_Seed = 0; input ENUM_DISTRIBUTION_MODEL ErrorDistribution = DIST_NORMAL; input int Distribution_Seed = 0; //--- indicator buffers double ForecastBuffer[]; double ThresholdBuffer[]; double VolZscoreBuffer[]; vector returns = vector::Zeros(HistoryLen); ArchParameters spec; HARX* full_model; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { if(HistoryLen<30) { Print("Invalid input value for HistoryLen"); return INIT_FAILED; } //--- indicator buffers mapping SetIndexBuffer(0,ForecastBuffer,INDICATOR_DATA); SetIndexBuffer(1,VolZscoreBuffer,INDICATOR_DATA); //--- PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,BarsToDraw); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,BarsToDraw); //--- IndicatorSetInteger(INDICATOR_LEVELS,2); IndicatorSetDouble(INDICATOR_LEVELVALUE,0,Num_Stds); IndicatorSetDouble(INDICATOR_LEVELVALUE,1,-1.0); //--- spec.mean_model_type = MeanModel; if(StringLen(MeanLags)) { string lag_info[]; int nlags = StringSplit(MeanLags,StringGetCharacter(",",0),lag_info); if(nlags>0) { for(uint i = 0; i0) { if(spec.mean_lags.Resize(spec.mean_lags.Size()+1,3)) spec.mean_lags[spec.mean_lags.Size()-1] = StringToDouble(lag_info[i]); else { Print(" error ", GetLastError()); return INIT_FAILED; } } } } } spec.vol_rng_seed = Volatility_Seed; spec.garch_o = _O_; spec.garch_p = _P_; spec.garch_q = _Q_; spec.dist_type = ErrorDistribution; spec.dist_rng_seed = Distribution_Seed; switch(MeanModel) { case MEAN_CONSTANT: full_model = new ConstantMean(); break; case MEAN_ZERO: full_model = new ZeroMean(); break; case MEAN_AR: full_model = new AR(); break; default: full_model = new ConstantMean(); break; } if(CheckPointer(full_model)==POINTER_INVALID) return INIT_FAILED; switch(VolatilityModel) { case VOL_GJR_GARCH: spec.vol_model_type = VOL_GJR_GARCH; break; case VOL_TARCH: spec.vol_model_type = VOL_TARCH; break; default: spec.vol_model_type = VOL_GARCH; break; } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(CheckPointer(full_model)==POINTER_DYNAMIC) delete full_model; } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int32_t rates_total, const int32_t 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 int32_t &spread[]) { //--- int32_t limit; static datetime last_time; if(time[rates_total-1]==last_time) return rates_total; else last_time = time[rates_total-1]; if(prev_calculated<=0) limit = rates_total - int32_t(fabs(BarsToDraw)); else limit = prev_calculated - 1; for(int32_t shift = limit; shift