486 lines
No EOL
40 KiB
MQL5
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("---");
|
|
}
|
|
//+------------------------------------------------------------------+ |