//+------------------------------------------------------------------+ //| TestMSTFDeMarker.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 2 #property indicator_plots 2 //--- enums //--- plot DeM1 #property indicator_label1 "DeM1" #property indicator_type1 DRAW_LINE #property indicator_color1 clrSeaGreen #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot DeM2 #property indicator_label2 "DeM2" #property indicator_type2 DRAW_LINE #property indicator_color2 clrDodgerBlue #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- includes #include "IndMSTF.mqh" #include "Dashboard.mqh" //--- input parameters input string InpSymbol = NULL; /* Symbol */ // Символ input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; /* Timeframe */ // Таймфрейм input int InpPeriod = 14; /* Period */ // Период расчёта input uchar InpLineWidth1 = 2; /* Senior period Line Width */ // Толщина линии для старшего периода input uchar InpLineWidth2 = 1; /* Junior period Line Width */ // Толщина линии для младшего периода input bool InpAsSeries = true; /* As Series flag */ // Флаг серийности массивов буферов индикатора //--- indicator buffers double BufferDeM1[]; double BufferDeM2[]; //--- global variables int handle_dem1; int handle_dem2; CMSTFIndicators indicators; // Экземпляр объекта коллекции индикаторов //--- переменные для панели CDashboard *panel=NULL; // Указатель на объект панели int mouse_bar_index; // Индекс бара, с которого берутся данные //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Устанавливаем таймер с периодичностью в 1 секунду EventSetTimer(1); //--- Назначаем рисуемым буферам 0 и 1 массивы BufferMA1 и BufferMA2 соответственно SetIndexBuffer(0,BufferDeM1,INDICATOR_DATA); SetIndexBuffer(1,BufferDeM2,INDICATOR_DATA); //--- Устанавливаем ширину линий int w1=0,w2=0; if(InpTimeframe>Period()) { w1=InpLineWidth2; w2=InpLineWidth1; } else { w1=InpLineWidth1; w2=InpLineWidth2; } PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2); //--- sets indicator shift //--- Устанавливаем флаги серийности массивам буферов индикатора (для теста, чтобы видно было отсутствие разницы) ArraySetAsSeries(BufferDeM1,InpAsSeries); ArraySetAsSeries(BufferDeM2,InpAsSeries); //--- Создаём два индикатора одного типа //--- Первый рассчитывается на текущих символе/периоде графика, а второй - на тех, что заданы в настройках handle_dem1=indicators.AddNewDeMarker(NULL,PERIOD_CURRENT,InpPeriod); handle_dem2=indicators.AddNewDeMarker(InpSymbol,InpTimeframe,InpPeriod); //--- Если не удалось создать хэндлы индикаторов - возвращаем ошибку инициализации if(handle_dem1==INVALID_HANDLE || handle_dem2==INVALID_HANDLE) return INIT_FAILED; //--- Устанавливаем описания линий индикатора из описаний буферов расчётной части созданных индикаторов indicators.SetPlotLabelFromBuffer(0,handle_dem1,0); indicators.SetPlotLabelFromBuffer(1,handle_dem2,0); //--- Панель //--- Создаём панель int width=247; panel=new CDashboard(1,20,20,width,264,0); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Устанавливаем параметры шрифта panel.SetFontParams("Calibri",9); //--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма" panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Создаём таблицу с идентификатором 0 для отображения в ней данных бара panel.CreateNewTable(0); //--- Рисуем таблицу с идентификатором 0 на фоне панели panel.DrawGrid(0,2,20,6,2,18,width/2-2); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора 1 panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,2,2,18,width/2-2); //--- Создаём таблицу с идентификатором 2 для отображения в ней данных индикатора 2 panel.CreateNewTable(2); //--- Получаем координату Y2 таблицы с идентификатором 1 и //--- устанавливаем координату Y1 для таблицы с идентификатором 2 int y2=panel.TableY2(1)+3; //--- Рисуем таблицу с идентификатором 2 на фоне панели panel.DrawGrid(2,2,y2,3,2,18,width/2-2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Уничтожаем таймер EventKillTimer(); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; //--- Стираем все комментарии Comment(""); } //+------------------------------------------------------------------+ //| 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=rates_total-prev_calculated; //--- Если limit > 1, значит это первый расчёт, либо изменение в истории if(limit>1) { //--- указываем для просчёта всю доступную историю limit=rates_total-1; /* // Если в индикаторе есть какие-либо буферы, в которых отображены другие расчёты (не мульти- индикаторы), // то здесь их нужно инициализировать "пустым" значением, установленным для этих буферов */ } //--- Рассчитываем все созданные мультисимвольные мультипериодные индикаторы if(!indicators.Calculate()) return 0; //--- Выводим на панель данные бара под курсором (либо текущий бар, если курсор за пределами графика) DrawData(mouse_bar_index,time[mouse_bar_index]); //--- Из буферов рассчитанных индикаторов выводим данные в индикаторные буферы if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_dem1,0,0,limit,BufferDeM1)) return 0; if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_dem2,0,0,limit,BufferDeM2)) return 0; //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Вызываем таймер коллекции индикаторов indicators.OnTimer(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Работа с панелью //--- Вызываем обработчик событий панели panel.OnChartEvent(id,lparam,dparam,sparam); //--- Если курсор перемещается или щелчок по графику if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Объявляем переменные для записи в них координат времени и цены datetime time=0; double price=0; int wnd=0; //--- Если координаты курсора преобразованы в дату и время if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- записываем индекс бара, где расположен курсор в глобальную переменную mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Выводим данные бара под курсором на панель DrawData(mouse_bar_index,time); } } //--- Если получили пользовательское событие - выводим об этом сообщение в журнал if(id>CHARTEVENT_CUSTOM) { //--- Здесь может быть обработка щелчка по кнопке закрытия на панели PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } } //+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlRates rates[1]; //--- Если данные бара по указанному индексу получить не удалось - уходим if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Устанавливаем параметры шрифта для заголовков данных бара и индикатора int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Устанавливаем параметры шрифта для данных бара и индикатора panel.SetFontParams(name,9); //--- Выводим на панель данные указанного бара в таблицу 0 panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Выводим в таблицу 1 данные индикатора 1 с указанного бара в таблицу 1 panel.DrawText(indicators.Title(handle_dem1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value1=indicators.GetData(handle_dem1,0,0,index); string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_dem1)) : " "); panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 1 panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_dem1,0,0,index); panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110); //--- Выводим в таблицу 2 данные индикатора 2 с указанного бара в таблицу 2 panel.DrawText(indicators.Title(handle_dem2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2); double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_dem2,0,0,index); string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_dem2)) : " "); panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110); //--- Выводим описание состояния линии индикатора 2 panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2); ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_dem2,0,0,index); panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110); //--- Выводим описание соотношения линии индикатора 1 относительно линии индикатора 2 double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_dem2,0,0,index+1); ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_dem1,0,0,index,value2,value21); string ma1=indicators.Name(handle_dem1); string ma2=indicators.Name(handle_dem2); string state_relative= ( stateR==LINE_STATE_ABOVE ? StringFormat("%s1 > %s2",ma1,ma2) : stateR==LINE_STATE_BELOW ? StringFormat("%s1 < %s2",ma1,ma2) : stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing" : stateR==LINE_STATE_CROSS_UP ? "Bottom-up crossing" : BufferLineStateDescription(stateR) ); panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2); panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); } //+------------------------------------------------------------------+