333 lines
33 KiB
MQL5
333 lines
33 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| TestOscillatorRVI.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 = 10; /* Period */ // Период расчёта RVI
|
|
//--- global variables
|
|
int handle=INVALID_HANDLE; // Хэндл индикатора
|
|
int period=0; // Период расчёта RVI
|
|
int ind_digits=0; // Количество знаков после запятой в значении индикатора
|
|
string ind_title; // Описание индикатора
|
|
//--- переменные для панели
|
|
int mouse_bar_index; // Индекс бара, с которого берутся данные
|
|
CDashboard *panel=NULL; // Указатель на объект панели
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- create timer
|
|
EventSetTimer(60);
|
|
|
|
//--- Индикатор
|
|
//--- Устанавливаем и корректируем при необходимости период расчёта
|
|
period=int(InpPeriod<1 ? 10 : InpPeriod);
|
|
//--- Устанавливаем наименование индикатора и количество знаков после запятой
|
|
ind_title=StringFormat("RVI(%lu)",period);
|
|
ind_digits=3;
|
|
//--- Создаём хэндл индикатора
|
|
ResetLastError();
|
|
handle=iRVI(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,199,225);
|
|
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,97);
|
|
|
|
//--- Создаём таблицу с идентификатором 1 для отображения в ней данных индикатора
|
|
panel.CreateNewTable(1);
|
|
//--- Получаем координату Y2 таблицы с идентификатором 0 и
|
|
//--- устанавливаем координату Y1 для таблицы с идентификатором 1
|
|
int y1=panel.TableY2(0)+22;
|
|
//--- Рисуем таблицу с идентификатором 1 на фоне панели
|
|
panel.DrawGrid(1,2,y1,3,2,18,97);
|
|
|
|
//--- Выводим в журнал табличные данные
|
|
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<value1)
|
|
if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0)
|
|
return LINE_STATE_TURN_DOWN;
|
|
//--- Направление линии вниз (value2>=value1 && value0<value1)
|
|
else if(NormalizeDouble(value2-value1,ind_digits)>=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);
|
|
//--- Линия находится под уровнем (value1<level && value0<level0)
|
|
if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0)
|
|
return LINE_STATE_UNDER;
|
|
//--- Линия находится над уровнем (value1>level && 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<level0)
|
|
if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0)
|
|
return LINE_STATE_CROSS_DOWN;
|
|
//--- Линия коснулась уровня снизу (value1<level0 && 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_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,MAIN_LINE);
|
|
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,90);
|
|
//--- Выводим на панель данные сигнальной линии индикатора с указанного бара в таблицу 1
|
|
panel.DrawText("Signal", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
|
|
double signal=IndicatorValue(handle,index,SIGNAL_LINE);
|
|
string signal_str=(signal!=EMPTY_VALUE ? DoubleToString(signal,ind_digits) : "");
|
|
panel.DrawText(signal_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90);
|
|
|
|
//--- Выводим описание состояния линии индикатора относительно сигнальной линии
|
|
panel.DrawText("RVI vs Signal", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2);
|
|
ENUM_LINE_STATE state_signal=LineStateRelative(handle,index,0,signal,IndicatorValue(handle,index+1,SIGNAL_LINE));
|
|
string state_signal_str=(state_signal==LINE_STATE_ABOVE ? "RVI > Signal" : state_signal==LINE_STATE_UNDER ? "RVI < Signal" : LineStateDescription(state_signal));
|
|
//--- Цвет надписи меняется в зависимости от значения линии относительно уровня
|
|
color clr=(state_signal==LINE_STATE_CROSS_UP ? clrBlue : state_signal==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE);
|
|
panel.DrawText(state_signal_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,90);
|
|
|
|
//--- Перерисовываем график для немедленного отображения всех изменений на панели
|
|
ChartRedraw(ChartID());
|
|
}
|
|
//+------------------------------------------------------------------+
|