| //+------------------------------------------------------------------+
|
| //| ExportBars.mq5 - dump OHLCV to Common\Files for research |
|
| //| Throwaway research tool. Opens no trades, reads no indicators. |
|
| //+------------------------------------------------------------------+
|
| #property copyright "claude"
|
| #property version "1.10"
|
|
|
| input string ExportTag = "bars"; // file prefix
|
| input string ExportSymbols = "EURUSD,GBPUSD,USDJPY,USDCHF,USDCAD,AUDUSD,NZDUSD";
|
| input string ExportPeriods = "H1,H4,D1";
|
|
|
| ENUM_TIMEFRAMES TfFromString(const string s)
|
| {
|
| 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;
|
| if(s == "W1") return PERIOD_W1;
|
| return PERIOD_CURRENT;
|
| }
|
|
|
| bool DumpOne(const string sym, const ENUM_TIMEFRAMES tf)
|
| {
|
| MqlRates r[];
|
| ArraySetAsSeries(r, false); // oldest -> newest, matches numpy
|
| int got = -1;
|
| //--- a non-tested symbol's history may still be syncing on the first request
|
| for(int attempt = 0; attempt < 5 && got <= 0; attempt++)
|
| {
|
| got = CopyRates(sym, tf, 0, 500000, r);
|
| if(got <= 0)
|
| Sleep(1000);
|
| }
|
| if(got <= 0)
|
| {
|
| PrintFormat("ExportBars: %s %s -> CopyRates failed (err=%d)",
|
| sym, EnumToString(tf), GetLastError());
|
| return false;
|
| }
|
| string name = StringFormat("%s_%s_%s.csv", ExportTag, sym, EnumToString(tf));
|
| int h = FileOpen(name, FILE_WRITE | FILE_CSV | FILE_ANSI | FILE_COMMON, ',');
|
| if(h == INVALID_HANDLE)
|
| {
|
| PrintFormat("ExportBars: FileOpen %s failed (err=%d)", name, GetLastError());
|
| return false;
|
| }
|
| FileWrite(h, "time", "open", "high", "low", "close", "tick_volume", "spread");
|
| int digits = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
|
| if(digits <= 0)
|
| digits = 5;
|
| for(int i = 0; i < got; i++)
|
| FileWrite(h,
|
| TimeToString(r[i].time, TIME_DATE | TIME_MINUTES),
|
| DoubleToString(r[i].open, digits),
|
| DoubleToString(r[i].high, digits),
|
| DoubleToString(r[i].low, digits),
|
| DoubleToString(r[i].close, digits),
|
| (string)r[i].tick_volume,
|
| (string)r[i].spread);
|
| FileClose(h);
|
| PrintFormat("ExportBars: %s %s -> %d bars (%s .. %s) file=%s",
|
| sym, EnumToString(tf), got,
|
| TimeToString(r[0].time, TIME_DATE),
|
| TimeToString(r[got - 1].time, TIME_DATE), name);
|
| return true;
|
| }
|
|
|
| //--- OnDeinit, not OnInit: by then the tester has walked the whole range, so
|
| //--- CopyRates returns every bar of the pass rather than only the warm-up.
|
| void OnDeinit(const int reason)
|
| {
|
| string syms[], tfs[];
|
| int ns = StringSplit(ExportSymbols, ',', syms);
|
| int nt = StringSplit(ExportPeriods, ',', tfs);
|
| int ok = 0, fail = 0;
|
| for(int i = 0; i < ns; i++)
|
| {
|
| string sym = syms[i];
|
| StringTrimLeft(sym);
|
| StringTrimRight(sym);
|
| if(StringLen(sym) == 0)
|
| continue;
|
| //--- nudge the symbol into the working set; without this a symbol that is
|
| //--- not in Market Watch reads back as zero bars and looks like missing
|
| //--- history rather than an unselected symbol.
|
| if(!SymbolSelect(sym, true))
|
| PrintFormat("ExportBars: SymbolSelect(%s) failed (err=%d)", sym, GetLastError());
|
| for(int j = 0; j < nt; j++)
|
| {
|
| string t = tfs[j];
|
| StringTrimLeft(t);
|
| StringTrimRight(t);
|
| ENUM_TIMEFRAMES tf = TfFromString(t);
|
| if(tf == PERIOD_CURRENT)
|
| continue;
|
| if(DumpOne(sym, tf))
|
| ok++;
|
| else
|
| fail++;
|
| }
|
| }
|
| PrintFormat("ExportBars: DONE ok=%d fail=%d", ok, fail);
|
| }
|
|
|
| int OnInit(void) { return(INIT_SUCCEEDED); }
|
| void OnTick(void) { }
|