Article-22714-Volatility-Mo.../Scripts/slsqp_article/VolatilityModelParameterComparison.mq5
2026-06-03 20:14:05 +02:00

311 satır
9,2 KiB
MQL5

//+------------------------------------------------------------------+
//| VolatilityModelParameterComparison.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"
#property script_show_inputs
#property description "The script downloads data from the terminal"
"to build a conditional volatility model using"
"the MQL5 library then Pythons ARCH module. By"
"default MQL5 lib uses minNLC. To use the SLSQP "
"solver define __SLSQP__ before including"
"the arch library and compile"
#define __SLSQP__
#include<slsqp_article\Arch\Univariate\mean.mqh>
#include<slsqp_article\win32_utils.mqh>
#include<slsqp_article\JAson.mqh>
#include<Files\FileTxt.mqh>
//---
#define FILENAME "arch.json"
#define SPACE " "
#define PYFILE "\\MQL5\\Scripts\\slsqp_article\\mt5_volatility_processor.py"
//---
input string Symbol_="AUDUSD";
input ENUM_TIMEFRAMES TimeFrame=PERIOD_D1;
input datetime StartDate=D'2025.01.01';
input ulong HistoryLength = 1000;
input double ScaleFactor=100.;
input ENUM_MEAN_MODEL MeanModel = MEAN_CONSTANT;
input bool MeanConstant = true;
input string MeanLags ="";
input ENUM_VOLATILITY_MODEL VolatilityModel = VOL_GJR_GARCH;
input ENUM_DISTRIBUTION_MODEL ErrorDistribution = DIST_NORMAL;
input ulong _P_ = 1;
input ulong _O_ = 1;
input ulong _Q_ = 1;
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
#ifdef __SLSQP__
Print("USING SLSQP");
#else
Print("USING minNLC");
#endif
Print(EnumToString(MeanModel));
Print(EnumToString(VolatilityModel));
Print(EnumToString(ErrorDistribution));
//---
string pstring = EnumToString(TimeFrame);
if(StringFind(pstring,"CURRENT")>=0)
{
Print("Invalid parameter setting. Please do not use PERIOD_CURRENT option, be explicit.");
return;
}
//---
ArchParameters spec;
spec.mean_model_type = MeanModel;
//---
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;
}
}
}
}
//---
spec.vol_model_type = VolatilityModel;
spec.garch_o = _O_;
spec.garch_p = _P_;
spec.garch_q = _Q_;
spec.dist_type = ErrorDistribution;
//---download data
vector prices;
if(!prices.CopyRates(Symbol_,TimeFrame,COPY_RATES_CLOSE,StartDate,HistoryLength))
{
Print(" failed to get close prices for ", Symbol_,". Error ", GetLastError());
return;
}
//---
prices = log(prices);
//---get returns
vector returns = np::diff(prices);
//---
if(ScaleFactor>1)
returns*=ScaleFactor;
//---
spec.observations = returns;
//---
HARX* arma_garch = arch_model(spec);
if(!arma_garch)
return;
//---
ArchParameters final_spec = arma_garch.get_specification();
Print("GARCH spec");
PrintFormat("P(%d) O(%d) Q(%d) Power(%f)",final_spec.garch_p,final_spec.garch_o,final_spec.garch_q,final_spec.vol_power);
//---
#ifdef __SLSQP__
ArchModelResult mt5_result = arma_garch.fit();
#else
ArchModelResult mt5_result = arma_garch.fit(ScaleFactor);
#endif
//---
if(mt5_result.params.Size())
{
Print("MT5 model parameters: ", mt5_result.params);
Print("MT5 model LogLikelihood: ", -1.*mt5_result.loglikelihood);
}
else
Print("Fitting model failed");
delete arma_garch;
//---
string cmdLine = StringFormat("%s %s%s%s","python ",TerminalInfoString(TERMINAL_DATA_PATH),PYFILE,cmd_builder(Symbol_,
StartDate,TimeFrame,HistoryLength,VolatilityModel,
ScaleFactor,MeanModel,MeanConstant,MeanLags,
ErrorDistribution,final_spec.garch_p,final_spec.garch_o,final_spec.garch_q));
//Print(cmdLine);
//---
PROCESS_INFORMATION piProcInfo;
STARTUPINFOW siStartInfo;
BOOL process_run = false;
//---
ZeroMemory(piProcInfo);
ZeroMemory(siStartInfo);
siStartInfo.cb = sizeof(STARTUPINFOW);
vector parameters;
//---
if(CreateProcessW(NULL,cmdLine,NULL,NULL,0,DETACHED_PROCESS,NULL,NULL,siStartInfo,piProcInfo))
{
WaitForSingleObject(piProcInfo.hProcess,INFINITE);
uint exitcode;
GetExitCodeProcess(piProcInfo.hProcess,exitcode);
if(!exitcode)
{
CFileTxt jfile;
if(jfile.Open(FILENAME,FILE_READ|FILE_COMMON) != INVALID_HANDLE)
{
CJAVal js;
if(js.Deserialize(jfile.ReadString()))
{
int jsize = js["x"].Size();
parameters = vector::Zeros(jsize);
for(int i = 0; i<jsize; ++i)
parameters[i] = js["x"][i].ToDbl();
Print("Python's Model Parameters ", parameters);
Print("Python's LogLikelihood: ", js["fun"].ToDbl());
}
else
Print("Failed to deserialize the model");
jfile.Delete(FILENAME,FILE_COMMON);
}
else
Print("File open error ", GetLastError());
}
else
Print("Python process failed to execute successfully.");
}
else
printf("CreateProcess failed with error %d\n", kernel32::GetLastError());
//---
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
//+------------------------------------------------------------------+
HARX* arch_model(ArchParameters &archparameters)
{
HARX* out = NULL;
switch(archparameters.mean_model_type)
{
case MEAN_CONSTANT:
out = new ConstantMean();
break;
case MEAN_AR:
out = new AR();
break;
case MEAN_ARX:
out = new ARX();
break;
case MEAN_HAR:
out = new HAR();
break;
case MEAN_HARX:
out = new HARX();
break;
case MEAN_ZERO:
out = new ZeroMean();
break;
default:
out = new ConstantMean();
break;
}
if(CheckPointer(out)==POINTER_DYNAMIC)
{
if(out.initialize(archparameters))
return out;
else
{
delete out;
return NULL;
}
}
else
return out;
}
//+------------------------------------------------------------------+
//| parse model options |
//+------------------------------------------------------------------+
string cmd_builder(string symb, datetime sdate, ENUM_TIMEFRAMES tf, ulong hist,ENUM_VOLATILITY_MODEL vmod, double scalef, ENUM_MEAN_MODEL mmod, bool mconst, string mlags, ENUM_DISTRIBUTION_MODEL edist, ulong P, ulong O, ulong Q)
{
string stime = TimeToString(sdate, TIME_DATE|TIME_MINUTES);
StringReplace(stime, " ", "_");
string tf_str = EnumToString(tf);
tf_str = StringSubstr(tf_str, 7);
string mmod_str = "";
switch(mmod)
{
case MEAN_CONSTANT:
mmod_str = "constant";
break;
case MEAN_ZERO:
mmod_str = "zero";
break;
case MEAN_AR:
mmod_str = "ar";
break;
case MEAN_ARX:
mmod_str = "arx";
break;
case MEAN_HAR:
mmod_str = "har";
break;
case MEAN_HARX:
mmod_str = "harx";
break;
default:
mmod_str = "constant";
break;
}
string vmod_str = "garch";
switch(vmod)
{
case VOL_ARCH:
vmod_str = "arch";
break;
case VOL_CONST:
vmod_str = "constant";
break;
case VOL_AVARCH:
vmod_str = "avarch";
break;
case VOL_AVGARCH:
vmod_str = "avgarch";
break;
case VOL_TARCH:
vmod_str = "tarch";
break;
case VOL_GJR_GARCH:
vmod_str = "gjr-garch";
break;
default:
vmod_str = "garch";
break;
}
string edist_str = "";
switch(edist)
{
case DIST_NORMAL:
edist_str = "normal";
break;
case DIST_GEN_ERROR:
edist_str = "gen-error";
break;
case DIST_SKEW_STUDENT:
edist_str = "skewed-student";
break;
case DIST_STUDENT:
edist_str = "student";
break;
default:
edist_str = "normal";
break;
}
string final_lags = (StringLen(mlags) > 0) ? mlags : "0";
string out = StringFormat("%s %s %s %s %s %G %I64u %I64u %I64u %I64u %s %d %s %s %s",
SPACE, FILENAME, stime, symb, tf_str,
scalef, hist, P, O, Q,
mmod_str, (mconst ? 1 : 0), vmod_str, edist_str, final_lags);
return out;
}
//+------------------------------------------------------------------+