MultiSymbolSignals/Include/MultiSymbol/Checks.mqh
super.admin f343eff89f convert
2025-05-30 16:10:44 +02:00

486 lines
No EOL
40 KiB
MQL5

//--- Связь с основным файлом индикатора
//#include "..\MultiSymbolPriceDivergence.mq5"
//--- Подключаем свои библиотеки
#include "SettingChart.mqh"
#include "SetDeleteObjects.mqh"
//+------------------------------------------------------------------+
//| Загружает и формируем необходимое/имеющееся кол-во данных |
//+------------------------------------------------------------------+
void LoadFormationData()
{
int try =10; // Количество удачных попыток
int number_bars =100; // Количество подгружаемых баров
//---
for(int s=0; s<SYMBOLS; s++)
{
int count_try =0; // Счётчик попыток копирования данных
int array_size =0; // Размер массива
datetime server_firstdate =NULL; // Время первого бара на сервере
datetime series_firstdate =NULL; // Время первого бара в базе терминала
//--- Получим первую дату символа-периода в базе терминала
for(int i=0; i<try; i++)
if(SeriesInfoInteger(symbols_names[s],Period(),SERIES_FIRSTDATE,series_firstdate))
break;
//--- Получим первую дату символа-периода на сервере
for(int i=0; i<try; i++)
if(SeriesInfoInteger(symbols_names[s],Period(),SERIES_SERVER_FIRSTDATE,server_firstdate))
break;
//--- Выведем сообщение
message_last=message_formation_data="Процесс загрузки и формирования данных текущего таймфрейма: "+
symbols_names[s]+"("+IntegerToString(s+1)+"/"+IntegerToString(SYMBOLS)+") ... ";
ShowCanvasMessage(message_formation_data);
//--- Загрузим/сформируем данные,
// если размер массива меньше, чем максимальное количество баров в терминале, а также
// между первой датой серии в терминале и первой датой серии на сервере больше указанного количества баров
while(array_size<on_calc_rates_total &&
series_firstdate-server_firstdate>PeriodSeconds()*number_bars)
{
datetime copied_time[];
//--- Получим первую дату символа-периода в базе терминала
for(int i=0; i<try; i++)
if(SeriesInfoInteger(symbols_names[s],Period(),SERIES_FIRSTDATE,series_firstdate))
break;
//--- Загрузим/скопируем ещё указанное количество баров
if(CopyTime(symbols_names[s],Period(),0,array_size+number_bars,copied_time))
{
//--- Если время первого бара массива с вычетом кол-ва подгружаемых баров раньше,
// чем время первого бара на графике, остановим цикл
if(copied_time[0]-PeriodSeconds()*number_bars<on_calc_time[0])
break;
//--- Если размер массива не увеличился,
// увеличим счётчик
if(ArraySize(copied_time)==array_size)
count_try++;
//--- Иначе получим текущий размер массива
else
array_size=ArraySize(copied_time);
//--- Если размер массива не увеличивается в течении
// 100 попыток, остановим цикл и обнулим счётчик для следующего символа
if(count_try==100)
{
count_try=0;
break;
}
}
}
}
}
//+------------------------------------------------------------------+
//| Загружает и формируем необходимое/имеющееся кол-во данных |
//+------------------------------------------------------------------+
void LoadFormationDataHighTF()
{
//--- Если в режиме вертикальной линии для начальной точки расхождения цен, выходим
if(StartPriceDivergence==VERT_LINE)
return;
//---
int try =50; // Количество удачных попыток
int number_bars =100; // Количество подгружаемых баров
//---
int count_try =0; // Счётчик попыток копирования данных
int array_size =0; // Размер массива
datetime server_firstdate =NULL; // Время первого бара на сервере
datetime series_firstdate =NULL; // Время первого бара в базе терминала
//--- Получим первую дату символа-периода в базе терминала
for(int i=0; i<try; i++)
if(SeriesInfoInteger(Symbol(),timeframe_start_point,SERIES_FIRSTDATE,series_firstdate))
break;
//--- Получим первую дату символа-периода на сервере
for(int i=0; i<try; i++)
if(SeriesInfoInteger(Symbol(),timeframe_start_point,SERIES_SERVER_FIRSTDATE,server_firstdate))
break;
//--- Выведем сообщение
message_last=message_formation_data="Процесс загрузки и формирования данных старшего таймфрейма ... ";
ShowCanvasMessage(message_formation_data);
//--- Загрузим/сформируем данные,
// между первой датой серии в терминале и первой датой серии на сервере больше указанного количества баров
while(series_firstdate>server_firstdate &&
series_firstdate-server_firstdate>PeriodSeconds(timeframe_start_point)*number_bars)
{
datetime copied_time[];
//--- Получим первую дату символа-периода в базе терминала
for(int i=0; i<try; i++)
if(SeriesInfoInteger(Symbol(),timeframe_start_point,SERIES_FIRSTDATE,series_firstdate))
break;
//--- Загрузим/скопируем ещё указанное количество баров
if(CopyTime(Symbol(),timeframe_start_point,0,array_size+number_bars,copied_time))
{
//--- Если время первого бара массива с вычетом кол-ва подгружаемых баров раньше меньше,
// чем время первого бара на графике, остановим цикл
if(copied_time[0]-PeriodSeconds(timeframe_start_point)*number_bars<=on_calc_time[0])
break;
//--- Если размер массива не увеличился,
// увеличим счётчик
if(ArraySize(copied_time)==array_size)
count_try++;
//--- Иначе получим текущий размер массива
else
array_size=ArraySize(copied_time);
//--- Если размер массива не увеличивается в течении
// 100 попыток, остановим цикл и обнулим счётчик для следующего символа
if(count_try==100)
break;
}
}
}
//+------------------------------------------------------------------+
//| Проверяет количество доступных данных у всех символов |
//+------------------------------------------------------------------+
bool CheckAvailableData()
{
int try=100;
//---
for(int s=0; s<SYMBOLS; s++)
{
//--- Если такой символ есть
if(symbols_names[s]!=empty_symbol)
{
datetime time[]; // Массив для проверки количества баров
int total_period_bars =0; // Количество баров текущего периода
datetime terminal_first_date =NULL; // Первая дата имеющихся данных текущего периода в терминале
//--- Получим первую дату данных текущего периода в терминале
terminal_first_date=(datetime)SeriesInfoInteger(symbols_names[s],Period(),SERIES_TERMINAL_FIRSTDATE);
//--- Получим количество доступных баров от указанной даты
total_period_bars=Bars(symbols_names[s],Period(),terminal_first_date,TimeCurrent());
//--- Проверим готовность данных баров
for(int i=0; i<try; i++)
{
//--- Скопируем указанное количество данных
if(CopyTime(symbols_names[s],Period(),0,total_period_bars,time))
{
//--- Если скопировалось нужное количество, остановим цикл
if(ArraySize(time)>=total_period_bars)
break;
}
}
//--- Если скопировано меньше данных
// значит нужно совершить ещё одну попытку
if(ArraySize(time)==0 || ArraySize(time)<total_period_bars)
{
message_last=message_data_available;
ShowCanvasMessage(message_data_available);
on_calc_prev_calculated=0;
return(false);
}
}
}
//--- Если в режиме вертикальной линии для начальной точки расхождения цен, выходим
if(StartPriceDivergence==VERT_LINE)
return(true);
else
{
datetime time[]; // Массив для проверки количества баров
int total_period_bars =0; // Количество баров текущего периода
datetime terminal_firstdate =NULL; // Первая дата имеющихся данных текущего периода в терминале
//--- Получим первую дату данных текущего периода в терминале
for(int i=0; i<try; i++)
if((terminal_firstdate=(datetime)SeriesInfoInteger(Symbol(),Period(),SERIES_FIRSTDATE))>0)
break;
//--- Получим количество доступных баров от указанной даты
for(int i=0; i<try; i++)
if((total_period_bars=(int)SeriesInfoInteger(Symbol(),timeframe_start_point,SERIES_BARS_COUNT))>0)
break;
//--- Проверим готовность данных баров
// Скопируем указанное количество данных
for(int i=0; i<try; i++)
if(CopyTime(Symbol(),timeframe_start_point,
terminal_firstdate+PeriodSeconds(timeframe_start_point),TimeCurrent(),time)>0)
break;
//--- Если скопировано меньше данных
// значит нужно совершить ещё одну попытку
if(ArraySize(time)<=0 || total_period_bars<=0)
{
message_last=message_data_available;
ShowCanvasMessage(message_data_available);
on_calc_prev_calculated=0;
return(false);
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Проверка события загрузки более глубокой истории |
//+------------------------------------------------------------------+
bool CheckEventLoadHistory()
{
bool load=false;
//---
for(int s=0; s<SYMBOLS; s++)
{
//--- Если такой символ есть
if(symbols_names[s]!=empty_symbol)
{
//--- Если нужно обновить серии
if(on_calc_prev_calculated==0)
{
ResetLastError();
//--- Получим первую дату символа-периода
SeriesInfoInteger(symbols_names[s],Period(),SERIES_FIRSTDATE,series_first_date[s]);
if(GetLastError()!=0)
return(true);
//--- Если здесь в первый раз (отсутствует значение), то
if(series_first_date_last[s]==NULL)
//--- Запомним первую дату символа-периода для последующих сравнений
// с целью определения загрузки более глубокой истории
series_first_date_last[s]=series_first_date[s];
}
else
{
ResetLastError();
//--- Получим первую дату символа-периода
SeriesInfoInteger(symbols_names[s],Period(),SERIES_FIRSTDATE,series_first_date[s]);
if(GetLastError()!=0)
return(true);
//--- Если даты отличаются, то есть дата в памяти более поздняя,
// чем та, которую получили сейчас, то
// значит была загрузка более глубокой истории
if(series_first_date_last[s]>series_first_date[s])
{
//--- Выведем сообщение в журнал
Print("(",symbols_names[s],",",TimeframeToString(Period()),
") > Была загружена/сформирована более глубокая история: ",
series_first_date_last[s]," > ",series_first_date[s]);
//--- Запомним дату
series_first_date_last[s]=series_first_date[s];
load=true;
}
}
}
}
//--- Если была загружена/сформирована более глубокая история, то
// отправим команду на обновление графических серий индикатора
if(load)
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Проверяет синхронизированность по символу/периоду |
//+------------------------------------------------------------------+
bool CheckSymbolIsSynchronized()
{
//--- Если есть соединение с сервером, то
// проверим синхронизированность данных
if(TerminalInfoInteger(TERMINAL_CONNECTED))
{
for(int s=0; s<SYMBOLS; s++)
{
//--- Если символ есть
if(symbols_names[s]!=empty_symbol)
{
//--- Если данные не синхронизированы, то
// сообщим об этом и попробуем снова
if(!SeriesInfoInteger(symbols_names[s],Period(),SERIES_SYNCHRONIZED) ||
!SeriesInfoInteger(symbols_names[s],timeframe_start_point,SERIES_SYNCHRONIZED))
{
message_last=message_is_synchronized;
ShowCanvasMessage(message_is_synchronized);
return(false);
}
}
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Определение времени первого истинного бара для отрисовки |
//+------------------------------------------------------------------+
bool DetermineBeginForCalculate()
{
for(int s=0; s<SYMBOLS; s++)
{
datetime time[]; // Массив времени баров
int total_period_bars=0; // Количество баров
//--- Если такого символа нет, перейти к следующему
if(symbols_names[s]==empty_symbol)
continue;
//--- Получим общее количество баров символа
total_period_bars=Bars(symbols_names[s],Period());
//--- Скопируем массив времени баров.
// Если не получилось, попробуем ещё раз
if(CopyTime(symbols_names[s],Period(),0,total_period_bars,time)<total_period_bars)
return(false);
//--- Получим время первого истинного бара,
// который соответствует текущему таймфрейму
limit_time[s]=GetFirstTruePeriodBarTime(time);
//--- Установим вертикальную линию на истинном баре
CreateVerticalLines(0,0,limit_time[s],prefix+symbols_names[s]+": begin time series",
2,STYLE_SOLID,line_color[s],false,false,true,TimeToString(limit_time[s]),"\n");
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Возвращает время первого истинного бара текущего периода |
//+------------------------------------------------------------------+
datetime GetFirstTruePeriodBarTime(datetime &time[])
{
datetime true_period =NULL; // Время первого истинного бара
int array_size =0; // Размер массива
//--- Получим размер массива
array_size=ArraySize(time);
ArraySetAsSeries(time,false);
//--- Поочерёдно проверяем каждый бар
for(int i=1; i<array_size; i++)
{
//--- Если бар соответствует текущему таймфрейму
if(time[i]-time[i-1]==PeriodSeconds())
{
//--- Запомним и остановим цикл
true_period=time[i-1];
break;
}
}
//--- Вернём время первого истинного бара
return(true_period);
}
//+------------------------------------------------------------------+
//| Добавляет указанный символ в окно обзор рынка |
//+------------------------------------------------------------------+
string CheckGetSymbol(string symbol)
{
int symbol_total =0; // Количество символов
string nm_symbol =""; // Имя символа
//--- Если передали пустую строку, то вернуть пустую строку
if(symbol=="")
return(empty_symbol);
//--- Всего символов на сервере
symbol_total=SymbolsTotal(false);
//--- Пройтись по всему списку символов
for(int s=symbol_total-1; s>=0; s--)
{
//--- Имя символа на сервере
nm_symbol=SymbolName(s,false);
//--- Если есть такой символ, то
if(nm_symbol==symbol)
{
//--- установим его в окно Обзор Рынка и
SymbolSelect(nm_symbol,true);
//--- вернём его имя
return(symbol);
}
}
//--- Если такого символа нет, то
// вернём строку символизирующую отсутствие символа
return(empty_symbol);
}
//+------------------------------------------------------------------+
//| Проверка на использование индикатора в тестере |
//+------------------------------------------------------------------+
bool CheckTesterMode()
{
//--- Если индикатор был запущен в тестере, то сообщим, что
// он не предназначен для использования в тестере
if(MQL5InfoInteger(MQL5_TESTER) ||
MQL5InfoInteger(MQL5_VISUAL_MODE) ||
MQL5InfoInteger(MQL5_OPTIMIZATION))
{
Comment("На данный момент индикатор <- "+PROGRAM_NAME+" -> не предназначен для использования в тестере!");
return(false);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Проверяет входные параметры на корректность |
//+------------------------------------------------------------------+
bool CheckInputParameters()
{
//--- Если сейчас режим не вертикальной линии
if(StartPriceDivergence!=VERT_LINE)
{
//--- Если текущий период больше либо равен
// указанному для начальной точки расхождения цен, сообщим об этом и выйдем
if(PeriodSeconds()>=PeriodSeconds(timeframe_start_point))
{
Print("Текущий таймфрейм должен быть меньше, чем в параметре Start Price Divergence!");
Comment("Текущий таймфрейм должен быть меньше, чем в параметре Start Price Divergence!");
return(false);
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Следит за размерами канвы |
//+------------------------------------------------------------------+
void EventChartChange()
{
//--- Получим свойства окна
SetSubwindowProperties();
//--- Если размеры окна не изменились, выйдем
if(!CheckChartSize())
return;
//--- Если размер окна меньше одного пикселя или
// центр рассчитан некорректно, выйдем
if(chart_height<1 || chart_vcenter<1)
return;
//--- Установим новый размер канве
ResizeCanvas();
//--- Покажем последнее сообщение
ShowCanvasMessage(message_last);
}
//+------------------------------------------------------------------+
//| Проверим размеры графика |
//+------------------------------------------------------------------+
bool CheckChartSize()
{
//--- Если размеры графика не изменились, выйдем
if(last_chart_width==chart_width &&
last_chart_height==chart_height)
return(false);
//--- Если же изменились, то запомним их
else
{
last_chart_width=chart_width;
last_chart_height=chart_height;
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Проверяет пустые значения |
//+------------------------------------------------------------------+
bool CheckEmptyValues()
{
if(MQL5InfoInteger(MQL5_VISUAL_MODE))
return(true);
//---
for(int s=0; s<SYMBOLS; s++)
{
static int count_empty=0;
if(count_empty>1000)
{
count_empty=0;
on_calc_prev_calculated=0;
return(false);
}
//---
if(symbols_names[s]!=empty_symbol)
{
for(int i=on_calc_rates_total-500; i<on_calc_rates_total; i++)
{
if(on_calc_time[i]<limit_time[s])
continue;
//---
if(buffer_data[s].close[i]==EMPTY_VALUE)
count_empty++;
}
}
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Выводит в журнал указанное количество значений из последних |
//+------------------------------------------------------------------+
void CheckLastEmptyValues(int amount)
{
for(int i=on_calc_rates_total-amount; i<on_calc_rates_total; i++)
Print(symbols_names[0],": ",DoubleToString(buffer_data[0].close[i],Digits()));
//---
Print("---");
}
//+------------------------------------------------------------------+