catch22/Scripts/Catch22/Catch22Validate.mq5
2026-07-12 10:16:21 +00:00

123 lines
4.2 KiB
MQL5

//+------------------------------------------------------------------+
//| Catch22Validate.mq5 |
//| MMQ — Muhammad Minhas Qamar |
//| www.mql5.com/en/articles/23488 |
//+------------------------------------------------------------------+
#property copyright "MMQ — Muhammad Minhas Qamar"
#property link "https://www.mql5.com/en/articles/23488"
#property version "1.00"
#property strict
#property script_show_inputs
#include <Catch22\Catch22.mqh>
//--- pick what to feed the engine: a deterministic fixture (for
//--- cross-checking against pycatch22) or live symbol returns.
enum ENUM_C22_SOURCE
{
SRC_FIXTURE, // reproducible sine+noise vector defined below
SRC_RETURNS // log returns of the current symbol/timeframe
};
input ENUM_C22_SOURCE InpSource = SRC_FIXTURE; // input data source
input int InpLength = 200; // window length
input int InpSeed = 12345; // RNG seed for the fixture
//+------------------------------------------------------------------+
//| Deterministic fixture: x[i] = sin(2*pi*i/20) + 0.5*sin(i/7) |
//| plus a seeded uniform noise term. Fully reproducible so the |
//| printed feature vector can be compared to a pycatch22 run on the |
//| identical vector (which the script also dumps to a CSV). |
//+------------------------------------------------------------------+
void BuildFixture(double &x[],int n,int seed)
{
ArrayResize(x,n);
MathSrand(seed);
for(int i=0;i<n;i++)
{
double noise=((double)MathRand()/32767.0-0.5)*0.6;
x[i]=MathSin(2.0*M_PI*i/20.0)+0.5*MathSin(i/7.0)+noise;
}
}
//+------------------------------------------------------------------+
//| Fill x[] with log returns of the current symbol. |
//+------------------------------------------------------------------+
bool BuildReturns(double &x[],int n)
{
int need=n+1;
double close[];
if(CopyClose(_Symbol,_Period,1,need,close)<need)
return false;
ArraySetAsSeries(close,false);
ArrayResize(x,n);
for(int i=0;i<n;i++)
{
if(close[i]<=0.0 || close[i+1]<=0.0)
{
x[i]=0.0;
continue;
}
x[i]=MathLog(close[i+1]/close[i]);
}
return true;
}
//+------------------------------------------------------------------+
//| Dump the input vector to Files\ so it can be re-run through |
//| pycatch22 for an external, side-by-side comparison. |
//+------------------------------------------------------------------+
void DumpInput(const double &x[],int n,string tag)
{
string fname="Catch22\\input_"+tag+".csv";
int h=FileOpen(fname,FILE_WRITE|FILE_CSV|FILE_ANSI,",");
if(h==INVALID_HANDLE)
{
PrintFormat("Could not write %s (err %d)",fname,GetLastError());
return;
}
for(int i=0;i<n;i++)
FileWrite(h,DoubleToString(x[i],10));
FileClose(h);
PrintFormat("Wrote input vector to MQL5\\Files\\%s",fname);
}
//+------------------------------------------------------------------+
//| Script entry: build the data, compute catch22, print the named |
//| vector, and persist the input for external validation. |
//+------------------------------------------------------------------+
void OnStart()
{
double x[];
string tag;
if(InpSource==SRC_FIXTURE)
{
BuildFixture(x,InpLength,InpSeed);
tag="fixture";
}
else
{
if(!BuildReturns(x,InpLength))
{
Print("Not enough history to build returns.");
return;
}
tag="returns";
}
CCatch22 c;
double feats[];
if(!c.Compute(x,InpLength,feats))
{
Print("Compute() failed: degenerate window (constant or too short).");
return;
}
Print("=== catch22 feature vector (",tag,", n=",InpLength,") ===");
for(int i=0;i<CATCH22_N;i++)
PrintFormat("%2d %-46s = % .8f",i,CCatch22::Name(i),feats[i]);
DumpInput(x,InpLength,tag);
Print("=== done ===");
}
//+------------------------------------------------------------------+