797 lines
71 KiB
MQL5
797 lines
71 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| MultiSymbolPriceDivergence.mq5 |
|
|
//| Copyright 2013, https://login.mql5.com/ru/users/tol64 |
|
|
//| Site, http://tol64.blogspot.com |
|
|
//+------------------------------------------------------------------+
|
|
//--- Свойства индикатора
|
|
#property copyright "Copyright 2013, http://tol64.blogspot.com"
|
|
#property link "http://tol64.blogspot.com/2013/06/218.html"
|
|
#property description "email: hello.tol64@gmail.com"
|
|
#property version "1.0"
|
|
//---
|
|
#property indicator_chart_window // Выводить индикатор в окно графика
|
|
#property indicator_buffers 25 // Количество буферов для расчёта индикатора
|
|
#property indicator_plots 5 // Количество графических серий
|
|
//--- Цвета цветовых буферов
|
|
#property indicator_color1 clrDodgerBlue,C'0,50,100'
|
|
#property indicator_color2 clrMagenta,C'130,0,130'
|
|
#property indicator_color3 clrGold,C'160,140,0'
|
|
#property indicator_color4 clrAqua,C'0,140,140'
|
|
#property indicator_color5 clrLimeGreen,C'20,80,20'
|
|
|
|
//--- Константа для возврата терминалу команды на пересчёт индикатора
|
|
#define RESET 0
|
|
//--- Количество символов
|
|
#define SYMBOLS 5
|
|
//--- Имя программы
|
|
#define PROGRAM_NAME MQL5InfoString(MQL5_PROGRAM_NAME)
|
|
|
|
//--- Подключим класс для работы с канвой
|
|
#include <Canvas\Canvas.mqh>
|
|
//--- Подключаем свои библиотеки
|
|
#include <MultiSymbol/Checks.mqh>
|
|
#include <MultiSymbol/SettingChart.mqh>
|
|
#include <MultiSymbol/SetDeleteObjects.mqh>
|
|
//--- Тип рисования данных
|
|
enum ENUM_DRAWTYPE
|
|
{
|
|
LINES =0, // Lines
|
|
BARS =1, // Bars
|
|
CANDLES =2 // Candles
|
|
};
|
|
//--- Режим начальной точки расхождения цен
|
|
enum ENUM_START_POINT
|
|
{
|
|
VERT_LINE =0, // Vertical Line
|
|
MONTH =1, // Month
|
|
WEEK =2, // Week
|
|
DAY =3, // Day
|
|
HOUR =4 // Hour
|
|
};
|
|
//--- Внешние параметры
|
|
input ENUM_DRAWTYPE DrawType =CANDLES; // Draw Type
|
|
input ENUM_START_POINT StartPriceDivergence =VERT_LINE; // Start Price Divergence
|
|
input bool TwoColor =false; // Two Colored Bars/Candles
|
|
sinput string dlm01=""; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
input string Symbol02 ="EURUSD"; // Symbol 02
|
|
input bool Inverse02 =false; // Inverse Symbol 02
|
|
input string Symbol03 ="GBPUSD"; // Symbol 03
|
|
input bool Inverse03 =false; // Inverse Symbol 03
|
|
input string Symbol04 ="EURGBP"; // Symbol 04
|
|
input bool Inverse04 =false; // Inverse Symbol 04
|
|
input string Symbol05 ="USDCAD"; // Symbol 05
|
|
input bool Inverse05 =false; // Inverse Symbol 05
|
|
input string Symbol06 ="USDCHF"; // Symbol 06
|
|
input bool Inverse06 =false; // Inverse Symbol 06
|
|
//--- Структура массивов индикаторных буферов
|
|
struct buffers
|
|
{
|
|
double open[]; // Буфер для цен открытия
|
|
double high[]; // Буфер для цен максимумов
|
|
double low[]; // Буфер для цен минимумов
|
|
double close[]; // Буфер для цен закрытия
|
|
double icolor[]; // Буфер для определения цвета элемента
|
|
};
|
|
buffers buffer_data[SYMBOLS];
|
|
//--- Загрузка класса
|
|
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[]; // Спред
|
|
|
|
//--- Для хранения и проверки времени первого бара в терминале
|
|
datetime series_first_date[SYMBOLS];
|
|
datetime series_first_date_last[SYMBOLS];
|
|
//--- Массив времени бара, от которого начинать отрисовку
|
|
datetime limit_time[SYMBOLS];
|
|
//--- Массив названий символов
|
|
string symbols_names[SYMBOLS];
|
|
//--- Массив названий символов
|
|
bool inverse[SYMBOLS];
|
|
//--- Цвета линий индикатора
|
|
color line_color[SYMBOLS]=
|
|
{clrDodgerBlue,clrLimeGreen,clrGold,clrAqua,clrMagenta};
|
|
//--- Строка символизирующая отсутствие символа
|
|
string empty_symbol="EMPTY";
|
|
//--- Свойства графика
|
|
int number_window =WRONG_VALUE; // Номер окна индикатора
|
|
int chart_width =0; // Ширина графика
|
|
int chart_height =0; // Высота графика
|
|
int last_chart_width =0; // Последняя в памяти ширина графика
|
|
int last_chart_height =0; // Последняя в памяти высота графика
|
|
int chart_wcenter =0; // Центр графика по горизонтали
|
|
int chart_vcenter =0; // Центр графика по вертикали
|
|
color color_bar_up =clrRed; // Цвет бара вверх
|
|
color color_bar_down =C'100,0,0'; // Цвет бара вниз
|
|
string shortname_indicator ="MS_PriceDivergence"; // Короткое имя индикатора
|
|
string prefix =shortname_indicator+"_"; // Префикс для объектов
|
|
//--- Имя вертикальной линии начальной точки расхождения цен
|
|
string start_price_divergence=prefix+"start_price_divergence";
|
|
//--- Свойства канвы
|
|
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_data_available ="Подготовка данных! Подождите пожалуйста...";
|
|
string message_is_synchronized ="Данные не синхронизированы! Подождите пожалуйста...";
|
|
string message_formation_data ="";
|
|
string message_data_update ="";
|
|
string message_last ="";
|
|
//---
|
|
ENUM_TIMEFRAMES timeframe_start_point =Period(); // Таймфрейм для точки расхождения цен
|
|
datetime first_period_time =NULL; // Время первого указанного периода данных на графике
|
|
double level_divergence =0.0; // Цена начальной точки расхождения цен
|
|
datetime time_divergence =NULL; // Время начальной точки расхождения цен
|
|
double symbol_difference[SYMBOLS]; // Разница в цене относительно текущего символа
|
|
double inverse_difference[SYMBOLS]; // Разница, которая образуется при расчёте инверсии
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Проверим, не используется ли сейчас индикатор в тестере
|
|
if(!CheckTesterMode())
|
|
return(INIT_FAILED);
|
|
//--- Установим цвет барам/свечам
|
|
SetBarColors();
|
|
//--- Определим период для начальной точки расхождения цен
|
|
// Define the period for the starting point of price divergence.
|
|
InitModeStartPriceDivergence();
|
|
//--- Проверим корректность входных параметров
|
|
// Check the correctness of the input parameters
|
|
if(!CheckInputParameters())
|
|
return(INIT_PARAMETERS_INCORRECT);
|
|
//--- Включим таймер с интервалом 1 секунда
|
|
EventSetMillisecondTimer(1000);
|
|
//--- Установим шрифт для отображения в канве
|
|
canvas.FontSet(font_name,font_size,FW_NORMAL);
|
|
//--- Инициализация массивов
|
|
InitArrays();
|
|
//--- Инициализируем массив символов
|
|
InitSymbolsNames();
|
|
//--- Инициализируем массив инверсий
|
|
InitInverse();
|
|
//--- Установим свойства индикатора
|
|
SetPropertiesIndicator();
|
|
//--- Установим вертикальную линию начала расхождения цен
|
|
SetLineStartPricesDivergence();
|
|
//--- Очистим комментарий
|
|
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();
|
|
//--- Удалим вертикальные линии
|
|
DeleteVerticalLines();
|
|
//--- Удалим канву
|
|
DeleteCanvas();
|
|
//--- Отключим масштабирование
|
|
ChartSetInteger(0,CHART_SCALEFIX,false);
|
|
//--- Очистим комментарий
|
|
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[]) // Спред
|
|
{
|
|
//--- Для определения, с какого бара производить расчёт
|
|
int limit=0;
|
|
//--- Сделаем копию параметров OnCalculate()
|
|
CopyDataOnCalculate(rates_total,prev_calculated,
|
|
time,open,high,low,close,
|
|
tick_volume,volume,spread);
|
|
//--- Если это первый расчёт или загружена более глубокая история или были заполнены пропуски истории
|
|
// If this is the first calculation or a deeper history has been loaded or the history gaps have been filled
|
|
if(prev_calculated==0)
|
|
{
|
|
//--- Обнулим индикаторные буферы - Zero indicator buffers
|
|
ZeroIndicatorBuffers();
|
|
//--- Получим свойства подокна - Get the properties of the subwindow
|
|
SetSubwindowProperties();
|
|
//--- Установим канву - Install the canvas
|
|
SetCanvas();
|
|
//--- Загрузим и сформируем необходимое/имеющееся количество данных
|
|
// Load and generate the necessary / available amount of data.
|
|
LoadFormationData();
|
|
LoadFormationDataHighTF();
|
|
//--- Проверяет количество доступных данных у всех символов
|
|
// Checks the amount of data available for all symbols.
|
|
if(!CheckAvailableData())
|
|
return(RESET);
|
|
//--- Если загружена более глубокая история
|
|
// If a deeper hisstory is loaded
|
|
if(!CheckEventLoadHistory())
|
|
return(RESET);
|
|
//--- Проверим синхронизированность данных по символу/периоду на данный момент
|
|
// Check the synchronization of data on the symbol / period at the moment
|
|
if(!CheckSymbolIsSynchronized())
|
|
return(RESET);
|
|
//--- Определим для каждого символа, с какого бара начинать отрисовку
|
|
// For each symbol find the bar at which to start drawing
|
|
if(!DetermineBeginForCalculate())
|
|
return(RESET);
|
|
//--- Если дошли до этого момента, то значит OnCalculate() вернёт ненулевое значение
|
|
// и это нужно запомнить. Reaching this point means OnCalculate() returned nonzero.
|
|
on_calc_prev_calculated=rates_total;
|
|
}
|
|
//--- Если нужно пересчитать только последние значения
|
|
// If you only need to recalculate the last
|
|
else
|
|
limit=prev_calculated-1;
|
|
|
|
//--- Заполним индикаторные буферы - Fill indicator buffers
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
//--- Если такой символ есть, то - If this symbol exists then
|
|
if(symbols_names[s]!=empty_symbol)
|
|
{
|
|
//--- Сформируем и выведем сообщение - Form and display a message
|
|
message_last=message_data_update="Обновление данных индикатора: "+
|
|
symbols_names[s]+"("+IntegerToString(s+1)+"/"+IntegerToString(SYMBOLS)+") ... ";
|
|
ShowCanvasMessage(message_data_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 size of the window and if the size has changed
|
|
// we will adapt the size of the canvas
|
|
if(!(i%2000))
|
|
EventChartChange();
|
|
}
|
|
}
|
|
}
|
|
//--- Сорректируем максимум и минимум графика
|
|
CorrectMaximumMinimumChart();
|
|
//--- Удалим канву
|
|
DeleteCanvas();
|
|
//--- Обнулим переменные сообщений
|
|
message_last="";
|
|
message_data_update="";
|
|
//--- Обновим график
|
|
ChartRedraw();
|
|
//--- Вернём размер массива данных текущего символа
|
|
return(rates_total);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| ChartEvent function |
|
|
//+------------------------------------------------------------------+
|
|
void OnChartEvent(const int id,
|
|
const long &lparam,
|
|
const double &dparam,
|
|
const string &sparam)
|
|
{
|
|
//--- Событие перетаскивания графического объекта
|
|
if(id==CHARTEVENT_OBJECT_DRAG)
|
|
{
|
|
//--- Если сейчас режим вертикальной линии для начальной точки расхождения цен,
|
|
// обновим индикаторные буферы
|
|
if(StartPriceDivergence==VERT_LINE)
|
|
OnCalculate(on_calc_rates_total,0,
|
|
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);
|
|
}
|
|
//--- Изменение размеров графика или изменение свойств графика через диалог свойств
|
|
if(id==CHARTEVENT_CHART_CHANGE)
|
|
//--- Скорректируем максимум и минимум графика
|
|
// относительно значений в индикаторных буферах
|
|
CorrectMaximumMinimumChart();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Timer function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer()
|
|
{
|
|
//--- Проверка пустых значений
|
|
if(!CheckEmptyValues())
|
|
on_calc_prev_calculated=0;
|
|
//--- Если была загружена более глубокая история
|
|
if(!CheckEventLoadHistory())
|
|
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);
|
|
|
|
//--- Проверка значений в индикаторных буферах
|
|
//CheckLastEmptyValues(10);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает свойства индикатора |
|
|
//+------------------------------------------------------------------+
|
|
void SetPropertiesIndicator()
|
|
{
|
|
//--- Установим короткое имя
|
|
IndicatorSetString(INDICATOR_SHORTNAME,shortname_indicator);
|
|
//--- Установим количество знаков
|
|
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
|
|
//--- Определим буферы для отрисовки
|
|
// В режиме линия нужен только один буфер отображающий цену открытия
|
|
if(DrawType==LINES)
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
SetIndexBuffer(s,buffer_data[s].close,INDICATOR_DATA);
|
|
}
|
|
//--- В других режимах используем все цены для построения
|
|
// баров/свеч и дополнительный буфер для двухцветного режима
|
|
else if(DrawType==BARS || DrawType==CANDLES)
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
static int number_buffer=0;
|
|
SetIndexBuffer(number_buffer,buffer_data[s].open,INDICATOR_DATA);
|
|
number_buffer++;
|
|
SetIndexBuffer(number_buffer,buffer_data[s].high,INDICATOR_DATA);
|
|
number_buffer++;
|
|
SetIndexBuffer(number_buffer,buffer_data[s].low,INDICATOR_DATA);
|
|
number_buffer++;
|
|
SetIndexBuffer(number_buffer,buffer_data[s].close,INDICATOR_DATA);
|
|
number_buffer++;
|
|
SetIndexBuffer(number_buffer,buffer_data[s].icolor,INDICATOR_COLOR_INDEX);
|
|
number_buffer++;
|
|
}
|
|
}
|
|
//--- Установим метки для текущего таймфрейма
|
|
// В режиме линия только цена открытия
|
|
if(DrawType==LINES)
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetString(s,PLOT_LABEL,symbols_names[s]+",Close");
|
|
}
|
|
//--- В других режимах все цены баров/свеч
|
|
// В качестве разделителя используется ";"
|
|
else if(DrawType==BARS || DrawType==CANDLES)
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
PlotIndexSetString(s,PLOT_LABEL,
|
|
symbols_names[s]+",Open;"+
|
|
symbols_names[s]+",High;"+
|
|
symbols_names[s]+",Low;"+
|
|
symbols_names[s]+",Close");
|
|
}
|
|
}
|
|
//--- Установим тип линий для индикаторных буферов
|
|
// Линия
|
|
if(DrawType==LINES)
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_LINE);
|
|
//--- Бары
|
|
if(DrawType==BARS)
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_COLOR_BARS);
|
|
//--- Свечи
|
|
if(DrawType==CANDLES)
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_COLOR_CANDLES);
|
|
|
|
//--- Установим тип линий для данных текущего символа
|
|
// Линия
|
|
if(DrawType==LINES)
|
|
ChartSetInteger(0,CHART_MODE,CHART_LINE);
|
|
//--- Бары
|
|
if(DrawType==BARS)
|
|
ChartSetInteger(0,CHART_MODE,CHART_BARS);
|
|
//--- Свечи
|
|
if(DrawType==CANDLES)
|
|
ChartSetInteger(0,CHART_MODE,CHART_CANDLES);
|
|
|
|
//--- Установим толщину линий
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetInteger(s,PLOT_LINE_WIDTH,1);
|
|
//--- Установим цвет линий для режима Линия
|
|
if(DrawType==LINES)
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetInteger(s,PLOT_LINE_COLOR,line_color[s]);
|
|
//--- Установим показ данных в Окне Данных только существующих символов
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
if(symbols_names[s]!=empty_symbol)
|
|
PlotIndexSetInteger(s,PLOT_SHOW_DATA,true);
|
|
else
|
|
PlotIndexSetInteger(s,PLOT_SHOW_DATA,false);
|
|
}
|
|
//--- Пустое значение для построения, для которого нет отрисовки
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
PlotIndexSetDouble(s,PLOT_EMPTY_VALUE,EMPTY_VALUE);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Первая инициализация массивов |
|
|
//+------------------------------------------------------------------+
|
|
void InitArrays()
|
|
{
|
|
ArrayInitialize(limit_time,NULL);
|
|
ArrayInitialize(symbol_difference,0.0);
|
|
ArrayInitialize(inverse_difference,0.0);
|
|
ArrayInitialize(series_first_date,NULL);
|
|
ArrayInitialize(series_first_date_last,NULL);
|
|
//---
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
ArrayInitialize(buffer_data[s].open,EMPTY_VALUE);
|
|
ArrayInitialize(buffer_data[s].high,EMPTY_VALUE);
|
|
ArrayInitialize(buffer_data[s].low,EMPTY_VALUE);
|
|
ArrayInitialize(buffer_data[s].close,EMPTY_VALUE);
|
|
ArrayInitialize(buffer_data[s].icolor,EMPTY_VALUE);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Инициализирует массив символов |
|
|
//+------------------------------------------------------------------+
|
|
void InitSymbolsNames()
|
|
{
|
|
symbols_names[0]=CheckGetSymbol(Symbol02);
|
|
symbols_names[1]=CheckGetSymbol(Symbol03);
|
|
symbols_names[2]=CheckGetSymbol(Symbol04);
|
|
symbols_names[3]=CheckGetSymbol(Symbol05);
|
|
symbols_names[4]=CheckGetSymbol(Symbol06);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Инициализирует массив инверсий |
|
|
//+------------------------------------------------------------------+
|
|
void InitInverse()
|
|
{
|
|
inverse[0]=Inverse02;
|
|
inverse[1]=Inverse03;
|
|
inverse[2]=Inverse04;
|
|
inverse[3]=Inverse05;
|
|
inverse[4]=Inverse06;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Определяет таймфрейм для режима начальной точки цен |
|
|
//+------------------------------------------------------------------+
|
|
void InitModeStartPriceDivergence()
|
|
{
|
|
//--- Если режим вертикальной линии, выйдем
|
|
if(StartPriceDivergence==VERT_LINE)
|
|
return;
|
|
//--- Иначе определим период
|
|
switch(StartPriceDivergence)
|
|
{
|
|
case MONTH : timeframe_start_point=PERIOD_MN1; break;
|
|
case WEEK : timeframe_start_point=PERIOD_W1; break;
|
|
case DAY : timeframe_start_point=PERIOD_D1; break;
|
|
case HOUR : timeframe_start_point=PERIOD_H1; break;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Заполняет индикаторные буферы |
|
|
//+------------------------------------------------------------------+
|
|
void FillIndicatorBuffers(int i,int s,datetime const &time[])
|
|
{
|
|
MqlRates rates[]; // Структура данных
|
|
double period_open[]; // Цена открытия бара в начале периода расхождения цен
|
|
datetime period_time[]; // Время начала периода расхождения цен
|
|
int try =100; // Количество попыток копирования
|
|
datetime high_tf_time =NULL; // Время бара старшего таймфрейма
|
|
|
|
//--- Если находимся вне зоны "истинных" баров символа, выйдем
|
|
// When we find ourselves outside the zone of "true" bars of the symbol, we'll exit
|
|
if(time[i]<limit_time[s])
|
|
return;
|
|
//--- Сбросим последнюю ошибку
|
|
ResetLastError();
|
|
//--- Получим данные текущего бара указанного символа
|
|
// Get the data of the current bar of the specified symbol
|
|
for(int j=0; j<try; j++)
|
|
if(CopyRates(symbols_names[s],Period(),time[i],1,rates)==1)
|
|
{ ResetLastError(); break; }
|
|
//--- Если неудалось получить данные, выйдем
|
|
// When failing to get the data, we’ll exit
|
|
if(ArraySize(rates)<1 || GetLastError()!=0)
|
|
return;
|
|
//--- Если время бара текущего символа на графике неравно времени бара указанного символа, выйдем
|
|
// If the bar time of the current symbol on the chart is not equal to the bar time of the specified symbol,
|
|
// we’ll exit
|
|
if(time[i]!=rates[0].time)
|
|
return;
|
|
//--- Если в режиме вертикальной линии для начальной точки расхождения цен
|
|
// When in vertical line mode for the starting point of the divergence of prices
|
|
if(StartPriceDivergence==VERT_LINE)
|
|
{
|
|
//--- Получим время линии
|
|
time_divergence=(datetime)ObjectGetInteger(0,start_price_divergence,OBJPROP_TIME);
|
|
//--- Получим время первого бара
|
|
first_period_time=time[0];
|
|
}
|
|
//--- Если в других режимах, то будем отслеживать начало периода
|
|
// When in friend mode, then we will retrace the start of the period
|
|
else
|
|
{
|
|
//--- Если зашли сюда в первый раз, то запомним данные первого бара старшего таймфрейма
|
|
// If we passed this part for the first time then we will remember the data of the first bar
|
|
// of the higher timeframe
|
|
if(time_divergence==NULL)
|
|
{
|
|
ResetLastError();
|
|
//--- Получим время открытия первого бара старшего таймфрейма
|
|
// Get the opening time of the first bar of the higher timeframe
|
|
for(int j=0; j<try; j++)
|
|
if(CopyTime(Symbol(),timeframe_start_point,time[0]+PeriodSeconds(timeframe_start_point),1,period_time)==1)
|
|
{ ResetLastError(); break; }
|
|
//--- Если не удалось получить цену/время, выйдем
|
|
// If you did not succeed getting the price / time, we will leave
|
|
if(ArraySize(period_time)<1 || GetLastError()!=0)
|
|
return;
|
|
//--- Иначе запомним время первого бара старшего таймфрейма
|
|
// Otherwise we remember the time of the first bar of the higher timeframe
|
|
else
|
|
first_period_time=period_time[0];
|
|
}
|
|
//--- Если время текущего бара на текущем таймфрейме
|
|
// раньше, чем время первого бара старшего таймфрейма
|
|
if(time[i]<first_period_time)
|
|
high_tf_time=first_period_time;
|
|
//--- Иначе будем получать данные последнего бара старшего таймфрейма
|
|
// относительно текущего бара текущего таймфрейма
|
|
else
|
|
high_tf_time=time[i];
|
|
//--- Обнулим последнюю ошибку
|
|
ResetLastError();
|
|
//--- Получим цену открытия первого бара старшего таймфрейма
|
|
for(int j=0; j<try; j++)
|
|
if(CopyOpen(Symbol(),timeframe_start_point,high_tf_time,1,period_open)==1)
|
|
{ ResetLastError(); break; }
|
|
//--- Получим время открытия первого бара старшего таймфрейма
|
|
for(int j=0; j<try; j++)
|
|
if(CopyTime(Symbol(),timeframe_start_point,high_tf_time,1,period_time)==1)
|
|
{ ResetLastError(); break; }
|
|
//--- Если не удалось получить цену/время, выйдем
|
|
if(ArraySize(period_open)<1 || ArraySize(period_time)<1 || GetLastError()!=0)
|
|
return;
|
|
//--- Если время текущего таймфрейма раньше, чем время начала первого периода или
|
|
// время указанного периода неравно тому, что в памяти
|
|
if(time[i]<first_period_time || time_divergence!=period_time[0])
|
|
{
|
|
symbol_difference[s] =0.0; // Обнулим разницу цен символов
|
|
inverse_difference[s] =0.0; // Обнулим разницу инверсии
|
|
//--- Запомним время начала расхождения цен
|
|
time_divergence=period_time[0];
|
|
//--- Запомним уровень начала расхождения цен
|
|
level_divergence=period_open[0];
|
|
//--- Установим вертикальную линию в начале периода расхождения цен
|
|
CreateVerticalLines(0,0,period_time[0],start_price_divergence+"_"+TimeToString(time_divergence),
|
|
2,STYLE_SOLID,clrWhite,false,false,true,TimeToString(time_divergence),"\n");
|
|
}
|
|
}
|
|
//--- Если в режиме вертикальной линии и
|
|
// время бара раньше, чем время линии
|
|
if(StartPriceDivergence==VERT_LINE && time[i]<time_divergence)
|
|
{
|
|
//--- Держим нулевые значения разницы
|
|
symbol_difference[s] =0.0;
|
|
inverse_difference[s] =0.0;
|
|
//--- Используем реальные значения символа
|
|
buffer_data[s].low[i] =rates[0].low;
|
|
buffer_data[s].open[i] =rates[0].open;
|
|
buffer_data[s].high[i] =rates[0].high;
|
|
buffer_data[s].close[i] =rates[0].close;
|
|
//--- Установим цвет текущему элементу индикаторного буфера
|
|
SetColorsIndicatorSeries(i,s,rates[0].close,rates[0].open);
|
|
}
|
|
//--- Если в других режимах
|
|
else
|
|
{
|
|
//--- Если нужна инверсия данных символа
|
|
if(inverse[s])
|
|
{
|
|
//--- Если начался новый период, пересчитаем переменные для расчёта
|
|
if(symbol_difference[s]==0.0)
|
|
{
|
|
//--- Если режим вертикальной линии
|
|
if(StartPriceDivergence==VERT_LINE)
|
|
{
|
|
//--- Рассчитаем разницу
|
|
symbol_difference[s] =rates[0].open-on_calc_open[i];
|
|
inverse_difference[s] =on_calc_open[i]-(-on_calc_open[i]);
|
|
}
|
|
//--- Для других режимов
|
|
else
|
|
{
|
|
//--- Рассчитаем разницу
|
|
symbol_difference[s] =rates[0].open-level_divergence;
|
|
inverse_difference[s] =level_divergence-(-level_divergence);
|
|
}
|
|
}
|
|
//--- Для режима Линия только цена закрытия
|
|
if(DrawType==LINES)
|
|
buffer_data[s].close[i]=-(rates[0].close-symbol_difference[s])+inverse_difference[s];
|
|
//--- Для других режимов все цены
|
|
else
|
|
{
|
|
buffer_data[s].low[i] =-(rates[0].low-symbol_difference[s])+inverse_difference[s];
|
|
buffer_data[s].open[i] =-(rates[0].open-symbol_difference[s])+inverse_difference[s];
|
|
buffer_data[s].high[i] =-(rates[0].high-symbol_difference[s])+inverse_difference[s];
|
|
buffer_data[s].close[i] =-(rates[0].close-symbol_difference[s])+inverse_difference[s];
|
|
//--- Установим цвет текущему элементу индикаторного буфера
|
|
SetColorsIndicatorSeries(i,s,rates[0].close,rates[0].open);
|
|
}
|
|
}
|
|
//--- Если без инверсии, то в начале периода
|
|
// нужно вычитать только разницу между ценами символов
|
|
else
|
|
{
|
|
//--- Если начался новый период
|
|
if(symbol_difference[s]==0.0)
|
|
{
|
|
//--- Если режим вертикальной линии
|
|
if(StartPriceDivergence==VERT_LINE)
|
|
symbol_difference[s]=rates[0].open-on_calc_open[i];
|
|
//--- Для других режимов
|
|
else
|
|
symbol_difference[s]=rates[0].open-level_divergence;
|
|
}
|
|
//--- Для режима отрисовки Линия только цена открытия
|
|
if(DrawType==LINES)
|
|
buffer_data[s].close[i]=rates[0].close-symbol_difference[s];
|
|
//--- Для других режимов отрисовки все цены
|
|
else
|
|
{
|
|
buffer_data[s].low[i] =rates[0].low-symbol_difference[s];
|
|
buffer_data[s].open[i] =rates[0].open-symbol_difference[s];
|
|
buffer_data[s].high[i] =rates[0].high-symbol_difference[s];
|
|
buffer_data[s].close[i] =rates[0].close-symbol_difference[s];
|
|
//--- Установим цвет текущему элементу индикаторного буфера
|
|
SetColorsIndicatorSeries(i,s,rates[0].close,rates[0].open);
|
|
}
|
|
}
|
|
}
|
|
//--- Контрольная проверка рассчитанных значений
|
|
// Для режима Линия только цена открытия
|
|
if(DrawType==LINES)
|
|
{
|
|
//--- Если текущее время раньше, чем время первого периода или
|
|
// время бара неравно времени бара текущего символа, запишем пустое значение
|
|
if(time[i]!=rates[0].time || time[i]<first_period_time)
|
|
buffer_data[s].close[i]=EMPTY_VALUE;
|
|
}
|
|
//--- Для других режимов все цены
|
|
else
|
|
{
|
|
//--- Если текущее время раньше, чем время первого периода или
|
|
// время бара неравно времени бара текущего символа
|
|
if(time[i]!=rates[0].time || time[i]<first_period_time)
|
|
{
|
|
//--- Запишем пустое значение
|
|
buffer_data[s].low[i] =EMPTY_VALUE;
|
|
buffer_data[s].open[i] =EMPTY_VALUE;
|
|
buffer_data[s].high[i] =EMPTY_VALUE;
|
|
buffer_data[s].close[i] =EMPTY_VALUE;
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает цвет элементу буфера по условию |
|
|
//+------------------------------------------------------------------+
|
|
void SetColorsIndicatorSeries(int i,int symbol_number,double close,double open)
|
|
{
|
|
//--- Если включен двухцветный режим, проверим условие
|
|
if(TwoColor)
|
|
{
|
|
//--- Если цена закрытия больше цены открытия, то
|
|
// это бар вверх и используем первый цвет
|
|
if(close>open)
|
|
buffer_data[symbol_number].icolor[i]=0;
|
|
//--- иначе это бар вниз и используем второй цвет
|
|
else
|
|
buffer_data[symbol_number].icolor[i]=1;
|
|
}
|
|
//--- Если одноцветный режим, то используем для всех баров/свечей первый цвет
|
|
else
|
|
buffer_data[symbol_number].icolor[i]=0;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Копирует данные из 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 ZeroIndicatorBuffers()
|
|
{
|
|
for(int s=0; s<SYMBOLS; s++)
|
|
{
|
|
ArrayInitialize(buffer_data[s].open,EMPTY_VALUE);
|
|
ArrayInitialize(buffer_data[s].high,EMPTY_VALUE);
|
|
ArrayInitialize(buffer_data[s].low,EMPTY_VALUE);
|
|
ArrayInitialize(buffer_data[s].close,EMPTY_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);
|
|
}
|
|
//+------------------------------------------------------------------+
|