Warrior_EA/Scripts/ExportIndicatorBuffers.mq5
AnimateDread 035a4920bc docs(research): pipeline analysis, and the two scripts the research depended on
DumpSymbolSpecs exports symbol specifications and deal history so the research
cost model uses the account's real commission and swap rather than assumptions.
ExportIndicatorBuffers dumps every AD/Wyckoff indicator buffer over full history,
so the research conditions on the PRODUCTION detectors rather than a Python
re-implementation of them - which is what made the Wyckoff verdict a verdict on
the indicators rather than on my approximation of them.

Both are read-only: handles, CopyBuffer, and writes under Common\Files. No orders,
no chart changes, no writes to any model or AltData file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 01:57:18 -04:00

185 lines
6.1 KiB
MQL5

//+------------------------------------------------------------------+
//| ExportIndicatorBuffers.mq5 |
//| Dump every buffer of the AD/Wyckoff indicator suite over full |
//| history to CSV, so the research pipeline can use the PRODUCTION |
//| definitions instead of a Python re-implementation of them. |
//| |
//| Read-only: creates indicator handles, copies buffers, writes |
//| files under Common\Files\Warrior_EA\indicators\. No orders, no |
//| chart changes, no writes to any model or AltData file. |
//| |
//| Buffer counts are not exposed by the API for a custom indicator, |
//| so each is probed from 0 upward until a copy fails - that is the |
//| only way to learn the count, and a failed probe is not an error. |
//+------------------------------------------------------------------+
#property script_show_inputs
#property strict
input string InpSymbols = "EURUSD,GBPUSD,USDJPY,AUDUSD,USDCAD,XAUUSD,SP500,BTCUSD";
input string InpTimeframes = "M15,H1"; // must match the research timeframes
input int InpMaxBars = 400000; // per symbol/timeframe
input int InpMaxBuffers = 12; // probe ceiling
string IndicatorList[] = {"ADCumulativeDelta", "ADShorteningOfThrust", "ADWyckoffEventStream",
"ADWyckoffFailedStructure", "ADWyckoffSignificantBarInversion",
"ADZigZag", "ADVolume", "ADTWAP"};
ENUM_TIMEFRAMES TfFromString(const string s)
{
if(s == "M1") return PERIOD_M1;
if(s == "M5") return PERIOD_M5;
if(s == "M15") return PERIOD_M15;
if(s == "M30") return PERIOD_M30;
if(s == "H1") return PERIOD_H1;
if(s == "H4") return PERIOD_H4;
if(s == "D1") return PERIOD_D1;
return PERIOD_CURRENT;
}
//--- how many buffers does this handle actually publish?
int ProbeBuffers(const int h, const int bars)
{
double tmp[];
int n = 0;
for(int b = 0; b < InpMaxBuffers; b++)
{
if(CopyBuffer(h, b, 0, MathMin(16, bars), tmp) <= 0)
break;
n++;
}
return n;
}
bool ExportOne(const string sym, const string tfName, const string indName)
{
ENUM_TIMEFRAMES tf = TfFromString(tfName);
int have = Bars(sym, tf);
if(have <= 100)
{
PrintFormat(" %s %s %s: only %d bars, skipped", sym, tfName, indName, have);
return false;
}
int bars = MathMin(have, InpMaxBars);
int h = iCustom(sym, tf, indName);
if(h == INVALID_HANDLE)
{
PrintFormat(" %s %s %s: INVALID_HANDLE err=%d", sym, tfName, indName, GetLastError());
return false;
}
//--- an indicator needs a moment to calculate its first pass over deep history
int spins = 0;
while(BarsCalculated(h) < bars && spins < 600)
{
Sleep(100);
spins++;
}
int ready = BarsCalculated(h);
if(ready <= 100)
{
PrintFormat(" %s %s %s: BarsCalculated=%d, skipped", sym, tfName, indName, ready);
IndicatorRelease(h);
return false;
}
bars = MathMin(bars, ready);
int nbuf = ProbeBuffers(h, bars);
if(nbuf <= 0)
{
PrintFormat(" %s %s %s: no readable buffers", sym, tfName, indName);
IndicatorRelease(h);
return false;
}
//--- pull the buffers and the bar times, oldest-first
datetime times[];
if(CopyTime(sym, tf, 0, bars, times) <= 0)
{
IndicatorRelease(h);
return false;
}
ArraySetAsSeries(times, false);
double buf[][12];
ArrayResize(buf, bars);
double one[];
for(int b = 0; b < nbuf; b++)
{
if(CopyBuffer(h, b, 0, bars, one) <= 0)
continue;
ArraySetAsSeries(one, false);
for(int i = 0; i < bars && i < ArraySize(one); i++)
buf[i][b] = one[i];
}
string dir = "Warrior_EA\\indicators";
FolderCreate(dir, FILE_COMMON);
string path = dir + "\\" + sym + "_" + tfName + "_" + indName + ".csv";
int fh = FileOpen(path, FILE_WRITE | FILE_TXT | FILE_ANSI | FILE_COMMON |
FILE_SHARE_READ | FILE_SHARE_WRITE);
if(fh == INVALID_HANDLE)
{
PrintFormat(" cannot write %s err=%d", path, GetLastError());
IndicatorRelease(h);
return false;
}
string head = "time";
for(int b = 0; b < nbuf; b++)
head += ",b" + IntegerToString(b);
FileWriteString(fh, head + "\n");
int written = 0;
for(int i = 0; i < bars; i++)
{
//--- skip the leading warm-up where every buffer is still empty
bool any = false;
for(int b = 0; b < nbuf; b++)
if(buf[i][b] != EMPTY_VALUE && MathAbs(buf[i][b]) < 1e15)
{
any = true;
break;
}
if(!any)
continue;
string line = IntegerToString((long)times[i]);
for(int b = 0; b < nbuf; b++)
{
double v = buf[i][b];
line += "," + ((v == EMPTY_VALUE || MathAbs(v) >= 1e15) ? "" : DoubleToString(v, 8));
}
FileWriteString(fh, line + "\n");
written++;
}
FileClose(fh);
IndicatorRelease(h);
PrintFormat(" %s %s %-34s %d buffers, %d rows", sym, tfName, indName, nbuf, written);
return true;
}
void OnStart()
{
string syms[], tfs[];
int ns = StringSplit(InpSymbols, ',', syms);
int nt = StringSplit(InpTimeframes, ',', tfs);
int ok = 0, fail = 0;
for(int s = 0; s < ns; s++)
{
string sym = syms[s];
StringTrimLeft(sym);
StringTrimRight(sym);
if(!SymbolSelect(sym, true))
{
PrintFormat(" %s: not available on this server", sym);
continue;
}
for(int t = 0; t < nt; t++)
{
string tfn = tfs[t];
StringTrimLeft(tfn);
StringTrimRight(tfn);
for(int k = 0; k < ArraySize(IndicatorList); k++)
{
if(ExportOne(sym, tfn, IndicatorList[k]))
ok++;
else
fail++;
}
}
}
PrintFormat("ExportIndicatorBuffers: %d exported, %d skipped -> Common\\Files\\Warrior_EA\\indicators", ok, fail);
}
//+------------------------------------------------------------------+