1207 lines
106 KiB
MQL5
1207 lines
106 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| ATR_MS.mq5 |
|
|
//| Copyright 2013, https://login.mql5.com/ru/users/tol64 |
|
|
//| Site, http://tol64.blogspot.com/2013/05/216.html |
|
|
//+------------------------------------------------------------------+
|
|
//--- Свойства индикатора
|
|
#property copyright "Copyright 2013, http://tol64.blogspot.com"
|
|
#property link "https://www.mql5.com/de/articles/752"
|
|
#property description "email: hello.tol64@gmail.com"
|
|
#property version "1.0"
|
|
#property indicator_separate_window // Индикатор в отдельном подокне
|
|
#property indicator_minimum 0 // Минимальное значение индикатора
|
|
#property indicator_buffers 6 // Количество буферов для расчёта индикатора
|
|
#property indicator_plots 6 // Количество графических серий
|
|
|
|
//--- Константа для возврата терминалу команды на пересчёт индикатора
|
|
#define RESET 0
|
|
#define LEVELS 6 // Количество уровней
|
|
#define SYMBOLS 6 // Количество символов
|
|
//--- Подключим класс для работы с канвой
|
|
#include <Canvas\Canvas.mqh>
|
|
|
|
//--- Внешние параметры
|
|
input int IndicatorPeriod=14; // Indicator Period
|
|
sinput string dlm01=""; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
input string Symbol02 ="GBPUSD"; // Symbol 02
|
|
input string Symbol03 ="AUDUSD"; // Symbol 03
|
|
input string Symbol04 ="NZDUSD"; // Symbol 04
|
|
input string Symbol05 ="USDCAD"; // Symbol 05
|
|
input string Symbol06 ="USDCHF"; // Symbol 06
|
|
sinput string dlm02=""; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
input int Level01 =10; // Level 01
|
|
input int Level02 =50; // Level 02
|
|
input int Level03 =100; // Level 03
|
|
input int Level04 =200; // Level 04
|
|
input int Level05 =400; // Level 05
|
|
input int Level06 =600; // Level 06
|
|
|
|
//--- Глобальные переменные и массивы
|
|
CCanvas canvas; // Загрузка класса
|
|
//--- Переменные/массивы для копирования данных из OnCalculate()
|
|
int on_calc_rates_total =0; // Размер входных таймсерий
|
|
int on_calc_prev_calculated =0; // Обработано баров на предыдущем вызове
|
|
datetime on_calc_time[]; // Время открытия
|
|
double on_calc_open[]; // Цены открытия
|
|
double on_calc_high[]; // Максимальные цены
|
|
double on_calc_low[]; // Минимальные цены
|
|
double on_calc_close[]; // Цены закрытия
|
|
long on_calc_tick_volume[]; // Тиковые объёмы
|
|
long on_calc_volume[]; // Реальные объёмы
|
|
int on_calc_spread[]; // Спред
|
|
//--- Структура массивов буферов
|
|
// для отрисовки значений индикатора
|
|
struct buffers { double data[]; };
|
|
buffers buffer_atr[SYMBOLS];
|
|
//--- Структуры массивов для подготовки данных
|
|
struct temp_time { datetime time[]; };
|
|
temp_time temp_symbol_time[SYMBOLS];
|
|
struct temp_atr { double value[]; };
|
|
temp_atr temp_atr_values[SYMBOLS];
|
|
//--- Для хранения и проверки времени первого бара в терминале
|
|
datetime series_first_date[SYMBOLS];
|
|
datetime series_first_date_last[SYMBOLS];
|
|
//--- Массив времени бара, от которого начинать отрисовку
|
|
datetime limit_time[SYMBOLS];
|
|
//--- Массив уровней индикатора
|
|
int levels[LEVELS];
|
|
//--- Массив названий символов
|
|
string symbols_names[SYMBOLS];
|
|
//--- Хэндлы символов
|
|
int handle_symbol[SYMBOLS];
|
|
//--- Цвета линий индикатора
|
|
color line_color[SYMBOLS]=
|
|
{clrRed,clrDodgerBlue,clrLimeGreen,clrGold,clrAqua,clrMagenta};
|
|
//--- Строка символизирующая отсутствие символа
|
|
string empty_symbol="EMPTY";
|
|
//--- Свойства подокна индикатора
|
|
int number_subwindow =WRONG_VALUE; // Номер подокна
|
|
int chart_width =0; // Ширина графика
|
|
int subwindow_height =0; // Высота подокна
|
|
int last_chart_width =0; // Последняя в памяти ширина графика
|
|
int last_subwindow_height =0; // Последняя в памяти высота подокна
|
|
int subwindow_center =0; // Центр подокна по горизонтали
|
|
int subwindow_vcenter =0; // Центр подокна по вертикали
|
|
string shortname_subwindow ="ATR_MS"; // Короткое имя индикатора
|
|
string prefix =shortname_subwindow+"_"; // Префикс для объектов
|
|
//--- Свойства канвы
|
|
string canvas_name =prefix+"canvas"; // Название канвы
|
|
color canvas_bg_color =clrBlack; // Цвет фона канвы
|
|
uchar canvas_opacity =190; // Степень прозрачности
|
|
int font_size =16; // Размер шрифта
|
|
string font_name ="Calibri"; // Шрифт
|
|
ENUM_COLOR_FORMAT clr_format =COLOR_FORMAT_ARGB_RAW; // Компоненты цвета не обрабатываются терминалом
|
|
//--- Сообщения канвы
|
|
string message_invalid_handle ="Невалидный хэндл индикатора! Подождите пожалуйста...";
|
|
string message_data_available ="Подготовка данных! Подождите пожалуйста...";
|
|
string message_number_data ="Данных меньше, чем период индикатора! Попробуйте уменьшить значение.";
|
|
string message_is_synchronized ="Данные не синхронизированы! Подождите пожалуйста...";
|
|
string message_formation_data ="";
|
|
string message_synchro_update ="";
|
|
string message_last ="";
|
|
//--- Максимальное количество баров установленное в настройках терминала
|
|
int terminal_max_bars=0;
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Проверим корректность входных параметров
|
|
if(!CheckInputParameters())
|
|
return(INIT_PARAMETERS_INCORRECT);
|
|
//--- Включим таймер с интервалом 1 секунда
|
|
EventSetMillisecondTimer(1000);
|
|
//--- Установим шрифт для отображения в канве
|
|
canvas.FontSet(font_name,font_size,FW_NORMAL);
|
|
//--- Инициализация массивов
|
|
InitArrays();
|
|
//--- Инициализируем массив символов
|
|
InitSymbolsNames();
|
|
//--- Инициализируем массив уровней
|
|
InitLevels();
|
|
//--- Получим хэндлы индикаторов
|
|
GetHandles();
|
|
//--- Установим свойства индикатора
|
|
SetPropertiesIndicator();
|
|
//--- Получим количество баров установленное в настройках терминала
|
|
terminal_max_bars=TerminalInfoInteger(TERMINAL_MAXBARS);
|
|
//--- Очистим комментарий
|
|
Comment("");
|
|
//--- Обновим график
|
|
ChartRedraw();
|
|
//--- Инициализация прошла успешно
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Деинициализация |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
if(reason==REASON_REMOVE || // Если индикатор удалён с графика или
|
|
reason==REASON_CHARTCHANGE || // символ или период был изменён или
|
|
reason==REASON_RECOMPILE || // программа была перекомпилирована или
|
|
reason==REASON_CHARTCLOSE || // график был закрыт или
|
|
reason==REASON_CLOSE || // терминал был закрыт или
|
|
reason==REASON_PARAMETERS) // параметры были изменены
|
|
{
|
|
//--- Отключим таймер
|
|
EventKillTimer();
|
|
//--- Удалим уровни
|
|
DeleteLevels();
|
|
//--- Удалим вертикальные линии
|
|
DeleteVerticalLines();
|
|
//--- Удалим канву
|
|
DeleteCanvas();
|
|
//--- Освободим расчётную часть индикатора
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
IndicatorRelease(handle_symbol[s]);
|
|
//--- Очистим комментарий
|
|
Comment("");
|
|
}
|
|
//--- Обновим график
|
|
ChartRedraw();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator iteration function |
|
|
//+------------------------------------------------------------------+
|
|
int OnCalculate(const int rates_total, // размер входных таймсерий
|
|
const int prev_calculated, // обработано баров на предыдущем вызове
|
|
const datetime &time[], // Время открытия
|
|
const double &open[], // Цены открытия
|
|
const double &high[], // Максимальные цены
|
|
const double &low[], // Минимальные цены
|
|
const double &close[], // Цены закрытия
|
|
const long &tick_volume[], // Тиковые объёмы
|
|
const long &volume[], // Реальные объёмы
|
|
const int &spread[]) // Спред
|
|
{
|
|
//--- Для определения, с какого бара производить расчёт
|
|
// To determine which bar to calculate
|
|
int limit=0;
|
|
//--- Сделаем копию параметров OnCalculate()
|
|
// Make a copy of the OnCalculate() parameters
|
|
CopyDataOnCalculate(rates_total,prev_calculated,
|
|
time,open,high,low,close,
|
|
tick_volume,volume,spread);
|
|
//--- Установим размер массивам для подготовки данных
|
|
// Set size for arrays for data preparation
|
|
ResizeCalculateArrays();
|
|
//--- Если это первый расчёт или загружена более глубокая история или были заполнены пропуски истории
|
|
// If this is the FIRST calculation or DOWNLOAD of deeper history or FILLING of history gaps
|
|
if(prev_calculated==0)
|
|
{
|
|
//--- Обнулим массивы для подготовки данных
|
|
// Zero the arrays for data preparation.
|
|
ZeroCalculateArrays();
|
|
//--- Обнулим индикаторные буферы
|
|
// Zero indicator buffers
|
|
ZeroIndicatorBuffers();
|
|
//--- Получим свойства подокна
|
|
SetSubwindowProperties();
|
|
//--- Установим канву
|
|
SetCanvas();
|
|
//--- rf. https://www.mql5.com/en/docs/series/timeseries_access
|
|
// LoadFormationData() - SERIES_FIRSTDATE, SERIES_SERVER_FIRSTDATE
|
|
// CheckAvailableData() - CopyTime() and CopyBuffer() from SERIES_TERMINAL_FIRSTDATE to TimeCurrent()
|
|
// CheckEventLoadHistory() -
|
|
// CheckSymbolIsSynchronized() - SERIES_SYNCHRONIZED, TERMINAL_CONNECTED
|
|
// DetermineBeginForCalculate() -
|
|
|
|
//--- Загрузим и сформируем необходимое/имеющееся количество данных
|
|
// Load and generate the necessary / available amount of data
|
|
LoadFormationData();
|
|
//--- Если есть невалидный хэндл, попробуем получить его снова
|
|
// If there is an invalid handle, try to get it again.
|
|
if(!GetHandles())
|
|
return(RESET);
|
|
//--- Проверяет количество доступных данных у всех символов
|
|
// Checks the amount of data available for all symbols.
|
|
if(!CheckAvailableData())
|
|
return(RESET);
|
|
//--- Если загружена более глубокая история
|
|
// if loading a deeper history
|
|
if(!CheckEventLoadHistory())
|
|
return(RESET);
|
|
//--- Проверим синхронизированность данных по символу/периоду на данный момент
|
|
// Check the synchronization of data on the symbol / period at the moment
|
|
if(!CheckSymbolIsSynchronized())
|
|
return(RESET);
|
|
//--- Определим для каждого символа, с какого бара начинать отрисовку
|
|
// Determine for each symbol, from which bar to start drawing
|
|
if(!DetermineBeginForCalculate())
|
|
return(RESET);
|
|
//--- Если дошли до этого момента, то значит OnCalculate() вернёт ненулевое значение и
|
|
// это нужно запомнить
|
|
// If you have reached this point, it means OnCalculate () returns a nonzero value and
|
|
// you need to remember this.
|
|
on_calc_prev_calculated=rates_total;
|
|
}
|
|
//--- Если нужно пересчитать только последние значения
|
|
// If you need to recount only the last values
|
|
else
|
|
limit=prev_calculated-1;
|
|
|
|
//--- Подготовим данные для отрисовки
|
|
// Prepare data for rendering
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
//--- Если символ существует
|
|
// If symbol exists
|
|
if(symbols_names[s]!=empty_symbol)
|
|
{
|
|
double percent=0.0; // Для расчёта процента прогресса - To calculate the percentage of progress
|
|
message_last=message_synchro_update="Подготовка данных ("+IntegerToString(rates_total)+" баров) : "+
|
|
symbols_names[s]+"("+IntegerToString(s+1)+"/"+IntegerToString(SYMBOLS)+") - 00% ... ";
|
|
//--- Выведем сообщение - Display message
|
|
ShowCanvasMessage(message_synchro_update);
|
|
//--- Проконтролируем каждое значение массива
|
|
// We control each array value
|
|
for(int i=limit; i<rates_total; i++)
|
|
{
|
|
PreparationData(i,s,time);
|
|
//--- Каждые 1000 баров обновляем сообщение
|
|
// Every 1000 bars update message
|
|
if(!(i%1000))
|
|
{
|
|
//--- Процент прогресса - percentage of progress
|
|
PercentProgress(i,s,percent);
|
|
//--- Выведем сообщение - We will display the message
|
|
ShowCanvasMessage(message_synchro_update);
|
|
}
|
|
//--- Каждые 2000 баров проверяем размеры подокна
|
|
// и если размер изменился подгоним под него размер канвы
|
|
// Every 2000 bars we check the dimensions of the subwindow
|
|
// and if the size has changed we will fit the size of the canvas
|
|
if(!(i%2000))
|
|
EventChartChange();
|
|
}
|
|
}
|
|
}
|
|
//--- Заполним индикаторные буферы
|
|
// We will fill indicator buffers
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
//--- Если указанного символа не существует, обнулим буфер
|
|
// If the specified character does not exist, zero the buffer
|
|
if(symbols_names[s]==empty_symbol)
|
|
ArrayInitialize(buffer_atr[s].data,EMPTY_VALUE);
|
|
else
|
|
{
|
|
//--- Сформируем сообщение - We will form a message
|
|
message_last=message_synchro_update="Обновление данных индикатора: "+
|
|
symbols_names[s]+"("+IntegerToString(s+1)+"/"+IntegerToString(SYMBOLS)+") ... ";
|
|
//--- Выведем сообщение - We will display the message
|
|
ShowCanvasMessage(message_synchro_update);
|
|
//--- Заполним индикаторные буферы значениями
|
|
// Fill indicator buffers with values
|
|
for(int i=limit; i<rates_total; i++)
|
|
{
|
|
FillIndicatorBuffers(i,s,time);
|
|
//--- Каждые 2000 баров проверяем размеры подокна
|
|
// и если размер изменился подгоним под него размер канвы
|
|
// Every 2000 bars we check the dimensions of the subwindow
|
|
// and if the size has changed we will fit the size of the canvas
|
|
if(!(i%2000))
|
|
EventChartChange();
|
|
}
|
|
}
|
|
}
|
|
//--- Удалим канву
|
|
DeleteCanvas();
|
|
//--- Установим уровни индикатора
|
|
SetLevels();
|
|
//--- Обнулим переменные
|
|
message_last="";
|
|
message_synchro_update="";
|
|
//--- Обновим график
|
|
ChartRedraw();
|
|
//--- Вернём размер массива данных текущего символа
|
|
return(rates_total);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Timer function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer()
|
|
{
|
|
//--- Если была загружена более глубокая история
|
|
if(!CheckEventLoadHistory())
|
|
on_calc_prev_calculated=0;
|
|
//--- Если по какой-то причине расчёты не были завершены или
|
|
// подкачана более глубокая история или
|
|
// были заполнены пропуски истории, то
|
|
// не дожидаясь тика сделаем ещё одну попытку
|
|
if(on_calc_prev_calculated==0)
|
|
{
|
|
OnCalculate(on_calc_rates_total,on_calc_prev_calculated,
|
|
on_calc_time,on_calc_open,on_calc_high,on_calc_low,on_calc_close,
|
|
on_calc_tick_volume,on_calc_volume,on_calc_spread);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Проверяет входные параметры на корректность |
|
|
//+------------------------------------------------------------------+
|
|
bool CheckInputParameters()
|
|
{
|
|
if(IndicatorPeriod>500)
|
|
{
|
|
Comment("Уменьшите период индикатора! Indicator Period: ",IndicatorPeriod,"; Limit: 500;");
|
|
printf("Уменьшите период индикатора! Indicator Period: %d; Limit: %d;",IndicatorPeriod,500);
|
|
return(false);
|
|
}
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает свойства индикатора |
|
|
//+------------------------------------------------------------------+
|
|
void SetPropertiesIndicator()
|
|
{
|
|
//--- Установим короткое имя
|
|
IndicatorSetString(INDICATOR_SHORTNAME,shortname_subwindow);
|
|
//--- Установим количество знаков
|
|
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
|
|
//--- Определим буферы для отрисовки
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
SetIndexBuffer(s,buffer_atr[s].data,INDICATOR_DATA);
|
|
//--- Установим метки для текущего таймфрейма
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetString(s,PLOT_LABEL,
|
|
"ATR ("+IntegerToString(s)+", "+symbols_names[s]+")");
|
|
//--- Установим тип линий
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_LINE);
|
|
//--- Установим толщину линий
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetInteger(s,PLOT_LINE_WIDTH,1);
|
|
//--- Установим цвет линий
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetInteger(s,PLOT_LINE_COLOR,line_color[s]);
|
|
//--- Пустое значение для построения, для которого нет отрисовки
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetDouble(s,PLOT_EMPTY_VALUE,EMPTY_VALUE);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Первая инициализация массивов |
|
|
//+------------------------------------------------------------------+
|
|
void InitArrays()
|
|
{
|
|
ArrayInitialize(limit_time,NULL);
|
|
ArrayInitialize(series_first_date,NULL);
|
|
ArrayInitialize(series_first_date_last,NULL);
|
|
ArrayInitialize(handle_symbol,INVALID_HANDLE);
|
|
//---
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
ArrayInitialize(buffer_atr[s].data,EMPTY_VALUE);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Инициализирует массив символов |
|
|
//+------------------------------------------------------------------+
|
|
void InitSymbolsNames()
|
|
{
|
|
symbols_names[0]=CheckGetSymbol(_Symbol);
|
|
symbols_names[1]=CheckGetSymbol(Symbol02);
|
|
symbols_names[2]=CheckGetSymbol(Symbol03);
|
|
symbols_names[3]=CheckGetSymbol(Symbol04);
|
|
symbols_names[4]=CheckGetSymbol(Symbol05);
|
|
symbols_names[5]=CheckGetSymbol(Symbol06);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Инициализирует массив уровней |
|
|
//+------------------------------------------------------------------+
|
|
void InitLevels()
|
|
{
|
|
levels[0]=Level01;
|
|
levels[1]=Level02;
|
|
levels[2]=Level03;
|
|
levels[3]=Level04;
|
|
levels[4]=Level05;
|
|
levels[5]=Level06;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Загружает и формируем необходимое/имеющееся кол-во данных |
|
|
//| It loads and we form the necessary / available amount of data |
|
|
//+------------------------------------------------------------------+
|
|
void LoadFormationData()
|
|
{
|
|
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; // Время первого бара в базе терминала
|
|
//--- Получим первую дату символа-периода в базе терминала
|
|
// Get the first date of the symbol-period in the terminal base
|
|
SeriesInfoInteger(symbols_names[s],Period(),SERIES_FIRSTDATE,series_firstdate);
|
|
//--- Получим первую дату символа-периода на сервере
|
|
// Get the first date of the symbol-period on the server
|
|
SeriesInfoInteger(symbols_names[s],Period(),SERIES_SERVER_FIRSTDATE,server_firstdate);
|
|
//--- Выведем сообщение - We will display the message
|
|
message_last=message_formation_data="Процесс загрузки и формирования данных: "+
|
|
symbols_names[s]+"("+IntegerToString(s+1)+"/"+IntegerToString(SYMBOLS)+") ... ";
|
|
ShowCanvasMessage(message_formation_data);
|
|
//--- Загрузим/сформируем данные, если размер массива меньше, чем максимальное количество баров в терминале,
|
|
// а также между первой датой серии в терминале и первой датой серии на сервере
|
|
// больше указанного количества баров
|
|
//--- Load / generate data if the size of the array is less than the maximum number of bars in the terminal,
|
|
// as well as between the first date of the series in the terminal and the first date of the series
|
|
// on the server more than the specified number of bars
|
|
while(array_size<on_calc_rates_total &&
|
|
series_firstdate-server_firstdate>PeriodSeconds()*number_bars)
|
|
{
|
|
datetime copied_time[];
|
|
//--- Получим первую дату символа-периода в базе терминала
|
|
// Get the first date of the symbol-period in the terminal base
|
|
SeriesInfoInteger(symbols_names[s],Period(),SERIES_FIRSTDATE,series_firstdate);
|
|
//--- Загрузим/скопируем ещё указанное количество баров
|
|
// Download / copy another specified number of bars
|
|
if(CopyTime(symbols_names[s],Period(),0,array_size+number_bars,copied_time))
|
|
{
|
|
//--- Если время первого бара массива с вычетом кол-ва подгружаемых баров раньше,
|
|
// чем время первого бара на графике, остановим цикл
|
|
// If the time of the first bar of the array minus the number of loaded bars
|
|
// is earlier than the time of the first bar on the chart, we stop the cycle
|
|
if(copied_time[0]-PeriodSeconds()*number_bars<on_calc_time[0])
|
|
break;
|
|
//--- Если размер массива не увеличился, увеличим счётчик
|
|
// If the size of the array has not increased, we will increase the counter
|
|
if(ArraySize(copied_time)==array_size)
|
|
count_try++;
|
|
//--- Иначе получим текущий размер массива
|
|
// Otherwise, we will get the current size of the array
|
|
else
|
|
array_size=ArraySize(copied_time);
|
|
//--- Если размер массива не увеличивается в течении 100 попыток, остановим цикл
|
|
// If the size of the array does not increase within 100 attempts, stop the loop
|
|
if(count_try==100)
|
|
{
|
|
count_try=0;
|
|
break;
|
|
}
|
|
}
|
|
//--- Каждые 2000 баров проверяем размеры подокна
|
|
// и если размер изменился подгоним под него размер канвы
|
|
// Every 2000 bars we check the dimensions of the subwindow
|
|
// and if the size has changed we will fit the size of the canvas
|
|
if(!(array_size%2000))
|
|
EventChartChange();
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Получает хэндлы |
|
|
//+------------------------------------------------------------------+
|
|
bool GetHandles()
|
|
{
|
|
//--- Признак того, что все хэндлы валидны
|
|
bool invalid=true;
|
|
//--- Пройдёмся в цикле по всем символам и ...
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
//--- Если символ есть и ...
|
|
if(symbols_names[s]!=empty_symbol)
|
|
{
|
|
// ...хэндл текущего таймфрейма невалиден, получим его
|
|
if(handle_symbol[s]==INVALID_HANDLE)
|
|
{
|
|
handle_symbol[s]=iATR(symbols_names[s],Period(),IndicatorPeriod);
|
|
//--- Если не удалось получить хэндл
|
|
if(handle_symbol[s]==INVALID_HANDLE)
|
|
invalid=false; // Попробуем в следующий раз
|
|
}
|
|
}
|
|
}
|
|
//--- Выведем сообщение, если хэндл для одного из символов не получен
|
|
// We will display the message if the handle for one of the symbols is not received
|
|
if(!invalid)
|
|
{
|
|
message_last=message_invalid_handle;
|
|
ShowCanvasMessage(message_invalid_handle);
|
|
}
|
|
//---
|
|
return(invalid);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Проверяет количество доступных данных у всех символов |
|
|
//+------------------------------------------------------------------+
|
|
bool CheckAvailableData()
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
//--- Если такой символ есть
|
|
if(symbols_names[s]!=empty_symbol)
|
|
{
|
|
double data[]; // Массив для проверки количества данных индикатора
|
|
datetime time[]; // Массив для проверки количества баров
|
|
int calculated_values =0; // Количество данных индикатора
|
|
int total_period_bars =0; // Количество баров текущего периода
|
|
datetime terminal_first_date =NULL; // Первая дата имеющихся данных текущего периода в терминале
|
|
//--- Получим кол-во рассчитанных значений индикатора
|
|
// Get the number of calculated indicator values
|
|
calculated_values=BarsCalculated(handle_symbol[s]);
|
|
//--- Получим первую дату данных текущего периода в терминале
|
|
// Get the first date of the current period data in the terminal
|
|
terminal_first_date=(datetime)SeriesInfoInteger(symbols_names[s],Period(),SERIES_TERMINAL_FIRSTDATE);
|
|
//--- Получим количество доступных баров от указанной даты
|
|
// Get the number of available bars from the specified date.
|
|
total_period_bars=Bars(symbols_names[s],Period(),terminal_first_date,TimeCurrent());
|
|
//--- Проверим готовность данных баров
|
|
for(int i=0; i<5; i++)
|
|
{
|
|
//--- Скопируем указанное количество данных
|
|
// Copy the specified amount of time data (all between terminal_first_date and TimeCurrent())
|
|
if(CopyTime(symbols_names[s],Period(),0,total_period_bars,time))
|
|
{
|
|
//--- Если скопировалось нужное количество, остановим цикл
|
|
// If the required amount has been copied, stop the cycle
|
|
if(ArraySize(time)>=total_period_bars)
|
|
break;
|
|
}
|
|
}
|
|
//--- Проверим готовность данных индикатора
|
|
for(int i=0; i<5; i++)
|
|
{
|
|
//--- Скопируем указанное количество данных
|
|
// Copy the specified amount of time data (all calculated for the indicator)
|
|
if(CopyBuffer(handle_symbol[s],0,0,calculated_values,data))
|
|
{
|
|
//--- Если скопировалось нужное количество, остановим цикл
|
|
// If the required amount has been copied, stop the cycle
|
|
if(ArraySize(data)>=calculated_values)
|
|
break;
|
|
}
|
|
}
|
|
//--- Если скопировано меньше данных
|
|
// значит нужно совершить ещё одну попытку
|
|
if(ArraySize(time)<total_period_bars || ArraySize(data)<calculated_values)
|
|
{
|
|
message_last=message_data_available;
|
|
ShowCanvasMessage(message_data_available);
|
|
on_calc_prev_calculated=0;
|
|
return(false);
|
|
}
|
|
}
|
|
}
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Проверка события загрузки более глубокой истории |
|
|
//| Check the event of loading a deeper history if there is a symbol |
|
|
//| such that |
|
|
//+------------------------------------------------------------------+
|
|
bool CheckEventLoadHistory()
|
|
{
|
|
bool load=false;
|
|
//---
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
//--- Если такой символ есть
|
|
if(symbols_names[s]!=empty_symbol)
|
|
{
|
|
//--- Если нужно обновить серии
|
|
if(on_calc_prev_calculated==0)
|
|
{
|
|
//--- Получим первую дату символа-периода
|
|
// Get the first date of the period symbol
|
|
series_first_date[s]=(datetime)SeriesInfoInteger(symbols_names[s],Period(),SERIES_FIRSTDATE);
|
|
//--- Если здесь в первый раз (отсутствует значение), то
|
|
if(series_first_date_last[s]==NULL)
|
|
//--- Запомним первую дату символа-периода для последующих сравнений с целью определения загрузки
|
|
// более глубокой истории
|
|
// Remember the first date of the symbol-period for subsequent comparisons to determine the load
|
|
// of a deeper history.
|
|
series_first_date_last[s]=series_first_date[s];
|
|
}
|
|
else
|
|
{
|
|
//--- Получим первую дату символа-периода
|
|
// Get the first date of the period symbol
|
|
series_first_date[s]=(datetime)SeriesInfoInteger(symbols_names[s],Period(),SERIES_FIRSTDATE);
|
|
//--- Если даты отличаются, то есть дата в памяти более поздняя, чем та, которую получили сейчас, то
|
|
// значит была загрузка более глубокой истории
|
|
// If the dates are different, then there is a date in memory later than the one that we received
|
|
// now, then it means that there was a deeper loading
|
|
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 a deeper history has been loaded / formed, then
|
|
// send a command to update the graphic series of the indicator
|
|
if(load)
|
|
return(false);
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Проверяет синхронизированность по символу/периоду |
|
|
//+------------------------------------------------------------------+
|
|
bool CheckSymbolIsSynchronized()
|
|
{
|
|
//--- Если есть соединение с сервером, то проверим синхронизированность данных
|
|
// If there is a connection to the server, then we will check the data synchronization.
|
|
if(TerminalInfoInteger(TERMINAL_CONNECTED))
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
//--- Если символ есть
|
|
if(symbols_names[s]!=empty_symbol)
|
|
{
|
|
//--- Если данные не синхронизированы, то сообщим об этом и попробуем снова
|
|
// If the data is not synchronized, then let us know and try again.
|
|
if(!SeriesInfoInteger(symbols_names[s],Period(),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;
|
|
//--- Получим общее количество баров символа
|
|
// Get the total number of bars of the symbol
|
|
total_period_bars=Bars(symbols_names[s],Period());
|
|
//--- Скопируем массив времени баров. Если не получилось, попробуем ещё раз
|
|
// Copy the array of time bars. If not, try again.
|
|
if(CopyTime(symbols_names[s],Period(),0,total_period_bars,time)<total_period_bars)
|
|
return(false);
|
|
//--- Получим время первого истинного бара, который соответствует текущему таймфрейму
|
|
// Get the time of the first true bar that corresponds to the current timeframe
|
|
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,TimeToString(limit_time[s]),"\n");
|
|
}
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает время первого истинного бара текущего периода |
|
|
//| Returns the time of the first true bar of the current period |
|
|
//+------------------------------------------------------------------+
|
|
datetime GetFirstTruePeriodBarTime(datetime &time[])
|
|
{
|
|
datetime true_period =NULL; // Время первого истинного бара - Time of the first true bar
|
|
int array_size =0; // Размер массива
|
|
//--- Получим размер массива - We will have got the size of the array
|
|
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Подготовка данных перед рисованием |
|
|
//+------------------------------------------------------------------+
|
|
void PreparationData(int i,int symbol_number,datetime const &time[])
|
|
{
|
|
int try
|
|
=100; // Количество попыток копирования
|
|
//--- Время бара указанного символа и тф
|
|
datetime symbol_time[];
|
|
//--- Массив для копирования значения индикатора
|
|
double atr_value[];
|
|
//--- Если в зоне баров текущего таймфрейма
|
|
if(time[i]>=limit_time[symbol_number])
|
|
{
|
|
//--- Скопируем время
|
|
for(int k=0; k<try
|
|
; k++)
|
|
{
|
|
if(CopyTime(symbols_names[symbol_number],0,time[i],1,symbol_time)==1)
|
|
{
|
|
temp_symbol_time[symbol_number].time[i]=symbol_time[0];
|
|
break;
|
|
}
|
|
}
|
|
//--- Скопируем значение индикатора
|
|
for(int k=0; k<try
|
|
; k++)
|
|
{
|
|
if(CopyBuffer(handle_symbol[symbol_number],0,time[i],1,atr_value)==1)
|
|
{
|
|
temp_atr_values[symbol_number].value[i]=atr_value[0];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//--- Если вне зоны баров текущего таймфрейма,
|
|
// установим пустое значение
|
|
else
|
|
temp_atr_values[symbol_number].value[i]=EMPTY_VALUE;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Заполняет индикаторные буферы |
|
|
//+------------------------------------------------------------------+
|
|
void FillIndicatorBuffers(int i,int symbol_number,datetime const &time[])
|
|
{
|
|
//--- Для проверки полученного значения индикатора
|
|
bool check_value=false;
|
|
//--- Счётчик баров текущего таймфрейма
|
|
static int count_current_period=0;
|
|
//--- Обнулим счётчик баров текущего таймфрейма
|
|
// в начале таймсерии символа
|
|
if(i==0)
|
|
count_current_period=0;
|
|
//--- Если в зоне баров текущего таймфрейма и
|
|
// счётчик меньше указанного периода индикатора, то
|
|
// увеличим счётчик
|
|
if(count_current_period<IndicatorPeriod &&
|
|
time[i]>=limit_time[symbol_number])
|
|
count_current_period++;
|
|
//--- Если в зоне индикатора и
|
|
// время текущего символа и время указанного символа совпадают
|
|
if(count_current_period>=IndicatorPeriod &&
|
|
time[i]==temp_symbol_time[symbol_number].time[i])
|
|
{
|
|
//--- Если полученное значение не пустое
|
|
// If the received value is not empty
|
|
if(temp_atr_values[symbol_number].value[i]!=EMPTY_VALUE)
|
|
{
|
|
check_value=true;
|
|
buffer_atr[symbol_number].data[i]=temp_atr_values[symbol_number].value[i];
|
|
}
|
|
}
|
|
//--- Установим пустое значение, если не получилось установить выше
|
|
if(!check_value)
|
|
buffer_atr[symbol_number].data[i]=EMPTY_VALUE;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Добавляет указанный символ в окно обзор рынка |
|
|
//+------------------------------------------------------------------+
|
|
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Установим свойства подокна |
|
|
//+------------------------------------------------------------------+
|
|
void SetSubwindowProperties()
|
|
{
|
|
//--- Получим номер подокна индикатора
|
|
number_subwindow=ChartWindowFind(0,shortname_subwindow);
|
|
//--- Получим ширину и высоту подокна
|
|
chart_width=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);
|
|
subwindow_height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,number_subwindow);
|
|
//--- Получим центр подокна
|
|
subwindow_center=chart_width/2;
|
|
subwindow_vcenter=subwindow_height/2;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Копирует данные из OnCalculate |
|
|
//+------------------------------------------------------------------+
|
|
void CopyDataOnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[])
|
|
{
|
|
on_calc_rates_total=rates_total;
|
|
on_calc_prev_calculated=prev_calculated;
|
|
ArrayCopy(on_calc_time,time);
|
|
ArrayCopy(on_calc_open,open);
|
|
ArrayCopy(on_calc_high,high);
|
|
ArrayCopy(on_calc_low,low);
|
|
ArrayCopy(on_calc_close,close);
|
|
ArrayCopy(on_calc_tick_volume,tick_volume);
|
|
ArrayCopy(on_calc_volume,volume);
|
|
ArrayCopy(on_calc_spread,spread);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Изменяет размер массивов под размер основного массива |
|
|
//+------------------------------------------------------------------+
|
|
void ResizeCalculateArrays()
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
ArrayResize(temp_symbol_time[s].time,on_calc_rates_total);
|
|
ArrayResize(temp_atr_values[s].value,on_calc_rates_total);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Обнуление массивов для подготовки данных |
|
|
//+------------------------------------------------------------------+
|
|
void ZeroCalculateArrays()
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
ArrayInitialize(temp_symbol_time[s].time,NULL);
|
|
ArrayInitialize(temp_atr_values[s].value,EMPTY_VALUE);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Обнуление индикаторных буферов |
|
|
//+------------------------------------------------------------------+
|
|
void ZeroIndicatorBuffers()
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
ArrayInitialize(buffer_atr[s].data,EMPTY_VALUE);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Следит за размерами канвы |
|
|
//+------------------------------------------------------------------+
|
|
void EventChartChange()
|
|
{
|
|
//--- Получим свойства подокна
|
|
SetSubwindowProperties();
|
|
//--- Если размеры подокна не изменились, выйдем
|
|
if(!CheckSubwindowSize())
|
|
return;
|
|
//--- Если размер подокна меньше одного пикселя или
|
|
// центр рассчитан некорректно, выйдем
|
|
if(subwindow_height<1 || subwindow_vcenter<1)
|
|
return;
|
|
//--- Установим новый размер канве
|
|
ResizeCanvas();
|
|
//--- Покажем последнее сообщение
|
|
ShowCanvasMessage(message_last);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Проверим размеры подокна |
|
|
//+------------------------------------------------------------------+
|
|
bool CheckSubwindowSize()
|
|
{
|
|
//--- Если размеры подокна не изменились, выйдем
|
|
if(last_chart_width==chart_width &&
|
|
last_subwindow_height==subwindow_height)
|
|
return(false);
|
|
//--- Если же изменились, то запомним их
|
|
else
|
|
{
|
|
last_chart_width=chart_width;
|
|
last_subwindow_height=subwindow_height;
|
|
}
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Установить канву |
|
|
//+------------------------------------------------------------------+
|
|
void SetCanvas()
|
|
{
|
|
//--- Если канвы нет, установим её
|
|
if(ObjectFind(0,canvas_name)<0)
|
|
{
|
|
//--- Создадим канву
|
|
canvas.CreateBitmapLabel(0,number_subwindow,canvas_name,0,0,chart_width,subwindow_height,clr_format);
|
|
//--- Сделаем канву полностью прозрачной
|
|
canvas.Erase(ColorToARGB(canvas_bg_color,0));
|
|
//--- Обновим канву
|
|
canvas.Update();
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Изменяет размер канвы |
|
|
//+------------------------------------------------------------------+
|
|
void ResizeCanvas()
|
|
{
|
|
//--- Если канва есть в подокне индикатора, установим новый размер
|
|
if(ObjectFind(0,canvas_name)==number_subwindow)
|
|
canvas.Resize(chart_width,subwindow_height);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Выводит сообщение в канве |
|
|
//+------------------------------------------------------------------+
|
|
void ShowCanvasMessage(string message_text)
|
|
{
|
|
SetSubwindowProperties();
|
|
//--- Если канва есть в подокне индикатора
|
|
if(ObjectFind(0,canvas_name)==number_subwindow)
|
|
{
|
|
//--- Отобразим сообщение,
|
|
// если передана не пустая строка и координаты получены
|
|
if(message_text!="" && subwindow_center>0 && subwindow_vcenter>0)
|
|
{
|
|
canvas.Erase(ColorToARGB(canvas_bg_color,canvas_opacity));
|
|
canvas.TextOut(subwindow_center,subwindow_vcenter,message_text,ColorToARGB(clrRed),TA_CENTER|TA_VCENTER);
|
|
canvas.Update();
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Удаляет канву |
|
|
//+------------------------------------------------------------------+
|
|
void DeleteCanvas()
|
|
{
|
|
//--- Удалим канву, если она есть
|
|
if(ObjectFind(0,canvas_name)>0)
|
|
{
|
|
//--- Перед удалением произведём эффект исчезания
|
|
for(int i=canvas_opacity; i>0; i-=5)
|
|
{
|
|
canvas.Erase(ColorToARGB(canvas_bg_color,(uchar)i));
|
|
canvas.Update();
|
|
}
|
|
//--- Удаление канвы
|
|
canvas.Destroy();
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Процент прогресса |
|
|
//+------------------------------------------------------------------+
|
|
void PercentProgress(int i,int symbols_number,double &percent)
|
|
{
|
|
string message_text="";
|
|
percent=(double(i)/on_calc_rates_total)*100;
|
|
//---
|
|
if(percent<=9.99)
|
|
message_text="0"+DoubleToString(percent,0);
|
|
else
|
|
if(percent<99)
|
|
message_text=DoubleToString(percent,0);
|
|
else
|
|
message_text="99";
|
|
//---
|
|
message_last=message_synchro_update="Подготовка данных ("+IntegerToString(on_calc_rates_total)+" баров) : "+
|
|
symbols_names[symbols_number]+
|
|
"("+IntegerToString(symbols_number+1)+"/"+IntegerToString(SYMBOLS)+") - "+message_text+"% ... ";
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Установка уровней |
|
|
//+------------------------------------------------------------------+
|
|
void SetLevels()
|
|
{
|
|
//--- Получим номер подокна индикатора
|
|
number_subwindow=ChartWindowFind(0,shortname_subwindow);
|
|
//--- Установим уровни
|
|
for(int s=0; s<LEVELS; s++)
|
|
CreateHorizontalLines(0,number_subwindow,
|
|
prefix+"level_0"+IntegerToString(s+1)+"",
|
|
CorrectValueBySymbolDigits(levels[s]*_Point),
|
|
1,STYLE_DOT,clrLightSteelBlue,false,false,false,"\n");
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Удаляет уровни |
|
|
//+------------------------------------------------------------------+
|
|
void DeleteLevels()
|
|
{
|
|
for(int i=0; i<LEVELS; i++)
|
|
DeleteObjectByName(prefix+"level_0"+IntegerToString(i+1)+"");
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Удаляет вертикальные линии начала серий |
|
|
//+------------------------------------------------------------------+
|
|
void DeleteVerticalLines()
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
DeleteObjectByName(prefix+symbols_names[s]+": begin time series");
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Удаляет объект по имени |
|
|
//+------------------------------------------------------------------+
|
|
void DeleteObjectByName(string Name)
|
|
{
|
|
//--- Если есть такой объект
|
|
if(ObjectFind(0,Name)>=0)
|
|
{
|
|
//--- Если была ошибка при удалении, сообщим об этом
|
|
if(!ObjectDelete(0,Name))
|
|
Print("Ошибка ("+IntegerToString(GetLastError())+") при удалении объекта!");
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Создание горизонтальной линии |
|
|
//+------------------------------------------------------------------+
|
|
void CreateHorizontalLines(long chart_id, // id графика
|
|
int number_window, // номер окна
|
|
string name_line, // имя объекта
|
|
double price, // уровень цены
|
|
int width_line, // толщина линии
|
|
ENUM_LINE_STYLE style_line, // стиль линии
|
|
color color_line, // цвет линии
|
|
bool selectable, // нельзя выделить объект, если FALSE
|
|
bool select, // выделение
|
|
bool back, // фоновое расположение
|
|
string tooltip) // нет всплывающей подсказки, если "\n"
|
|
{
|
|
//--- Если объект успешно создан...
|
|
if(ObjectCreate(chart_id,name_line,OBJ_HLINE,number_window,0,price))
|
|
{
|
|
// ...установим ему свойства
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_SELECTABLE,selectable);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_SELECTED,select);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_BACK,back);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_STYLE,style_line);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_WIDTH,width_line);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_COLOR,color_line);
|
|
ObjectSetString(chart_id,name_line,OBJPROP_TOOLTIP,tooltip);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Создание вертикальной линии |
|
|
//+------------------------------------------------------------------+
|
|
void CreateVerticalLines(long chart_id, // id графика
|
|
int number_window, // номер окна
|
|
datetime time, // время
|
|
string name_line, // имя объекта
|
|
int width_line, // толщина линии
|
|
ENUM_LINE_STYLE style_line, // стиль линии
|
|
color color_line, // цвет линии
|
|
bool selectable, // нельзя выделить объект, если FALSE
|
|
string description_text, // текст описания
|
|
string tooltip) // нет всплывающей подсказки, если "\n"
|
|
{
|
|
//--- Если объект успешно создан...
|
|
if(ObjectCreate(chart_id,name_line,OBJ_VLINE,number_window,time,0))
|
|
{
|
|
// ...установим ему свойства
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_TIME,time);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_SELECTABLE,selectable);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_STYLE,style_line);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_WIDTH,width_line);
|
|
ObjectSetInteger(chart_id,name_line,OBJPROP_COLOR,color_line);
|
|
ObjectSetString(chart_id,name_line,OBJPROP_TEXT,description_text);
|
|
ObjectSetString(chart_id,name_line,OBJPROP_TOOLTIP,tooltip);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Коррекция значения по количеству знаков в цене (double) |
|
|
//+------------------------------------------------------------------+
|
|
double CorrectValueBySymbolDigits(double value)
|
|
{
|
|
return(_Digits==3 || _Digits==5) ? value*=10 : value;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Преобразует таймфрейм в строку |
|
|
//+------------------------------------------------------------------+
|
|
string TimeframeToString(ENUM_TIMEFRAMES timeframe)
|
|
{
|
|
string str="";
|
|
//--- Если переданное значение некорректно, берем таймфрейм текущего графика
|
|
if(timeframe==WRONG_VALUE || timeframe== NULL)
|
|
timeframe= Period();
|
|
switch(timeframe)
|
|
{
|
|
case PERIOD_M1 :
|
|
str="M1";
|
|
break;
|
|
case PERIOD_M2 :
|
|
str="M2";
|
|
break;
|
|
case PERIOD_M3 :
|
|
str="M3";
|
|
break;
|
|
case PERIOD_M4 :
|
|
str="M4";
|
|
break;
|
|
case PERIOD_M5 :
|
|
str="M5";
|
|
break;
|
|
case PERIOD_M6 :
|
|
str="M6";
|
|
break;
|
|
case PERIOD_M10 :
|
|
str="M10";
|
|
break;
|
|
case PERIOD_M12 :
|
|
str="M12";
|
|
break;
|
|
case PERIOD_M15 :
|
|
str="M15";
|
|
break;
|
|
case PERIOD_M20 :
|
|
str="M20";
|
|
break;
|
|
case PERIOD_M30 :
|
|
str="M30";
|
|
break;
|
|
case PERIOD_H1 :
|
|
str="H1";
|
|
break;
|
|
case PERIOD_H2 :
|
|
str="H2";
|
|
break;
|
|
case PERIOD_H3 :
|
|
str="H3";
|
|
break;
|
|
case PERIOD_H4 :
|
|
str="H4";
|
|
break;
|
|
case PERIOD_H6 :
|
|
str="H6";
|
|
break;
|
|
case PERIOD_H8 :
|
|
str="H8";
|
|
break;
|
|
case PERIOD_H12 :
|
|
str="H12";
|
|
break;
|
|
case PERIOD_D1 :
|
|
str="D1";
|
|
break;
|
|
case PERIOD_W1 :
|
|
str="W1";
|
|
break;
|
|
case PERIOD_MN1 :
|
|
str="MN1";
|
|
break;
|
|
}
|
|
//---
|
|
return(str);
|
|
}
|
|
//+------------------------------------------------------------------+
|