MQL5Book/Scripts/p7/CustomSymbolFilterTicks.mq5

144 lines
5.5 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:09:41 +02:00
//+------------------------------------------------------------------+
//| 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;
}
//+------------------------------------------------------------------+