//+------------------------------------------------------------------+ //| CustomSymbolFilterTicks.mq5 | //| Copyright 2022, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, MetaQuotes Ltd." #property link "https://www.mql5.com" #property description "Create specified custom symbol based on current chart's symbol with prunned ticks for faster tests and optimizations." #property script_show_inputs //#include "..\..\Include\PRTF.mqh" #define PRTF #include "..\..\Include\TickFilter.mqh" #include "..\..\Include\Timing.mqh" #include "..\..\Include\CustomSymbolMonitor.mqh" //+------------------------------------------------------------------+ //| Inputs | //+------------------------------------------------------------------+ input string CustomPath = "MQL5Book\\Part7"; // Custom Symbol Folder input datetime _Start; // Start (default: 120 days back) input TickFilter::FILTER_MODE Mode = TickFilter::SEQUENCE; //+------------------------------------------------------------------+ //| Globals | //+------------------------------------------------------------------+ string CustomSymbol = _Symbol + ".TckFltr" + "-" + EnumToString(Mode); const uint DailySeconds = 60 * 60 * 24; datetime Start = _Start == 0 ? TimeCurrent() - DailySeconds * 120 : _Start; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { bool custom = false; if(PRTF(SymbolExist(CustomSymbol, custom)) && custom) { if(IDYES == MessageBox(StringFormat("Delete existing custom symbol '%s'?", CustomSymbol), "Please, confirm", MB_YESNO)) { PRTF(SymbolSelect(CustomSymbol, false)); PRTF(CustomRatesDelete(CustomSymbol, 0, LONG_MAX)); PRTF(CustomTicksDelete(CustomSymbol, 0, LONG_MAX)); PRTF(CustomSymbolDelete(CustomSymbol)); } else { return; } } if(IDYES == MessageBox(StringFormat("Create new custom symbol '%s'?", CustomSymbol), "Please, confirm", MB_YESNO)) { if(PRTF(CustomSymbolCreate(CustomSymbol, CustomPath, _Symbol))) { //PRTF(CustomSymbolSetDouble(CustomSymbol, SYMBOL_TRADE_TICK_VALUE_PROFIT, 1.0)); // BUG: some properties are not set as expected, including very important ones: // SYMBOL_TRADE_TICK_VALUE, SYMBOL_TRADE_TICK_SIZE, etc. which remain zeros, // so we need to edit them "manually" SymbolMonitor sm; CustomSymbolMonitor csm(CustomSymbol, &sm); int props[] = {SYMBOL_TRADE_TICK_VALUE, SYMBOL_TRADE_TICK_SIZE/*, SYMBOL_TRADE_TICK_VALUE_PROFIT, SYMBOL_TRADE_TICK_VALUE_LOSS*/}; const int d1 = csm.verify(props); if(d1) { Print("Number of found descrepancies: ", d1); if(csm.verify(props)) // check again { Alert("Custom symbol can not be created, internal error!"); return; } Print("Fixed"); } CustomSymbolSetString(CustomSymbol, SYMBOL_DESCRIPTION, "Prunned ticks by " + EnumToString(Mode)); if(GenerateTickData()) { SymbolSelect(CustomSymbol, true); ChartOpen(CustomSymbol, PERIOD_H1); } } } } //+------------------------------------------------------------------+ //| Day-by-day tick data processor | //+------------------------------------------------------------------+ bool GenerateTickData() { bool result = true; datetime from = Start / DailySeconds * DailySeconds; // round up to a day boundary ulong read = 0, written = 0; uint day = 0; const uint total = (uint)((TimeCurrent() - from) / DailySeconds + 1); Timing timing; MqlTick array[]; while(!IsStopped() && from < TimeCurrent()) { Comment(TimeToString(from, TIME_DATE), " ", day++, "/", total, " elapsed: ", timing.elapsed(), ", remain: ", timing.remain(day * 1.0f / total)); const int r = PRTF(CopyTicksRange(_Symbol, array, COPY_TICKS_ALL, from * 1000L, (from + DailySeconds) * 1000L - 1)); if(r < 0) { Alert("Error reading ticks at ", TimeToString(from, TIME_DATE)); result = false; break; } read += r; if(r > 0) { const int t = PRTF(TickFilter::filter(Mode, array)); const int w = PRTF(CustomTicksReplace(CustomSymbol, from * 1000L, (from + DailySeconds) * 1000L - 1, array)); if(w <= 0) { Alert("Error writing custom ticks at ", TimeToString(from, TIME_DATE)); result = false; break; } written += w; } from += DailySeconds; } if(read > 0) { PrintFormat("Done ticks - read: %lld, written: %lld, ratio: %.1f%%", read, written, written * 100.0 / read); } Comment(""); return result; } //+------------------------------------------------------------------+