//+------------------------------------------------------------------+ //| TestOscillatorDeM.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" //--- includes #include "Dashboard.mqh" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Неопределённое состояние LINE_STATE_UP, // Направление вверх LINE_STATE_DOWN, // Направление вниз LINE_STATE_TURN_UP, // Разворот вверх LINE_STATE_TURN_DOWN, // Разворот вниз LINE_STATE_STOP_UP, // Остановка направления вверх LINE_STATE_STOP_DOWN, // Остановка направления вниз LINE_STATE_ABOVE, // Над значением LINE_STATE_UNDER, // Под значением LINE_STATE_CROSS_UP, // Пересечение значения вверх LINE_STATE_CROSS_DOWN, // Пересечение значения вниз LINE_STATE_TOUCH_BELOW, // Касание значения снизу LINE_STATE_TOUCH_ABOVE, // Касание значения сверху LINE_STATE_EQUALS, // Равно значению }; //--- input parameters input uint InpPeriod = 14; /* Period */ // Период расчёта DeMarker input double InpOverbough= 0.7; /* Overbough level*/ // Уровень перекупленности input double InpOversold = 0.3; /* Oversold level */ // Уровень перепроданности //--- global variables int handle=INVALID_HANDLE; // Хэндл индикатора int period=0; // Период расчёта DeMarker int ind_digits=0; // Количество знаков после запятой в значении индикатора double overbough=0; // Уровень перекупленности double oversold=0; // Уровень перепроданности string ind_title; // Описание индикатора //--- переменные для панели int mouse_bar_index; // Индекс бара, с которого берутся данные CDashboard *panel=NULL; // Указатель на объект панели //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Индикатор //--- Устанавливаем и корректируем при необходимости период расчёта и уровни period=int(InpPeriod<1 ? 14 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Устанавливаем наименование индикатора и количество знаков после запятой ind_title=StringFormat("DeM(%lu)",period); ind_digits=3; //--- Создаём хэндл индикатора ResetLastError(); handle=iDeMarker(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Панель //--- Создаём панель panel=new CDashboard(1,20,20,229,243); 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,112); //--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора panel.CreateNewTable(1); //--- Получаем координату Y2 таблицы с идентификатором 0 и //--- устанавливаем координату Y1 для таблицы с идентификатором 1 int y1=panel.TableY2(0)+22; //--- Рисуем таблицу с идентификатором 1 на фоне панели panel.DrawGrid(1,2,y1,4,2,18,112); //--- Выводим в журнал табличные данные panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Инициализируем переменную с индексом бара указателя мышки mouse_bar_index=0; //--- Выводим на панель данные текущего бара DrawData(mouse_bar_index,TimeCurrent()); //--- Успешная инициализация return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Освобождаем хэндл индикатора ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Очищаем все комментарии на графике Comment(""); //--- Если объект панели существует - удаляем его if(panel!=NULL) delete panel; } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void 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); } } //+------------------------------------------------------------------+ //| Возвращает данные индикатора на указанном баре | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Возвращает состояние линии индикатора | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Получаем значения линии индикатора со смещением (0,1,2) относительно переданного индекса const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Разворот линии вверх (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Направление линии вверх (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Остановка направления линии вверх (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Разворот линии вниз (value2=value1 && value0=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Остановка направления линии вниз (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Неопределённое состояние return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Возвращает состояние линии относительно указанного уровня | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Получаем значения линии индикатора со смещением (0,1) относительно переданного индекса const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- Если хоть одно из значений получить не удалось - возвращаем неопределённое значение if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Определяем второй сравниваемый уровень double level=(level1==EMPTY_VALUE ? level0 : level1); //--- Линия находится под уровнем (value1level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- Линия пересекла уровень снизу-вверх (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- Линия пересекла уровень сверху-вниз (value1>=level && value0=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- Линия коснулась уровня снизу (value1level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Линия равна значению уровня (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Неопределённое состояние return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Возвращает описание состояния линии индикатора | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } } //+------------------------------------------------------------------+ //| Выводит данные с указанного индекса таймсерии на панель | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Объявляем переменные для получения в них данных MqlTick tick={0}; MqlRates rates[1]; //--- Если текущие цены получить не удалось - уходим if(!SymbolInfoTick(Symbol(),tick)) return; //--- Если данные бара по указанному индексу получить не удалось - уходим 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("Indicator 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 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Выводим описание состояния линии индикатора относительно уровня перекупленности string ovb=StringFormat("%+.2f",overbough); panel.DrawText("Overbough", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); panel.DrawText(ovb, panel.CellX(1,2,0)+66, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_ovb=LineStateRelative(handle,index,0,overbough); //--- Цвет надписи меняется в зависимости от значения линии относительно уровня color clr=(state_ovb==LINE_STATE_ABOVE || state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); string ovb_str=(state_ovb==LINE_STATE_ABOVE ? "Inside the area" : LineStateDescription(state_ovb)); panel.DrawText(ovb_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,100); //--- Выводим описание состояния линии индикатора относительно уровня перепроданности panel.DrawText("Oversold", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); string ovs=StringFormat("%+.2f",oversold); panel.DrawText(ovs, panel.CellX(1,3,0)+68, panel.CellY(1,3,0)+2); ENUM_LINE_STATE state_ovs=LineStateRelative(handle,index,0,oversold); //--- Цвет надписи меняется в зависимости от значения линии относительно уровня clr=(state_ovs==LINE_STATE_UNDER || state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); string ovs_str=(state_ovs==LINE_STATE_UNDER ? "Inside the area" : LineStateDescription(state_ovs)); panel.DrawText(ovs_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,100); //--- Выводим описание состояния линии индикатора panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); //--- Цвет надписи меняется в зависимости от нахождения линии в областях перекупленности/перепроданности clr=(state_ovb==LINE_STATE_ABOVE || state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : state_ovs==LINE_STATE_UNDER || state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,100); //--- Перерисовываем график для немедленного отображения всех изменений на панели ChartRedraw(ChartID()); } //+------------------------------------------------------------------+