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>
185 lines
6.1 KiB
MQL5
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|