2026-03-19 00:45:49 +07:00
|
|
|
//+------------------------------------------------------------------+
|
2026-03-19 00:39:42 +07:00
|
|
|
//| Article-13179-MQL5-InfoPanel-Ind-EAs.mq5 |
|
|
|
|
|
//| Copyright 2026, MetaQuotes Ltd. |
|
|
|
|
|
//| https://www.mql5.com |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-19 00:45:49 +07:00
|
|
|
#property indicator_chart_window
|
|
|
|
|
#property indicator_buffers 1
|
|
|
|
|
#property indicator_plots 1
|
|
|
|
|
|
|
|
|
|
//--- plot MA
|
|
|
|
|
#property indicator_label1 "MA"
|
|
|
|
|
#property indicator_type1 DRAW_LINE
|
|
|
|
|
#property indicator_color1 clrRed
|
|
|
|
|
#property indicator_style1 STYLE_SOLID
|
|
|
|
|
#property indicator_width1 1
|
|
|
|
|
|
|
|
|
|
//--- includes
|
|
|
|
|
#include "Dashboard.mqh"
|
|
|
|
|
|
|
|
|
|
//--- input variables
|
|
|
|
|
input int InpPeriodMA = 10; /* MA Period */ // Период расчёта скользящей средней
|
|
|
|
|
input ENUM_MA_METHOD InpMethodMA = MODE_SMA; /* MA Method */ // Метод расчёта скользящей средней
|
|
|
|
|
input ENUM_APPLIED_PRICE InpPriceMA = PRICE_CLOSE; /* MA Price */ // Цена расчёта скользящей средней
|
|
|
|
|
input int InpPanelX = 20; /* Dashboard X */ // Координата X панели
|
|
|
|
|
input int InpPanelY = 20; /* Dashboard Y */ // Координата Y панели
|
|
|
|
|
input int InpUniqID = 0; /* Unique ID */ // Уникальный идентификатор для объекта-панели
|
|
|
|
|
|
|
|
|
|
//--- indicator buffers
|
|
|
|
|
double BufferMA[];
|
|
|
|
|
|
|
|
|
|
//--- global variables
|
|
|
|
|
CDashboard *dashboard=NULL;
|
|
|
|
|
int handle_ma; // Хэндл индикатора Moving Average
|
|
|
|
|
int period_ma; // Период расчёта Moving Average
|
|
|
|
|
int mouse_bar_index; // Индекс бара, с которого берутся данные
|
|
|
|
|
string plot_label; // Имя индикаторной графической серии для отображения в окне DataWindow
|
|
|
|
|
|
2026-03-19 00:39:42 +07:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Custom indicator initialization function |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
int OnInit()
|
|
|
|
|
{
|
|
|
|
|
//--- indicator buffers mapping
|
2026-03-19 00:45:49 +07:00
|
|
|
SetIndexBuffer(0,BufferMA,INDICATOR_DATA);
|
|
|
|
|
|
|
|
|
|
//--- Создаём хэндл индикатора
|
|
|
|
|
period_ma=(InpPeriodMA<1 ? 1 : InpPeriodMA);
|
|
|
|
|
ResetLastError();
|
|
|
|
|
handle_ma=iMA(Symbol(),PERIOD_CURRENT,period_ma,0,InpMethodMA,InpPriceMA);
|
|
|
|
|
if(handle_ma==INVALID_HANDLE)
|
|
|
|
|
{
|
|
|
|
|
PrintFormat("%s Failed to create MA indicator handle. Error %lu",__FUNCTION__,GetLastError());
|
|
|
|
|
return INIT_FAILED;
|
|
|
|
|
}
|
|
|
|
|
//--- Устанавливаем параметры индикатора
|
|
|
|
|
IndicatorSetInteger(INDICATOR_DIGITS,Digits());
|
|
|
|
|
IndicatorSetString(INDICATOR_SHORTNAME,"Test Dashboard");
|
2026-03-19 00:39:42 +07:00
|
|
|
|
2026-03-19 00:45:49 +07:00
|
|
|
//--- Устанавливаем параметры рисуемого буфера
|
|
|
|
|
plot_label="MA("+(string)period_ma+","+StringSubstr(EnumToString(Period()),7)+")";
|
|
|
|
|
PlotIndexSetString(0,PLOT_LABEL,plot_label);
|
|
|
|
|
ArraySetAsSeries(BufferMA,true);
|
|
|
|
|
|
|
|
|
|
//--- Создаём объект панели
|
|
|
|
|
dashboard=new CDashboard(InpUniqID,InpPanelX,InpPanelY,200,250);
|
|
|
|
|
if(dashboard==NULL)
|
|
|
|
|
{
|
|
|
|
|
Print("Error. Failed to create dashboard object");
|
|
|
|
|
return INIT_FAILED;
|
|
|
|
|
}
|
|
|
|
|
//--- Отображаем панель с текстом в заголовке "Символ, Описание таймфрейма"
|
|
|
|
|
dashboard.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));
|
|
|
|
|
|
|
|
|
|
//--- Рисуем табличку на фоне панели
|
|
|
|
|
dashboard.DrawGridAutoFill(2,12,2);
|
|
|
|
|
//dashboard.DrawGrid(2,1,12,2,19,97);
|
|
|
|
|
|
|
|
|
|
//--- Выводим в журнал табличные данные
|
|
|
|
|
dashboard.GridPrint(2);
|
|
|
|
|
|
|
|
|
|
//--- Инициализируем переменную с индексом бара указателя мышки
|
|
|
|
|
mouse_bar_index=0;
|
|
|
|
|
|
|
|
|
|
//--- Успешная инициализация
|
2026-03-19 00:39:42 +07:00
|
|
|
return(INIT_SUCCEEDED);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-19 00:45:49 +07:00
|
|
|
//| Custom indicator deinitialization function |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
void OnDeinit(const int reason)
|
|
|
|
|
{
|
|
|
|
|
//--- Если объект панели существует - удаляем
|
|
|
|
|
if(dashboard!=NULL)
|
|
|
|
|
delete dashboard;
|
|
|
|
|
//--- Освобождаем хэндл индикатора МА
|
|
|
|
|
ResetLastError();
|
|
|
|
|
if(!IndicatorRelease(handle_ma))
|
|
|
|
|
PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError());
|
|
|
|
|
//--- Стираем все комментарии
|
|
|
|
|
Comment("");
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-19 00:39:42 +07:00
|
|
|
//| Custom indicator iteration function |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-19 00:45:49 +07:00
|
|
|
int OnCalculate(const int rates_total,
|
|
|
|
|
const int prev_calculated,
|
2026-03-19 00:39:42 +07:00
|
|
|
const datetime &time[],
|
|
|
|
|
const double &open[],
|
|
|
|
|
const double &high[],
|
|
|
|
|
const double &low[],
|
|
|
|
|
const double &close[],
|
|
|
|
|
const long &tick_volume[],
|
|
|
|
|
const long &volume[],
|
2026-03-19 00:45:49 +07:00
|
|
|
const int &spread[])
|
2026-03-19 00:39:42 +07:00
|
|
|
{
|
2026-03-19 00:45:49 +07:00
|
|
|
//--- Устанавливаем массивам индексацию как в таймсерии
|
|
|
|
|
ArraySetAsSeries(time,true);
|
|
|
|
|
ArraySetAsSeries(open,true);
|
|
|
|
|
ArraySetAsSeries(high,true);
|
|
|
|
|
ArraySetAsSeries(low,true);
|
|
|
|
|
ArraySetAsSeries(close,true);
|
|
|
|
|
ArraySetAsSeries(tick_volume,true);
|
|
|
|
|
ArraySetAsSeries(volume,true);
|
|
|
|
|
ArraySetAsSeries(spread,true);
|
|
|
|
|
|
|
|
|
|
//--- Проверка на минимальное количество баров для расчёта
|
|
|
|
|
if(rates_total<period_ma) return 0;
|
|
|
|
|
|
|
|
|
|
//--- Проверка и расчёт количества просчитываемых баров
|
|
|
|
|
int limit=rates_total-prev_calculated;
|
|
|
|
|
//--- Если limit равен 0, то просчитывается только текущий бар
|
|
|
|
|
//--- Если limit равен 1 (открытие нового бара), то просчитываются два бара - текущий вновь открытый и предыдущий
|
|
|
|
|
//--- Если limit более 1, то это либо первый запуск индикатора, либо какие-то изменения в истории - индикатор полностью пересчитывается
|
|
|
|
|
if(limit>1)
|
|
|
|
|
{
|
|
|
|
|
limit=rates_total-period_ma-1;
|
|
|
|
|
ArrayInitialize(BufferMA,EMPTY_VALUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- Расчёт количества копируемых данных из хэндла индикатора в рисуемый буфер
|
|
|
|
|
int count=(limit>1 ? rates_total : 1),copied=0;
|
|
|
|
|
//--- Подготовка данных (получение данных в буфер скользящей средней по хэндлу)
|
|
|
|
|
copied=CopyBuffer(handle_ma,0,0,count,BufferMA);
|
|
|
|
|
if(copied!=count) return 0;
|
|
|
|
|
|
|
|
|
|
//--- Цикл расчёта индикатора по данным скользящей средней
|
|
|
|
|
for(int i=limit; i>=0 && !IsStopped(); i--)
|
|
|
|
|
{
|
|
|
|
|
// Здесь рассчитываем некий индикатор по данным стандартного Moving Average
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- Получаем данные цен и таймсерии и выводим на панель
|
|
|
|
|
//--- При первом запуске выводим на панель данные текущего бара
|
|
|
|
|
static bool first=true;
|
|
|
|
|
if(first)
|
|
|
|
|
{
|
|
|
|
|
DrawData(0,TimeCurrent());
|
|
|
|
|
first=false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- Объявляем структуру цен и получаем текущие цены
|
|
|
|
|
MqlTick tick={0};
|
|
|
|
|
if(!SymbolInfoTick(Symbol(),tick))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
//--- Если курсор находится на текущем баре - выводим на панель все данные текущего бара
|
|
|
|
|
if(mouse_bar_index==0)
|
|
|
|
|
DrawData(0,time[0]);
|
|
|
|
|
//--- Иначе - выводим на панель только цены Bid и Ask (обновляем цены на панели на каждом тике)
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dashboard.DrawText("Bid",dashboard.CellX(0,0)+2,dashboard.CellY(0,0)+2); dashboard.DrawText(DoubleToString(tick.bid,Digits()),dashboard.CellX(0,1)+2,dashboard.CellY(0,1)+2,90);
|
|
|
|
|
dashboard.DrawText("Ask",dashboard.CellX(1,0)+2,dashboard.CellY(1,0)+2); dashboard.DrawText(DoubleToString(tick.ask,Digits()),dashboard.CellX(1,1)+2,dashboard.CellY(1,1)+2,90);
|
|
|
|
|
}
|
2026-03-19 00:39:42 +07:00
|
|
|
|
|
|
|
|
//--- return value of prev_calculated for next call
|
|
|
|
|
return(rates_total);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Timer function |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
void OnTimer()
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ChartEvent function |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-19 00:45:49 +07:00
|
|
|
void OnChartEvent(const int id,
|
2026-03-19 00:39:42 +07:00
|
|
|
const long &lparam,
|
|
|
|
|
const double &dparam,
|
|
|
|
|
const string &sparam)
|
|
|
|
|
{
|
2026-03-19 00:45:49 +07:00
|
|
|
//--- Вызываем обработчик событий панели
|
|
|
|
|
dashboard.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)
|
|
|
|
|
{
|
|
|
|
|
//--- Объявляем переменные для получения в них данных
|
|
|
|
|
MqlTick tick={0};
|
|
|
|
|
MqlRates rates[1];
|
|
|
|
|
//--- Если текущие цены получить не удалось - уходим
|
|
|
|
|
if(!SymbolInfoTick(Symbol(),tick))
|
|
|
|
|
return;
|
|
|
|
|
//--- Если данные бара по указанному индексу получить не удалось - уходим
|
|
|
|
|
if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
|
|
|
|
|
return;
|
|
|
|
|
//--- Выводим на панель текущие цены и данные указанного бара
|
|
|
|
|
dashboard.DrawText("Bid", dashboard.CellX(0,0)+2, dashboard.CellY(0,0)+2); dashboard.DrawText(DoubleToString(tick.bid,Digits()), dashboard.CellX(0,1)+2, dashboard.CellY(0,1)+2,90);
|
|
|
|
|
dashboard.DrawText("Ask", dashboard.CellX(1,0)+2, dashboard.CellY(1,0)+2); dashboard.DrawText(DoubleToString(tick.ask,Digits()), dashboard.CellX(1,1)+2, dashboard.CellY(1,1)+2,90);
|
|
|
|
|
dashboard.DrawText("Date", dashboard.CellX(2,0)+2, dashboard.CellY(2,0)+2); dashboard.DrawText(TimeToString(rates[0].time,TIME_DATE), dashboard.CellX(2,1)+2, dashboard.CellY(2,1)+2,90);
|
|
|
|
|
dashboard.DrawText("Time", dashboard.CellX(3,0)+2, dashboard.CellY(3,0)+2); dashboard.DrawText(TimeToString(rates[0].time,TIME_MINUTES),dashboard.CellX(3,1)+2, dashboard.CellY(3,1)+2,90);
|
|
|
|
|
|
|
|
|
|
dashboard.DrawText("Open", dashboard.CellX(4,0)+2, dashboard.CellY(4,0)+2); dashboard.DrawText(DoubleToString(rates[0].open,Digits()), dashboard.CellX(4,1)+2, dashboard.CellY(4,1)+2,90);
|
|
|
|
|
dashboard.DrawText("High", dashboard.CellX(5,0)+2, dashboard.CellY(5,0)+2); dashboard.DrawText(DoubleToString(rates[0].high,Digits()), dashboard.CellX(5,1)+2, dashboard.CellY(5,1)+2,90);
|
|
|
|
|
dashboard.DrawText("Low", dashboard.CellX(6,0)+2, dashboard.CellY(6,0)+2); dashboard.DrawText(DoubleToString(rates[0].low,Digits()), dashboard.CellX(6,1)+2, dashboard.CellY(6,1)+2,90);
|
|
|
|
|
dashboard.DrawText("Close", dashboard.CellX(7,0)+2, dashboard.CellY(7,0)+2); dashboard.DrawText(DoubleToString(rates[0].close,Digits()), dashboard.CellX(7,1)+2, dashboard.CellY(7,1)+2,90);
|
2026-03-19 00:39:42 +07:00
|
|
|
|
2026-03-19 00:45:49 +07:00
|
|
|
dashboard.DrawText("Volume", dashboard.CellX(8,0)+2, dashboard.CellY(8,0)+2); dashboard.DrawText((string)rates[0].real_volume, dashboard.CellX(8,1)+2, dashboard.CellY(8,1)+2,90);
|
|
|
|
|
dashboard.DrawText("Tick Volume",dashboard.CellX(9,0)+2, dashboard.CellY(9,0)+2); dashboard.DrawText((string)rates[0].tick_volume, dashboard.CellX(9,1)+2, dashboard.CellY(9,1)+2,90);
|
|
|
|
|
dashboard.DrawText("Spread", dashboard.CellX(10,0)+2, dashboard.CellY(10,0)+2); dashboard.DrawText((string)rates[0].spread, dashboard.CellX(10,1)+2, dashboard.CellY(10,1)+2,90);
|
|
|
|
|
dashboard.DrawText(plot_label, dashboard.CellX(11,0)+2, dashboard.CellY(11,0)+2); dashboard.DrawText(DoubleToString(BufferMA[index],Digits()),dashboard.CellX(11,1)+2, dashboard.CellY(11,1)+2,90);
|
|
|
|
|
//--- Перерисовываем график для немедленного отображения всех изменений на панели
|
|
|
|
|
ChartRedraw(ChartID());
|
2026-03-19 00:39:42 +07:00
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|