Article-22258-Volatility-Mo.../Indicators/VolatilityModels/ConditionalVolatility_forecaster.mq5
2026-06-03 20:03:04 +02:00

196 lines
6.3 KiB
MQL5

//+------------------------------------------------------------------+
//| 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<VolatilityModels\Arch\Univariate\mean.mqh>
#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; i<uint(nlags); ++i)
{
if(StringLen(lag_info[i])>0)
{
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<rates_total; ++shift)
{
int from = shift - fabs(HistoryLen);
for(int32_t i = from; i<(shift); ++i)
returns[i-(from)] = log(close[i]/close[i-1]);
returns*=fabs(ScaleFactor);
spec.observations = returns;
if(!full_model.initialize(spec))
{
Print(" initialization error ");
return 0;
}
ArchModelResult result = full_model.fit(ScaleFactor);
ulong size = result.conditional_volatility.Size();
if(!size)
{
Print(" model fit error ");
return 0;
}
ArchForecast forecast = full_model.forecast();
ForecastBuffer[shift] = (spec.vol_model_type!=VOL_TARCH)?sqrt(forecast.variance[0,0]):forecast.variance[0,0];
VolZscoreBuffer[shift] = (ForecastBuffer[shift] - result.conditional_volatility.Mean())/result.conditional_volatility.Std();
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+