195 lines
9.1 KiB
MQL5
195 lines
9.1 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| DiagnoseADBuffers.mq5 |
| |||
//| AnimateDread |
| |||
//| |
| |||
//| BUFFER HEALTH for the five AD/Wyckoff custom indicators, at the |
| |||
//| SHIPPED defaults, on every fleet chart. |
| |||
//| |
| |||
//| WHY: a feature block that scores zero can be uninformative OR |
| |||
//| BROKEN, and those two look identical from downstream. The screen |
| |||
//| said ADWyckoffEventStream clears 0 of 16 columns on all five |
| |||
//| charts, and a 41-candidate parameter sweep found no setting that |
| |||
//| changed it - but a search over the parameters of a function that |
| |||
//| is not computing what it claims fails at EVERY point in the |
| |||
//| space, which is exactly that pattern. The feature-health report |
| |||
//| separately noted EventStream is where every CONSTANT column |
| |||
//| appeared, and a constant column is a bug signature: a real but |
| |||
//| weak feature still VARIES. |
| |||
//| |
| |||
//| This does not judge whether a block PAYS. It answers the prior |
| |||
//| question - is each buffer being filled with something that moves |
| |||
//| - so a correctness review starts from measurements rather than |
| |||
//| from reading code cold. |
| |||
//| |
| |||
//| Flags raised per buffer: |
| |||
//| NEVER-FILLED every value EMPTY_VALUE / non-finite |
| |||
//| ALL-ZERO finite everywhere but never non-zero |
| |||
//| CONSTANT exactly one distinct finite value |
| |||
//| NEAR-CONSTANT one value covers >99% of bars |
| |||
//| SPARSE non-zero on <0.5% of bars (may be correct for an |
| |||
//| event flag - read it beside the event's expected |
| |||
//| frequency, not as a fault on its own) |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "AnimateDread"
| |||
#property link "https://www.mql5.com"
| |||
#property version "1.00"
| |||
| |||
input string InpSymbols = "EURUSD,USDJPY,NAS100,XAUUSD,XTIUSD"; // Charts to check
| |||
input int InpBars = 40000; // Bars of H1 history
| |||
| |||
//+------------------------------------------------------------------+
| |||
void DiagnoseOne(const string sym, const string indName, const int buffers,
| |||
MqlParam &mp[])
| |||
{
| |||
int h = IndicatorCreate(sym, PERIOD_H1, IND_CUSTOM, ArraySize(mp), mp);
| |||
if(h == INVALID_HANDLE)
| |||
{
| |||
PrintFormat(" %-34s %-8s IndicatorCreate FAILED (error %d)", indName, sym, GetLastError());
| |||
return;
| |||
}
| |||
//--- Let the terminal finish calculating before reading, or an incomplete series reads as a fault.
| |||
int calc = 0;
| |||
for(int t = 0; t < 300; t++)
| |||
{
| |||
calc = BarsCalculated(h);
| |||
if(calc >= InpBars) break;
| |||
Sleep(100);
| |||
}
| |||
if(calc < InpBars)
| |||
PrintFormat(" %-34s %-8s NOTE: BarsCalculated=%d of %d requested", indName, sym, calc, InpBars);
| |||
| |||
for(int c = 0; c < buffers; c++)
| |||
{
| |||
double v[];
| |||
ArraySetAsSeries(v, true);
| |||
int got = CopyBuffer(h, c, 0, InpBars, v);
| |||
if(got <= 0)
| |||
{
| |||
PrintFormat(" %-34s %-8s buf%-2d COPY FAILED (%d, error %d)", indName, sym, c, got, GetLastError());
| |||
continue;
| |||
}
| |||
int nFinite = 0, nZero = 0, nEmpty = 0;
| |||
double mn = 0, mx = 0, sum = 0, sum2 = 0;
| |||
bool first = true;
| |||
for(int i = 0; i < got; i++)
| |||
{
| |||
double x = v[i];
| |||
if(!MathIsValidNumber(x) || x == EMPTY_VALUE) { nEmpty++; continue; }
| |||
nFinite++;
| |||
if(x == 0.0) nZero++;
| |||
sum += x; sum2 += x * x;
| |||
if(first) { mn = x; mx = x; first = false; }
| |||
else { if(x < mn) mn = x; if(x > mx) mx = x; }
| |||
}
| |||
string flag = "ok";
| |||
double sd = 0.0, mean = 0.0, modeShare = 0.0;
| |||
if(nFinite == 0)
| |||
flag = "NEVER-FILLED";
| |||
else
| |||
{
| |||
mean = sum / nFinite;
| |||
double var = sum2 / nFinite - mean * mean;
| |||
sd = (var > 1e-18) ? MathSqrt(var) : 0.0;
| |||
//--- Share of the single most common value, via a sorted copy of the finite entries.
| |||
double s[];
| |||
ArrayResize(s, nFinite);
| |||
int w = 0;
| |||
for(int i = 0; i < got; i++)
| |||
{ double x = v[i]; if(MathIsValidNumber(x) && x != EMPTY_VALUE) s[w++] = x; }
| |||
ArraySort(s);
| |||
int best = 1, run = 1;
| |||
for(int i = 1; i < nFinite; i++)
| |||
{
| |||
if(s[i] == s[i - 1]) run++;
| |||
else { if(run > best) best = run; run = 1; }
| |||
}
| |||
if(run > best) best = run;
| |||
modeShare = (double)best / nFinite;
| |||
| |||
if(nZero == nFinite) flag = "ALL-ZERO";
| |||
else if(mn == mx) flag = "CONSTANT";
| |||
else if(modeShare > 0.99) flag = "NEAR-CONSTANT";
| |||
else if((double)(nFinite - nZero) / got < 0.005) flag = "SPARSE";
| |||
}
| |||
PrintFormat(" %-34s %-8s buf%-2d empty %5.1f%% zero %5.1f%% modeShare %5.1f%% sd %-12.6g [%s]",
| |||
indName, sym, c, 100.0 * nEmpty / got, 100.0 * nZero / got,
| |||
100.0 * modeShare, sd, flag);
| |||
}
| |||
//--- Released in the same iteration that created it.
| |||
IndicatorRelease(h);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
void PushInt(MqlParam &mp[], int &n, const long v)
| |||
{ mp[n].type = TYPE_INT; mp[n].integer_value = v; n++; }
| |||
void PushDbl(MqlParam &mp[], int &n, const double v)
| |||
{ mp[n].type = TYPE_DOUBLE; mp[n].double_value = v; n++; }
| |||
| |||
//+------------------------------------------------------------------+
| |||
void OnStart(void)
| |||
{
| |||
Print("==================================================================");
| |||
Print("AD/WYCKOFF BUFFER HEALTH - shipped defaults, per chart, per buffer.");
| |||
Print("Answers 'is this buffer computing anything', NOT 'does it pay'.");
| |||
Print("A CONSTANT or ALL-ZERO buffer is a code fault, not a weak feature:");
| |||
Print("a real but weak signal still varies.");
| |||
Print("==================================================================");
| |||
| |||
string syms[];
| |||
int ns = StringSplit(InpSymbols, ',', syms);
| |||
| |||
for(int s = 0; s < ns; s++)
| |||
{
| |||
string sym = syms[s];
| |||
StringTrimLeft(sym); StringTrimRight(sym);
| |||
if(sym == "") continue;
| |||
Print("");
| |||
PrintFormat("---------------- %s ----------------", sym);
| |||
| |||
MqlParam mp[];
| |||
int n;
| |||
| |||
//--- ADCumulativeDelta: 10 inputs, 6 buffers
| |||
ArrayResize(mp, 11); n = 0;
| |||
mp[n].type = TYPE_STRING; mp[n].string_value = "ADCumulativeDelta"; n++;
| |||
PushInt(mp, n, 50); PushDbl(mp, n, 2.5); PushDbl(mp, n, 1.5); PushDbl(mp, n, 1.8);
| |||
PushDbl(mp, n, 1.2); PushDbl(mp, n, 0.6); PushDbl(mp, n, 0.5);
| |||
PushInt(mp, n, 0); PushInt(mp, n, 5); PushInt(mp, n, 1);
| |||
DiagnoseOne(sym, "ADCumulativeDelta", 6, mp);
| |||
| |||
//--- ADShorteningOfThrust: 6 inputs, 4 buffers
| |||
ArrayResize(mp, 7); n = 0;
| |||
mp[n].type = TYPE_STRING; mp[n].string_value = "ADShorteningOfThrust"; n++;
| |||
PushInt(mp, n, 30); PushInt(mp, n, 3); PushDbl(mp, n, 0.30);
| |||
PushInt(mp, n, 0); PushInt(mp, n, 5); PushInt(mp, n, 1);
| |||
DiagnoseOne(sym, "ADShorteningOfThrust", 4, mp);
| |||
| |||
//--- ADWyckoffEventStream: 14 inputs, 14 buffers
| |||
ArrayResize(mp, 15); n = 0;
| |||
mp[n].type = TYPE_STRING; mp[n].string_value = "ADWyckoffEventStream"; n++;
| |||
PushInt(mp, n, 50); PushInt(mp, n, 3); PushDbl(mp, n, 2.5); PushDbl(mp, n, 1.5);
| |||
PushDbl(mp, n, 1.8); PushDbl(mp, n, 1.2); PushDbl(mp, n, 0.6); PushDbl(mp, n, 0.5);
| |||
PushInt(mp, n, 0); PushInt(mp, n, 5); PushInt(mp, n, 1);
| |||
PushDbl(mp, n, 0.5); PushDbl(mp, n, 1.0); PushInt(mp, n, 200);
| |||
DiagnoseOne(sym, "ADWyckoffEventStream", 14, mp);
| |||
| |||
//--- ADWyckoffFailedStructure: 11 inputs, 5 buffers
| |||
ArrayResize(mp, 12); n = 0;
| |||
mp[n].type = TYPE_STRING; mp[n].string_value = "ADWyckoffFailedStructure"; n++;
| |||
PushInt(mp, n, 50); PushInt(mp, n, 3); PushDbl(mp, n, 2.5); PushDbl(mp, n, 1.5);
| |||
PushDbl(mp, n, 1.8); PushDbl(mp, n, 1.2); PushDbl(mp, n, 0.6); PushDbl(mp, n, 0.5);
| |||
PushInt(mp, n, 0); PushInt(mp, n, 5); PushInt(mp, n, 1);
| |||
DiagnoseOne(sym, "ADWyckoffFailedStructure", 5, mp);
| |||
| |||
//--- ADWyckoffSignificantBarInversion: 7 inputs, 5 buffers
| |||
ArrayResize(mp, 8); n = 0;
| |||
mp[n].type = TYPE_STRING; mp[n].string_value = "ADWyckoffSignificantBarInversion"; n++;
| |||
PushInt(mp, n, 50); PushDbl(mp, n, 1.2); PushDbl(mp, n, 1.5); PushDbl(mp, n, 0.5);
| |||
PushInt(mp, n, 0); PushInt(mp, n, 5); PushInt(mp, n, 1);
| |||
DiagnoseOne(sym, "ADWyckoffSignificantBarInversion", 5, mp);
| |||
}
| |||
Print("");
| |||
Print("Done. NEVER-FILLED / ALL-ZERO / CONSTANT on a buffer that should carry an event");
| |||
Print("is a defect to fix in the indicator, not a reason to drop the feature block.");
| |||
}
| |||
//+------------------------------------------------------------------+
|