2026-03-23 20:55:01 +07:00
//+------------------------------------------------------------------+
2026-03-23 20:51:20 +07:00
//| Article-16461-MQL5-Market-Profile-Introduction.mq5 |
//| Copyright 2026, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
2026-03-23 20:55:01 +07:00
# property indicator_chart_window
# property indicator_plots 0
//--- input parameters
input uint InpStartDate = 0 ; /* day number to start calculation */ // номер дня, с которого начнём расчёт (0 - текущий, 1 - предыдущий, и т.д.)
input uint InpShowDays = 3 ; /* number of days to display */ // количество отображаемых дней, начиная и включая день в InpStartDate
input int InpMultiplier = 1 ; /* histogram length multiplier */ // множитель длины гистограммы
input color InpAsiaSession = clrGold ; /* Asian session */ // цвет гистограммы азиатской сессии
input color InpEuropeSession = clrBlue ; /* European session */ // цвет гистограммы европейской сессии
input color InpAmericaSession = clrViolet ; /* American session */ // цвет гистограммы американской сессии
input uint InpEuropeStartHour = 8 ; /* European session opening hour */ // час открытия европейской сессии
input uint InpAmericaStartHour = 14 ; /* American session opening hour */ // час открытия американской сессии
//--- уникальный префикс для идентификации графических объектов, принадлежащих индикатору
string ExtPrefixUniq ;
2026-03-23 20:51:20 +07:00
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit ( )
{
2026-03-23 20:55:01 +07:00
//--- создаём префикс для имён объектов
string number = StringFormat ( " %I64d " , GetTickCount64 ( ) ) ;
ExtPrefixUniq = StringSubstr ( number , StringLen ( number ) -4 ) ;
Print ( " Indicator \" Market Profile \" started, prefix= " , ExtPrefixUniq ) ;
2026-03-23 20:51:20 +07:00
return ( INIT_SUCCEEDED ) ;
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
2026-03-23 20:55:01 +07:00
int OnCalculate ( const int rates_total ,
const int prev_calculated ,
2026-03-23 20:51:20 +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-23 20:55:01 +07:00
const int & spread [ ] )
2026-03-23 20:51:20 +07:00
{
2026-03-23 20:55:01 +07:00
//--- время открытия текущего дневного бара
datetime static open_time = 0 ;
//--- номер последнего дня для расчетов
//--- (при InpStartDate = 0 и InpShowDays = 3, lastday = 3)
//--- (при InpStartDate = 1 и InpShowDays = 3, lastday = 4) etc ...
uint lastday = InpStartDate + InpShowDays ;
//--- если первый расчет уже был
if ( prev_calculated ! = 0 )
{
//--- получаем время открытия текущего дневного бара
datetime current_open = iTime ( Symbol ( ) , PERIOD_D1 , 0 ) ;
//--- если текущий день не рассчитываем
if ( InpStartDate ! = 0 )
{
//--- если время открытия не было получено - уходим
if ( current_open = = open_time )
return ( rates_total ) ;
}
//--- обновляем время открытия
open_time = current_open ;
//--- далее будем рассчитывать только один день, так как все остальные дни уже посчитаны при первом запуске
lastday = InpStartDate + 1 ;
}
//--- в цикле по указанному количеству дней (либо InpStartDate+InpShowDays при первом запуске, либо InpStartDate+1 на каждом тике)
for ( uint day = InpStartDate ; day < lastday ; day + + )
{
//--- получаем в структуру данные дня с индексом day
MqlRates day_rate [ ] ;
//--- если индикатор запускается в выходные или праздничные дни, когда нет тиков, сначала нужно открыть дневной график символа
//--- если не получили данные бара по индексу day дневного периода - уходим до следующего вызова OnCalculate()
if ( CopyRates ( Symbol ( ) , PERIOD_D1 , day , 1 , day_rate ) = = -1 )
return ( prev_calculated ) ;
//--- получаем дневной диапазон (Range) в пунктах
double high_day = day_rate [ 0 ] . high ;
double low_day = day_rate [ 0 ] . low ;
double point = SymbolInfoDouble ( Symbol ( ) , SYMBOL_POINT ) ;
int day_size = ( int ) ( ( high_day - low_day ) / point ) ;
//--- подготавливаем массивы для хранения прямоугольников уровней цены
int boxes_asia [ ] , boxes_europe [ ] , boxes_america [ ] ;
//--- размеры массивов равны количеству пунктов в диапазоне дня
ArrayResize ( boxes_asia , day_size ) ;
ArrayResize ( boxes_europe , day_size ) ;
ArrayResize ( boxes_america , day_size ) ;
//--- обнуляем массивы
ZeroMemory ( boxes_asia ) ;
ZeroMemory ( boxes_europe ) ;
ZeroMemory ( boxes_america ) ;
//--- получаем все внутредневные бары текущего дня
MqlRates bars_in_day [ ] ;
datetime start_time = day_rate [ 0 ] . time + PeriodSeconds ( PERIOD_D1 ) -1 ;
datetime stop_time = day_rate [ 0 ] . time ;
//--- если индикатор запускается в выходные или праздничные дни, когда нет тиков, сначала нужно открыть дневной график символа
//--- если для указанного дня не удалось получить бары текущего таймфрейма - уходим до следующего вызова OnCalculate()
if ( CopyRates ( Symbol ( ) , PERIOD_CURRENT , start_time , stop_time , bars_in_day ) = = -1 )
return ( prev_calculated ) ;
//--- перебираем в цикле все бары текущего дня и отмечаем ячейки цены, в которые попадают бары
int size = ArraySize ( bars_in_day ) ;
for ( int i = 0 ; i < size ; i + + )
{
//--- рассчитываем диапазон индексов уровней цены в дневном диапазоне
int start_box = ( int ) ( ( bars_in_day [ i ] . low - low_day ) / point ) ; // индекс первой ячейки массива цен, соответствующей цене Low текущего бара i
int stop_box = ( int ) ( ( bars_in_day [ i ] . high - low_day ) / point ) ; // индекс последней ячейки массива цен, соответствующей цене High текущего бара i
//--- получаем час бара по индексу цикла
MqlDateTime bar_time ;
TimeToStruct ( bars_in_day [ i ] . time , bar_time ) ;
uint hour = bar_time . hour ;
//--- по часу бара определяем к какой сессии принадлежит бар
//--- американская сессия
if ( hour > = InpAmericaStartHour )
{
//--- в массиве американской сессии, в ячейках от start_box до stop_box увеличиваем счётчики баров
for ( int ind = start_box ; ind < stop_box ; ind + + )
boxes_america [ ind ] + + ;
}
//--- Европа или Азия
else
{
//--- европейская сессия
if ( hour > = InpEuropeStartHour & & hour < InpAmericaStartHour )
//--- в массиве европейской сессии, в ячейках от start_box до stop_box увеличиваем счётчики баров
for ( int ind = start_box ; ind < stop_box ; ind + + )
boxes_europe [ ind ] + + ;
//--- азиатская сессия
else
//--- в массиве азиатской сессии, в ячейках от start_box до stop_box увеличиваем счётчики баров
for ( int ind = start_box ; ind < stop_box ; ind + + )
boxes_asia [ ind ] + + ;
}
}
//--- на основании созданных массивов уровней цен рисуем профиль рынка
//--- профиль рынка на графике рисуется отрезками цветных линий цветом, заданным в настройках для каждой торговой сессии
//--- отрезки рисуются объектами-прямоугольниками с высотой прямоугольника, равной одному пункту цены, и шириной, равной дистанции до следующего бара справа
//--- определяем день для наименования графического объекта и ширину прямоугольника
string day_prefix = TimeToString ( day_rate [ 0 ] . time , TIME_DATE ) ;
int box_length = PeriodSeconds ( PERIOD_CURRENT ) ;
//--- азиатская сессия
//--- в цикле по количеству пунктов дневного бара
for ( int ind = 0 ; ind < day_size ; ind + + )
{
//--- если массив азиатской сессии заполнен
if ( boxes_asia [ ind ] > 0 )
{
//--- получаем очередную цену методом прибавления количества пунктов ind к цене Low дневного бара
//--- получаем время начала отрезка (время открытия дневного бара)
//--- и время конца отрезка (время открытия дневного бара + количество баров, хранящееся в ячейке ind массива boxes_asia[])
double price = low_day + ind * point ;
datetime time1 = day_rate [ 0 ] . time ;
datetime time2 = time1 + boxes_asia [ ind ] * box_length * InpMultiplier ;
//--- создаём префикс имени графического объекта азиатской сессии
string prefix = ExtPrefixUniq + " _ " + day_prefix + " _Asia_ " + StringFormat ( " %.5f " , price ) ;
//--- рисуем прямоугольник (отрезок линии) на рассчитанных координатах с цветом для азиатской сессии
DrawBox ( prefix , price , time1 , time2 , InpAsiaSession ) ;
}
}
//--- европейская сессия
//--- в цикле по количеству пунктов дневного бара
for ( int ind = 0 ; ind < day_size ; ind + + )
{
//--- если массив европейской сессии заполнен
if ( boxes_europe [ ind ] > 0 )
{
//--- получаем очередную цену методом прибавления количества пунктов ind к цене Low дневного бара
//--- получаем время начала отрезка (время открытия дневного бара + время правого края профиля азиатской сессии)
//--- и время конца отрезка (время начала отрезка европейской сессии + количество баров, хранящееся в ячейке ind массива boxes_europe[])
double price = low_day + ind * point ;
datetime time1 = day_rate [ 0 ] . time + boxes_asia [ ind ] * box_length * InpMultiplier ;
datetime time2 = time1 + boxes_europe [ ind ] * box_length * InpMultiplier ;
//--- создаём префикс имени графического объекта европейской сессии
string prefix = ExtPrefixUniq + " _ " + day_prefix + " _Europe_ " + StringFormat ( " %.5f " , price ) ;
//--- рисуем прямоугольник (отрезок линии) на рассчитанных координатах с цветом для европейской сессии
DrawBox ( prefix , price , time1 , time2 , InpEuropeSession ) ;
}
}
//--- американская сессия
//--- в цикле по количеству пунктов дневного бара
for ( int ind = 0 ; ind < day_size ; ind + + )
{
//--- если массив американской сессии заполнен
if ( boxes_america [ ind ] > 0 )
{
//--- получаем очередную цену методом прибавления количества пунктов ind к цене Low дневного бара
//--- получаем время начала отрезка (время открытия дневного бара + время правого края профиля азиатской сессии + время правого края профиля европейской сессии)
//--- и время конца отрезка (время начала отрезка американской сессии + количество баров, хранящееся в ячейке ind массива boxes_america[])
double price = low_day + ind * point ;
datetime time1 = day_rate [ 0 ] . time + ( boxes_asia [ ind ] + boxes_europe [ ind ] ) * box_length * InpMultiplier ;
datetime time2 = time1 + boxes_america [ ind ] * box_length * InpMultiplier ;
//--- создаём префикс имени графического объекта американской сессии
string prefix = ExtPrefixUniq + " _ " + day_prefix + " _America_ " + StringFormat ( " %.5f " , price ) ;
//--- рисуем прямоугольник (отрезок линии) на рассчитанных координатах с цветом для американской сессии
DrawBox ( prefix , price , time1 , time2 , InpAmericaSession ) ;
}
}
}
//--- по завершении цикла перерисуем график
ChartRedraw ( 0 ) ;
//--- возвращаем количество баров для следующего вызова OnCalculate
2026-03-23 20:51:20 +07:00
return ( rates_total ) ;
}
//+------------------------------------------------------------------+
2026-03-23 20:55:01 +07:00
//| Custom indicator deinitialization function |
2026-03-23 20:51:20 +07:00
//+------------------------------------------------------------------+
2026-03-23 20:55:01 +07:00
void OnDeinit ( const int reason )
2026-03-23 20:51:20 +07:00
{
2026-03-23 20:55:01 +07:00
//--- после использования удалим все графические объекты, созданные индикатором
Print ( " Indicator \" Market Profile \" stopped, delete all objects with prefix= " , ExtPrefixUniq ) ;
ObjectsDeleteAll ( 0 , ExtPrefixUniq , 0 , OBJ_RECTANGLE ) ;
ChartRedraw ( 0 ) ;
2026-03-23 20:51:20 +07:00
}
//+------------------------------------------------------------------+
2026-03-23 20:55:01 +07:00
//| Draw color box |
2026-03-23 20:51:20 +07:00
//+------------------------------------------------------------------+
2026-03-23 20:55:01 +07:00
void DrawBox ( string bar_prefix , double price , datetime time1 , datetime time2 , color clr )
2026-03-23 20:51:20 +07:00
{
2026-03-23 20:55:01 +07:00
ObjectCreate ( 0 , bar_prefix , OBJ_RECTANGLE , 0 , time1 , price , time2 , price ) ;
ObjectSetInteger ( 0 , bar_prefix , OBJPROP_COLOR , clr ) ;
ObjectSetInteger ( 0 , bar_prefix , OBJPROP_STYLE , STYLE_SOLID ) ;
ObjectSetInteger ( 0 , bar_prefix , OBJPROP_WIDTH , 1 ) ;
ObjectSetString ( 0 , bar_prefix , OBJPROP_TOOLTIP , " \n " ) ;
ObjectSetInteger ( 0 , bar_prefix , OBJPROP_BACK , true ) ;
2026-03-23 20:51:20 +07:00
}
//+------------------------------------------------------------------+