← К каталогу
Исходный код · ID 2894

MarketProfile

market profile 1.19 (1).mq4
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

MarketProfile — пользовательский индикатор для MetaTrader 4, отображающий рыночный профиль за внутридневные, дневные, недельные или месячные торговые сессии. Индикатор строит гистограмму распределения цены по уровням, отмечает зону стоимости (VAH/VAL), медиану (POC) и уровни одиночных тиков (Single Print). Поддерживает режим Rectangle, при котором сессии задаются нарисованными на графике прямоугольниками. Доступны настройки цветовых схем, стилей и толщины линий, а также режим Developing POC для отображения развивающегося POC в реальном времени. Индикатор может выдавать оповещения при пересечении ценой уровней медианы, зоны стоимости и Single Print, а также при разрывах. Для оповещений доступны всплывающие уведомления, электронная почта и push-уведомления, а также отрисовка стрелок на графике. Настройки производительности позволяют управлять частотой перерисовки и количеством объектов. Индикатор работает в окне графика, использует 5 буферов для отображения Developing POC и стрелок оповещений. Поддерживаются внутридневные сессии с настраиваемыми временными интервалами и цветовыми схемами. Предусмотрены настройки для учета выходных дней и отключения оповещений на неподходящих таймфреймах.

Настройки программы

НастройкаОписание
Session Сессия — Выбор периода сессии: дневная, недельная, месячная, внутридневная или прямоугольник.
StartFromDate: lower priority. (StartFromDate) Начинать с даты — Дата начала отображения (имеет более низкий приоритет).
StartFromCurrentSession: higher priority. (StartFromCurrentSession) Начинать с текущей сессии — Начинать с текущей сессии (имеет более высокий приоритет).
SessionsToCount: Number of sessions to count Market Profile. (SessionsToCount) Количество сессий — Количество сессий для расчета рыночного профиля.
SeamlessScrollingMode: show sessions on current screen. (SeamlessScrollingMode) Режим бесшовной прокрутки — Показывать сессии на текущем экране.
Enable Developing POC. (EnableDevelopingPOC) Включить Developing POC — Включить отображение развивающегося POC.
ValueAreaPercentage: Percentage of TPO's inside Value Area. (ValueAreaPercentage) Процент зоны стоимости — Процент TPO внутри зоны стоимости.
ColorScheme Цветовая схема — Выбор цветовой схемы для отображения профиля.
SingleColor: if ColorScheme is set to Single_Color. (SingleColor) Одиночный цвет — Цвет, используемый, если выбрана одноцветная схема.
ColorBullBear: If true, colors are from bars' direction. (ColorBullBear) Цвет по быкам/медведям — Если включено, цвета берутся из направления баров.
MedianColor Цвет медианы — Цвет линии медианы.
ValueAreaSidesColor Цвет боковых линий зоны стоимости — Цвет боковых линий зоны стоимости.
ValueAreaHighLowColor Цвет максимума/минимума зоны стоимости — Цвет линий максимума и минимума зоны стоимости.
MedianStyle Стиль медианы — Стиль линии медианы.
MedianRayStyle Стиль луча медианы — Стиль линии луча медианы.
ValueAreaSidesStyle Стиль боковых линий зоны стоимости — Стиль боковых линий зоны стоимости.
ValueAreaHighLowStyle Стиль максимума/минимума зоны стоимости — Стиль линий максимума и минимума зоны стоимости.
ValueAreaRayHighLowStyle Стиль лучей максимума/минимума зоны стоимости — Стиль лучей максимума и минимума зоны стоимости.
MedianWidth Толщина медианы — Толщина линии медианы.
MedianRayWidth Толщина луча медианы — Толщина линии луча медианы.
ValueAreaSidesWidth Толщина боковых линий зоны стоимости — Толщина боковых линий зоны стоимости.
ValueAreaHighLowWidth Толщина максимума/минимума зоны стоимости — Толщина линий максимума и минимума зоны стоимости.
ValueAreaRayHighLowWidth Толщина лучей максимума/минимума зоны стоимости — Толщина лучей максимума и минимума зоны стоимости.
ShowValueAreaRays: draw previous value area high/low rays. (ShowValueAreaRays) Показывать лучи зоны стоимости — Рисовать лучи максимума/минимума зоны стоимости предыдущих сессий.
ShowMedianRays: draw previous median rays. (ShowMedianRays) Показывать лучи медианы — Рисовать лучи медианы предыдущих сессий.
RaysUntilIntersection: which rays stop when hit another MP. (RaysUntilIntersection) Лучи до пересечения — Выбор лучей, которые останавливаются при пересечении с другим профилем.
HideRaysFromInvisibleSessions: hide rays from behind the screen. (HideRaysFromInvisibleSessions) Скрывать лучи невидимых сессий — Скрывать лучи от сессий, находящихся за пределами экрана.
TimeShiftMinutes: shift session + to the left, - to the right. (TimeShiftMinutes) Сдвиг времени в минутах — Сдвиг сессии в минутах: положительное значение — влево, отрицательное — вправо.
ShowSinglePrint: mark Single Print profile levels. (ShowSinglePrint) Показывать Single Print — Отмечать уровни Single Print в профиле.
SinglePrintColor Цвет Single Print — Цвет отметок Single Print.
SinglePrintRays: mark Single Print edges with rays. (SinglePrintRays) Лучи Single Print — Отмечать границы Single Print лучами.
SinglePrintRayStyle Стиль лучей Single Print — Стиль линии лучей Single Print.
SinglePrintRayWidth Толщина лучей Single Print — Толщина линии лучей Single Print.
ProminentMedianColor Цвет выделенной медианы — Цвет выделенной медианы.
ProminentMedianStyle Стиль выделенной медианы — Стиль линии выделенной медианы.
ProminentMedianWidth Толщина выделенной медианы — Толщина линии выделенной медианы.
RightToLeft: Draw histogram from right to left. (RightToLeft) Справа налево — Рисовать гистограмму справа налево.
PointMultiplier: higher value = fewer objects. 0 - adaptive. (PointMultiplier) Множитель пунктов — Множитель пунктов: большее значение — меньше объектов. 0 — адаптивный режим.
ThrottleRedraw: delay (in seconds) for updating Market Profile. (ThrottleRedraw) Задержка перерисовки — Задержка в секундах для обновления рыночного профиля.
DisableHistogram: do not draw profile, VAH, VAL, and POC still visible. (DisableHistogram) Отключить гистограмму — Не рисовать гистограмму профиля, при этом VAH, VAL и POC остаются видимыми.
AlertNative: issue native pop-up alerts. (AlertNative) Всплывающие оповещения — Выдавать всплывающие оповещения в терминале.
AlertEmail: issue email alerts. (AlertEmail) Оповещения по email — Отправлять оповещения по электронной почте.
AlertPush: issue push-notification alerts. (AlertPush) Push-уведомления — Отправлять push-уведомления.
AlertArrows: draw chart arrows on alerts. (AlertArrows) Стрелки оповещений — Отрисовывать стрелки на графике при оповещениях.
AlertCheckBar: which bar to check for alerts? (AlertCheckBar) Проверяемый бар — Выбор бара для проверки оповещений: текущий или предыдущий.
AlertForValueArea: alerts for Value Area (VAH, VAL) rays. (AlertForValueArea) Оповещения для зоны стоимости — Оповещения при пересечении лучей зоны стоимости (VAH, VAL).
AlertForMedian: alerts for POC (Median) rays' crossing. (AlertForMedian) Оповещения для медианы — Оповещения при пересечении лучей медианы (POC).
AlertForSinglePrint: alerts for single print rays' crossing. (AlertForSinglePrint) Оповещения для Single Print — Оповещения при пересечении лучей Single Print.
AlertOnPriceBreak: price breaking above/below the ray. (AlertOnPriceBreak) Оповещение при пробое цены — Оповещать, когда цена пробивает уровень выше/ниже луча.
AlertOnCandleClose: candle closing above/below the ray. (AlertOnCandleClose) Оповещение при закрытии свечи — Оповещать, когда свеча закрывается выше/ниже луча.
AlertOnGapCross: bar gap above/below the ray. (AlertOnGapCross) Оповещение при разрыве — Оповещать, когда бар образует разрыв выше/ниже луча.
AlertArrowCodePB: arrow code for price break alerts. (AlertArrowCodePB) Код стрелки для пробоя цены — Код стрелки для оповещений о пробое ценой уровня.
AlertArrowCodeCC: arrow code for candle close alerts. (AlertArrowCodeCC) Код стрелки для закрытия свечи — Код стрелки для оповещений о закрытии свечи выше/ниже луча.
AlertArrowCodeGC: arrow code for gap crossover alerts. (AlertArrowCodeGC) Код стрелки для разрыва — Код стрелки для оповещений о разрыве выше/ниже луча.
EnableIntradaySession1 Включить внутридневную сессию 1 — Включить первую внутридневную сессию.
IntradaySession1StartTime Время начала сессии 1 — Время начала первой внутридневной сессии.
IntradaySession1EndTime Время окончания сессии 1 — Время окончания первой внутридневной сессии.
IntradaySession1ColorScheme Цветовая схема сессии 1 — Цветовая схема для первой внутридневной сессии.
EnableIntradaySession2 Включить внутридневную сессию 2 — Включить вторую внутридневную сессию.
IntradaySession2StartTime Время начала сессии 2 — Время начала второй внутридневной сессии.
IntradaySession2EndTime Время окончания сессии 2 — Время окончания второй внутридневной сессии.
IntradaySession2ColorScheme Цветовая схема сессии 2 — Цветовая схема для второй внутридневной сессии.
EnableIntradaySession3 Включить внутридневную сессию 3 — Включить третью внутридневную сессию.
IntradaySession3StartTime Время начала сессии 3 — Время начала третьей внутридневной сессии.
IntradaySession3EndTime Время окончания сессии 3 — Время окончания третьей внутридневной сессии.
IntradaySession3ColorScheme Цветовая схема сессии 3 — Цветовая схема для третьей внутридневной сессии.
EnableIntradaySession4 Включить внутридневную сессию 4 — Включить четвертую внутридневную сессию.
IntradaySession4StartTime Время начала сессии 4 — Время начала четвертой внутридневной сессии.
IntradaySession4EndTime Время окончания сессии 4 — Время окончания четвертой внутридневной сессии.
IntradaySession4ColorScheme Цветовая схема сессии 4 — Цветовая схема для четвертой внутридневной сессии.
SaturdaySunday Суббота и воскресенье — Обработка субботы и воскресенья: нормальные сессии, игнорировать или добавлять.
Disable alerts on wrong timeframes. (DisableAlertsOnWrongTimeframes) Отключить оповещения на неправильных таймфреймах — Отключать оповещения на неподходящих таймфреймах.
Percentage of Median TPOs out of total for a Prominent one. (ProminentMedianPercentage) Процент выделенной медианы — Процент TPO медианы от общего числа для выделения.
Получить полный код

Поиск по коду файла

???//+------------------------------------------------------------------+

#property version   "1.19"
#property strict

#property description "Displays the Market Profile indicator for intraday, daily, weekly, or monthly trading sessions."
#property description "Daily - should be attached to M5-M30 timeframes. M30 is recommended."
#property description "Weekly - should be attached to M30-H4 timeframes. H1 is recommended."
#property description "Weeks start on Sunday."
#property description "Monthly - should be attached to H1-D1 timeframes. H4 is recommended."
#property description "Intraday - should be attached to M1-M15 timeframes. M5 is recommended.\r\n"
#property description "Designed for major currency pairs, but should work also with exotic pairs, CFDs, or commodities."

#property indicator_chart_window

#property indicator_plots 5
#property indicator_buffers 5
#property indicator_color1  clrGreen
#property indicator_color2  clrGreen
#property indicator_color3  clrRed
#property indicator_color4  clrBlue
#property indicator_color5  clrYellow
#property indicator_width1  5
#property indicator_width2  5
#property indicator_width3  5
#property indicator_width4  5
#property indicator_width5  5
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_type3   DRAW_ARROW
#property indicator_type4   DRAW_ARROW
#property indicator_type5   DRAW_ARROW
#property indicator_style1  STYLE_SOLID
#property indicator_style2  STYLE_SOLID
#property indicator_label1  "Developing POC"
#property indicator_label2  "Developing POC"
#property indicator_label3  "Price break"
#property indicator_label4  "Candle close crossover"
#property indicator_label5  "Gap crossover"

enum color_scheme
{
    Blue_to_Red,        // Blue to Red
    Red_to_Green,       // Red to Green
    Green_to_Blue,      // Green to Blue
    Yellow_to_Cyan,     // Yellow to Cyan
    Magenta_to_Yellow,  // Magenta to Yellow
    Cyan_to_Magenta,    // Cyan to Magenta
    Single_Color        // Single Color
};

enum session_period
{
    Daily,
    Weekly,
    Monthly,
    Intraday,
    Rectangle
};

enum sat_sun_solution
{
    Saturday_Sunday_Normal_Days,    // Normal sessions
    Ignore_Saturday_Sunday,         // Ignore Saturday and Sunday
    Append_Saturday_Sunday          // Append Saturday and Sunday
};

enum sessions_to_draw_rays
{
    None,
    Previous,
    Current,
    PreviousCurrent,    // Previous & Current
    AllPrevious,        // All Previous
    All
};

enum ways_to_stop_rays
{
    Stop_No_Rays,                      // Stop no rays
    Stop_All_Rays,                     // Stop all rays
    Stop_All_Rays_Except_Prev_Session, // Stop all rays except previous session
    Stop_Only_Previous_Session,        // Stop only previous session's rays
};

enum bar_direction
{
    Bullish,
    Bearish,
    Neutral
};

enum single_print_type
{
    No,
    Leftside,
    Rightside
};

enum alert_check_bar
{
    CheckCurrentBar, // Current
    CheckPreviousBar // Previous
};

enum alert_types // Required to type a parameter of DoAlerts().
{
    PriceBreak,           // Price Break
    CandleCloseCrossover, // Candle Close Crossover
    GapCrossover          // Gap Crossover
};

input group "Main"
input session_period Session                 = Daily;
input datetime       StartFromDate           = __DATE__;        // StartFromDate: lower priority.
input bool           StartFromCurrentSession = true;            // StartFromCurrentSession: higher priority.
input int            SessionsToCount         = 5;               // SessionsToCount: Number of sessions to count Market Profile.
input bool           SeamlessScrollingMode   = true;            // SeamlessScrollingMode: show sessions on current screen.
input bool           EnableDevelopingPOC     = true;            // Enable Developing POC.
input int            ValueAreaPercentage     = 70;              // ValueAreaPercentage: Percentage of TPO's inside Value Area.

input group "Colors and looks"
input color_scheme   ColorScheme              = Blue_to_Red;
input color          SingleColor              = clrBlue;        // SingleColor: if ColorScheme is set to Single_Color.
input bool           ColorBullBear            = false;          // ColorBullBear: If true, colors are from bars' direction.
input color          MedianColor              = clrDarkGoldenrod;
input color          ValueAreaSidesColor      = clrDarkGreen;
input color          ValueAreaHighLowColor    = clrCrimson;
input ENUM_LINE_STYLE MedianStyle             = STYLE_SOLID;
input ENUM_LINE_STYLE MedianRayStyle          = STYLE_DASH;
input ENUM_LINE_STYLE ValueAreaSidesStyle     = STYLE_SOLID;
input ENUM_LINE_STYLE ValueAreaHighLowStyle   = STYLE_SOLID;
input ENUM_LINE_STYLE ValueAreaRayHighLowStyle= STYLE_DOT;
input int            MedianWidth              = 1;
input int            MedianRayWidth           = 1;
input int            ValueAreaSidesWidth      = 1;
input int            ValueAreaHighLowWidth    = 1;
input int            ValueAreaRayHighLowWidth = 1;
input sessions_to_draw_rays ShowValueAreaRays = None;           // ShowValueAreaRays: draw previous value area high/low rays.
input sessions_to_draw_rays ShowMedianRays    = None;           // ShowMedianRays: draw previous median rays.
input ways_to_stop_rays RaysUntilIntersection = Stop_No_Rays;   // RaysUntilIntersection: which rays stop when hit another MP.
input bool           HideRaysFromInvisibleSessions = false;     // HideRaysFromInvisibleSessions: hide rays from behind the screen.
input int            TimeShiftMinutes         = 0;              // TimeShiftMinutes: shift session + to the left, - to the right.
input bool           ShowKeyValues            = true;           // ShowKeyValues: print out VAH, VAL, POC on chart.
input color          KeyValuesColor           = clrDarkGreen;       // KeyValuesColor: color for VAH, VAL, POC printout.
input int            KeyValuesSize            = 8;              // KeyValuesSize: font size for VAH, VAL, POC printout.
input single_print_type ShowSinglePrint       = No;             // ShowSinglePrint: mark Single Print profile levels.
input color          SinglePrintColor         = clrGold;
input bool           SinglePrintRays          = false;          // SinglePrintRays: mark Single Print edges with rays.
input ENUM_LINE_STYLE SinglePrintRayStyle     = STYLE_SOLID;
input int            SinglePrintRayWidth      = 1;
input color          ProminentMedianColor     = clrYellow;
input ENUM_LINE_STYLE ProminentMedianStyle    = STYLE_SOLID;
input int            ProminentMedianWidth     = 4;
input bool           RightToLeft              = false;          // RightToLeft: Draw histogram from right to left.

input group "Performance"
input int            PointMultiplier          = 0;      // PointMultiplier: higher value = fewer objects. 0 - adaptive.
input int            ThrottleRedraw           = 0;      // ThrottleRedraw: delay (in seconds) for updating Market Profile.
input bool           DisableHistogram         = false;  // DisableHistogram: do not draw profile, VAH, VAL, and POC still visible.

input group "Alerts"
input bool           AlertNative              = false;           // AlertNative: issue native pop-up alerts.
input bool           AlertEmail               = false;           // AlertEmail: issue email alerts.
input bool           AlertPush                = false;           // AlertPush: issue push-notification alerts.
input bool           AlertArrows              = false;           // AlertArrows: draw chart arrows on alerts.
input alert_check_bar AlertCheckBar           = CheckCurrentBar; // AlertCheckBar: which bar to check for alerts?
input bool           AlertForValueArea        = false;           // AlertForValueArea: alerts for Value Area (VAH, VAL) rays.
input bool           AlertForMedian           = false;           // AlertForMedian: alerts for POC (Median) rays' crossing.
input bool           AlertForSinglePrint      = false;           // AlertForSinglePrint: alerts for single print rays' crossing.
input bool           AlertOnPriceBreak        = false;           // AlertOnPriceBreak: price breaking above/below the ray.
input bool           AlertOnCandleClose       = false;           // AlertOnCandleClose: candle closing above/below the ray.
input bool           AlertOnGapCross          = false;           // AlertOnGapCross: bar gap above/below the ray.
input int            AlertArrowCodePB         = 108;             // AlertArrowCodePB: arrow code for price break alerts.
input int            AlertArrowCodeCC         = 110;             // AlertArrowCodeCC: arrow code for candle close alerts.
input int            AlertArrowCodeGC         = 117;             // AlertArrowCodeGC: arrow code for gap crossover alerts.

input group "Intraday settings"
input bool           EnableIntradaySession1      = true;
input string         IntradaySession1StartTime   = "00:00";
input string         IntradaySession1EndTime     = "06:00";
input color_scheme   IntradaySession1ColorScheme = Blue_to_Red;

input bool           EnableIntradaySession2      = true;
input string         IntradaySession2StartTime   = "06:00";
input string         IntradaySession2EndTime     = "12:00";
input color_scheme   IntradaySession2ColorScheme = Red_to_Green;

input bool           EnableIntradaySession3      = true;
input string         IntradaySession3StartTime   = "12:00";
input string         IntradaySession3EndTime     = "18:00";
input color_scheme   IntradaySession3ColorScheme = Green_to_Blue;

input bool           EnableIntradaySession4      = true;
input string         IntradaySession4StartTime   = "18:00";
input string         IntradaySession4EndTime     = "00:00";
input color_scheme   IntradaySession4ColorScheme = Yellow_to_Cyan;

input group "Miscellaneous"
input sat_sun_solution SaturdaySunday                 = Saturday_Sunday_Normal_Days;
input bool             DisableAlertsOnWrongTimeframes = false;  // Disable alerts on wrong timeframes.
input int              ProminentMedianPercentage      = 101;    // Percentage of Median TPOs out of total for a Prominent one.

int PointMultiplier_calculated;     // Will have to be calculated based number digits in a quote if PointMultiplier input is 0.
int DigitsM;                        // Number of digits normalized based on PointMultiplier_calculated.
bool InitFailed;                    // Used for soft INIT_FAILED. Hard INIT_FAILED resets input parameters.
datetime StartDate;                 // Will hold either StartFromDate or Time[0].
double onetick;                     // One normalized pip.
bool FirstRunDone = false;          // If true - OnCalculate() was already executed once.
string Suffix = "_";                // Will store object name suffix depending on timeframe.
color_scheme CurrentColorScheme;    // Required due to intraday sessions.
int Max_number_of_bars_in_a_session = 1;
int Timer = 0;                      // For throttling updates of market profiles in slow systems.
bool NeedToRestartDrawing = false;  // Global flag for RightToLeft redrawing;
int CleanedUpOn = 0;                // To prevent cleaning up the buffers again and again when the platform just starts.
double ValueAreaPercentage_double = 0.7; // Will be calculated based on the input parameter in OnInit().
datetime LastAlertTime_CandleCross = 0, LastAlertTime_GapCross = 0; // For CheckCurrentBar alerts.
datetime LastAlertTime = 0; // For CheckPreviousBar alerts;
double Close_prev = EMPTY_VALUE;   // Previous price value for Price Break alerts.

bar_direction CurrentBarDirection = Neutral;
bar_direction PreviousBarDirection = Neutral;
bool NeedToReviewColors = false;

int IDStartHours[4];
int IDStartMinutes[4];
int IDStartTime[4]; // Stores IDStartHours x 60 + IDStartMinutes for comparison purposes.
int IDEndHours[4];
int IDEndMinutes[4];
int IDEndTime[4];   // Stores IDEndHours x 60 + IDEndMinutes for comparison purposes.
color_scheme IDColorScheme[4];
bool IntradayCheckPassed = false;
int IntradaySessionCount = 0;
int _SessionsToCount;
int IntradayCrossSessionDefined = -1; // For special case used only with Ignore_Saturday_Sunday on Monday.

double RememberSessionMax[], RememberSessionMin[];
datetime RememberSessionStart[];
string RememberSessionSuffix[];
int SessionsNumber = 0; // Different from _SessionsToCount when working with Intraday sessions and for RaysUntilIntersection != Stop_No_Rays.

class CRectangleMP
{
private:
    datetime prev_Time0;
    double prev_High, prev_Low;
    double prev_RectanglePriceMax, prev_RectanglePriceMin;
    int Number; // Order number of the rectangle;
public:
    double RectanglePriceMax, RectanglePriceMin;
    datetime RectangleTimeMax, RectangleTimeMin;
    datetime t1, t2; // To avoid reading object properties in Process() after sorting was done.
    string name;
    CRectangleMP(string);
    ~CRectangleMP(void) {};
    void Process(int);
};
CRectangleMP* MPR_Array[];
int mpr_total = 0;
uint LastRecalculationTime = 0;

double DevelopingPOC_1[], DevelopingPOC_2[]; // Indicator buffers for Developing POC.
double ArrowsPB[], ArrowsCC[], ArrowsGC[]; // Indicator buffers for alert arrows.

int OnInit()
{
      // код доступен только после оплаты
   }

void OnDeinit(const int reason)
{
    if (Session == Rectangle)
    {
        for (int i = 0; i < mpr_total; i++)
        {
            ObjectCleanup(MPR_Array[i].name + "_");
            delete MPR_Array[i];
        }
    }
    else ObjectCleanup();
}

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time_timeseries[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[]
               )
{
      // код доступен только после оплаты
   }

int FindSessionStart(const int n)
{
    if (Session == Daily) return FindDayStart(n);
    else if (Session == Weekly) return FindWeekStart(n);
    else if (Session == Monthly) return FindMonthStart(n);
    else if (Session == Intraday)
    {

        if ((SaturdaySunday == Append_Saturday_Sunday) && (TimeDayOfWeek(Time[n] + TimeShiftMinutes * 60) == 1))
        {

            for (int intraday_i = 0; intraday_i < IntradaySessionCount; intraday_i++)
            {
                if ((IDStartTime[intraday_i] == 0) || (IDStartTime[intraday_i] > IDEndTime[intraday_i]))
                {

                    if ((TimeHour(Time[n]) * 60 + TimeMinute(Time[n]) >= IDEndTime[intraday_i]) && (IDStartTime[intraday_i] > IDEndTime[intraday_i]))
                    {

                        int x = n;
                        while ((x < Bars) && (TimeHour(Time[x]) * 60 + TimeMinute(Time[x]) >= IDEndTime[intraday_i]))
                        {
                            x++;

                            if (TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60) > 1) return FindDayStart(n);
                        }
                        return (x - 1);
                    }
                    else
                    {

                        int x = n;
                        while ((x < Bars) && ((TimeDayOfYear(Time[n] + TimeShiftMinutes * 60) == TimeDayOfYear(Time[x] + TimeShiftMinutes * 60)) || (TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60) == 0))) x++;

                        _SessionsToCount++;
                        return (x - 1);
                    }
                }
            }
        }
        return FindDayStart(n);
    }
    return -1;
}

int FindDayStart(const int n)
{
    if (n >= Bars) return -1;
    int x = n;
    int time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);
    int time_n_day_of_week = time_x_day_of_week;

    while ((TimeDayOfYear(Time[n] + TimeShiftMinutes * 60) == TimeDayOfYear(Time[x] + TimeShiftMinutes * 60)) || ((SaturdaySunday == Append_Saturday_Sunday) && ((time_x_day_of_week == 0) || ((time_x_day_of_week == 5) && (time_n_day_of_week == 6)))))
    {
        x++;
        if (x >= Bars) break;
        time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);
    }

    return (x - 1);
}

int FindWeekStart(const int n)
{
    if (n >= Bars) return -1;
    int x = n;
    int time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);

    while ((SameWeek(Time[n] + TimeShiftMinutes * 60, Time[x] + TimeShiftMinutes * 60)) || ((SaturdaySunday == Append_Saturday_Sunday) && (time_x_day_of_week == 0)))
    {

        if ((SaturdaySunday == Ignore_Saturday_Sunday) && (time_x_day_of_week == 0)) break;
        x++;
        if (x >= Bars) break;
        time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);
    }

    return (x - 1);
}

int FindMonthStart(const int n)
{
    if (n >= Bars) return -1;
    int x = n;
    int time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);

    int time_n_day_of_week = TimeDayOfWeek(Time[n] + TimeShiftMinutes * 60);
    int time_n_day = TimeDay(Time[n] + TimeShiftMinutes * 60);
    int time_n_month = TimeMonth(Time[n] + TimeShiftMinutes * 60);

    while ((time_n_month == TimeMonth(Time[x] + TimeShiftMinutes * 60)) || ((SaturdaySunday == Append_Saturday_Sunday) && ((time_x_day_of_week == 0) || ((time_n_day_of_week == 6) && (time_n_day == 1)))))
    {

        int month_distance = time_n_month - TimeMonth(Time[x] + TimeShiftMinutes * 60);
        if (month_distance < 0) month_distance = 12 - month_distance;
        if (month_distance > 1) break;

        if (SaturdaySunday == Append_Saturday_Sunday)
        {
            if ((time_x_day_of_week == 6) && (TimeDay(Time[x] + TimeShiftMinutes * 60) == 1) && (time_n_day != TimeDay(Time[x] + TimeShiftMinutes * 60))) break;
        }

        if (SaturdaySunday == Ignore_Saturday_Sunday)
        {
            if (((time_x_day_of_week == 0) || (time_x_day_of_week == 6)) && ((TimeDay(Time[x] + TimeShiftMinutes * 60) == 1) || (TimeDay(Time[x] + TimeShiftMinutes * 60) == 2))) break;
        }
        x++;
        if (x >= Bars) break;
        time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);
    }

    return (x - 1);
}

int FindSessionEndByDate(const datetime date)
{
    if (Session == Daily) return FindDayEndByDate(date);
    else if (Session == Weekly) return FindWeekEndByDate(date);
    else if (Session == Monthly) return FindMonthEndByDate(date);
    else if (Session == Intraday)
    {

        if ((SaturdaySunday == Append_Saturday_Sunday) && (TimeDayOfWeek(date + TimeShiftMinutes * 60) == 0))
        {

            for (int intraday_i = 0; intraday_i < IntradaySessionCount; intraday_i++)
            {
                if ((IDStartTime[intraday_i] == 0) || (IDStartTime[intraday_i] > IDEndTime[intraday_i]))
                {

                    int x = 0;
                    int abs_day = TimeAbsoluteDay(date + TimeShiftMinutes * 60);

                    while ((x < Bars) && (abs_day < TimeAbsoluteDay(Time[x] + TimeShiftMinutes * 60))) // It's Sunday.
                    {

                        if (TimeAbsoluteDay(Time[x] + TimeShiftMinutes * 60) == abs_day + 1)
                        {

                            if (TimeHour(Time[x]) * 60 +  TimeMinute(Time[x]) < IDEndTime[intraday_i]) break;

                            if (IDStartTime[intraday_i] == 0) break;
                        }
                        x++;
                    }
                    return x;
                }
            }
        }
        return FindDayEndByDate(date);
    }

    return -1;
}

int FindDayEndByDate(const datetime date)
{
    int x = 0;

    while ((x < Bars) && (TimeAbsoluteDay(date + TimeShiftMinutes * 60) < TimeAbsoluteDay(Time[x] + TimeShiftMinutes * 60)))
    {

        if (SaturdaySunday == Append_Saturday_Sunday)
        {
            if (((TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60) == 6) || (TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60) == 1)) && (TimeAbsoluteDay(Time[x] + TimeShiftMinutes * 60) - TimeAbsoluteDay(date + TimeShiftMinutes * 60) == 1)) break;
        }
        x++;
    }

    return x;
}

int FindWeekEndByDate(const datetime date)
{
    int x = 0;

    int time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);

    while ((SameWeek(date + TimeShiftMinutes * 60, Time[x] + TimeShiftMinutes * 60) != true) || ((SaturdaySunday == Append_Saturday_Sunday) && (time_x_day_of_week == 0))  || ((SaturdaySunday == Ignore_Saturday_Sunday) && ((time_x_day_of_week == 0) || (time_x_day_of_week == 6))))
    {
        x++;
        if (x >= Bars) break;
        time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);
    }

    return x;
}

int FindMonthEndByDate(const datetime date)
{
    int x = 0;

    int time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);

    while ((SameMonth(date + TimeShiftMinutes * 60, Time[x] + TimeShiftMinutes * 60) != true) || ((SaturdaySunday == Append_Saturday_Sunday) && (time_x_day_of_week == 0))  || ((SaturdaySunday == Ignore_Saturday_Sunday) && ((time_x_day_of_week == 0) || (time_x_day_of_week == 6))))
    {

        if (SaturdaySunday == Append_Saturday_Sunday)
        {

            if ((time_x_day_of_week == 6) && (TimeDay(Time[x] + TimeShiftMinutes * 60) == 1) && (TimeYear(Time[x] + TimeShiftMinutes * 60) * 12 + TimeMonth(Time[x] + TimeShiftMinutes * 60) - TimeYear(date + TimeShiftMinutes * 60) * 12 - TimeMonth(date + TimeShiftMinutes * 60) == 1)) break;

            if ((TimeDayOfWeek(date + TimeShiftMinutes * 60) == 0) && (TimeYear(Time[x] + TimeShiftMinutes * 60) * 12 + TimeMonth(Time[x] + TimeShiftMinutes * 60) - TimeYear(date + TimeShiftMinutes * 60) * 12 - TimeMonth(date + TimeShiftMinutes * 60) == 1)) break;
        }
        x++;
        if (x >= Bars) break;
        time_x_day_of_week = TimeDayOfWeek(Time[x] + TimeShiftMinutes * 60);
    }

    return x;
}

int SameWeek(const datetime date1, const datetime date2)
{
    int seconds_from_start = TimeDayOfWeek(date1) * 24 * 3600 + TimeHour(date1) * 3600 + TimeMinute(date1) * 60 + TimeSeconds(date1);

    if (date1 == date2) return true;
    else if (date2 < date1)
    {
        if (date1 - date2 <= seconds_from_start) return true;
    }

    else if (date2 - date1 < 604800 - seconds_from_start) return true;

    return false;
}

int SameMonth(const datetime date1, const datetime date2)
{
    if ((TimeMonth(date1) == TimeMonth(date2)) && (TimeYear(date1) == TimeYear(date2))) return true;
    return false;
}

datetime PutDot(const double price, const int start_bar, const int range, const int bar, string rectangle_prefix = "", datetime converted_time = 0)
{
    double divisor, color_shift;
    int colour = -1;

    string LastNameStart = " " + TimeToString(Time[bar + start_bar]) + " ";
    string LastName = LastNameStart + DoubleToString(price, _Digits);

    if (ColorBullBear) colour = CalculateProperColor();

    if (NeedToReviewColors)
    {

        int obj_total = ObjectsTotal(ChartID(), -1, OBJ_RECTANGLE);
        for (int i = obj_total - 1; i >= 0; i--)
        {
            string obj = ObjectName(ChartID(), i, -1, OBJ_RECTANGLE);

            if (StringSubstr(obj, 0, StringLen(rectangle_prefix + "MP" + Suffix)) != rectangle_prefix + "MP" + Suffix) continue;

            if (StringSubstr(obj, 0, StringLen(rectangle_prefix + "MP" + Suffix + LastNameStart)) != rectangle_prefix + "MP" + Suffix + LastNameStart) break;

            ObjectSetInteger(0, obj, OBJPROP_COLOR, colour);
        }
    }

    if (ObjectFind(0, rectangle_prefix + "MP" + Suffix + LastName) >= 0)
    {
        if ((!RightToLeft) || (converted_time == 0)) return 0; // Normal case;
    }

    datetime time_end, time_start;
    datetime prev_time = converted_time; // For drawing, we need two times.
    if (converted_time != 0) // This is the right-to-left mode and the right-most session.
    {

        static datetime prev_time_start_bar = 0;
        if ((Time[start_bar] != prev_time_start_bar) && (prev_time_start_bar != 0)) // New right-most session arrived - recalculate everything.
        {
            NeedToRestartDrawing = true;
        }
        prev_time_start_bar = Time[start_bar];

        int x = -1;
        for (int i = range + 1; i > 0; i--) // + 1 to get a bit "lefter" time in converted_time, and actual dot's time into prev_time.
        {
            prev_time = converted_time;
            if (converted_time == Time[0]) // First time stepped into existing candles.
            {
                x = i + 1; // Remember the position.
                converted_time = Time[1]; // Move further.
            }
            else if (converted_time < Time[0])
            {
                if (x == -1) x = iBarShift(Symbol(), Period(), converted_time) + i + 1;
                converted_time = Time[x - i]; // While inside the existing candles, use existing Time for candles.
            }
            else converted_time -= PeriodSeconds(); // While beyond the current candle, subtract fixed time periods to move left on the time scale.
        }
        time_end = converted_time;
        time_start = prev_time;
    }
    else
    {
        if (start_bar - (range + 1) < 0) time_end = Time[0] + PeriodSeconds(); // Protection from 'Array out of range' error.
        else time_end = Time[start_bar - (range + 1)];
        time_start = Time[start_bar - range];
    }

    if (ObjectFind(0, rectangle_prefix + "MP" + Suffix + LastName) >= 0) // Need to move the rectangle.
    {
        ObjectSetInteger(0, rectangle_prefix  + "MP" + Suffix + LastName, OBJPROP_TIME, 0, time_start);
        ObjectSetInteger(0, rectangle_prefix  + "MP" + Suffix + LastName, OBJPROP_TIME, 1, time_end);
    }
    else ObjectCreate(0, rectangle_prefix + "MP" + Suffix + LastName, OBJ_RECTANGLE, 0, time_start, price, time_end, price - onetick);

    if (!ColorBullBear) // Otherwise, colour is already calculated.
    {

        int offset1, offset2;

        switch (CurrentColorScheme)
        {
        case Blue_to_Red:
            colour = 0xFF0000; // clrBlue;
            offset1 = 0x030000;
            offset2 = 0x000003;
            break;
        case Red_to_Green:
            colour = 0x0000FF; // clrDarkRed;
            offset1 = 0x000003;
            offset2 = 0x000300;
            break;
        case Green_to_Blue:
            colour = 0x00FF00; // clrDarkGreen;
            offset1 = 0x000300;
            offset2 = 0x030000;
            break;
        case Yellow_to_Cyan:
            colour = 0x00FFFF; // clrYellow;
            offset1 = 0x000003;
            offset2 = 0x030000;
            break;
        case Magenta_to_Yellow:
            colour = 0xFF00FF; // clrMagenta;
            offset1 = 0x030000;
            offset2 = 0x000300;
            break;
        case Cyan_to_Magenta:
            colour = 0xFFFF00; // clrCyan;
            offset1 = 0x000300;
            offset2 = 0x000003;
            break;
        case Single_Color:
            colour = SingleColor;
            offset1 = 0;
            offset2 = 0;
            break;
        default:
            colour = SingleColor;
            offset1 = 0;
            offset2 = 0;
            break;
        }

        if (CurrentColorScheme != Single_Color)
        {
            divisor = 3.0 / 0xFF * (double)Max_number_of_bars_in_a_session;

            color_shift = MathFloor((double)bar / divisor);

            if ((int)color_shift < -85) color_shift = -85;

            colour += (int)color_shift * offset1;
            colour -= (int)color_shift * offset2;
        }
    }

    ObjectSetInteger(0, rectangle_prefix + "MP" + Suffix + LastName, OBJPROP_COLOR, colour);

    ObjectSetInteger(0, rectangle_prefix + "MP" + Suffix + LastName, OBJPROP_BACK, true);
    ObjectSetInteger(0, rectangle_prefix + "MP" + Suffix + LastName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, rectangle_prefix + "MP" + Suffix + LastName, OBJPROP_HIDDEN, true);

    return time_end;
}

void ObjectCleanup(string rectangle_prefix = "")
{

    ObjectsDeleteAll(0, rectangle_prefix + "MP" + Suffix, EMPTY, OBJ_RECTANGLE);
    ObjectsDeleteAll(0, rectangle_prefix + "Median" + Suffix, EMPTY, OBJ_TREND);
    ObjectsDeleteAll(0, rectangle_prefix + "VA_LeftSide" + Suffix, EMPTY, OBJ_TREND);
    ObjectsDeleteAll(0, rectangle_prefix + "VA_RightSide" + Suffix, EMPTY, OBJ_TREND);
    ObjectsDeleteAll(0, rectangle_prefix + "VA_Top" + Suffix, EMPTY, OBJ_TREND);
    ObjectsDeleteAll(0, rectangle_prefix + "VA_Bottom" + Suffix, EMPTY, OBJ_TREND);
    if (ShowValueAreaRays != None)
    {

        ObjectsDeleteAll(0, rectangle_prefix + "Value Area HighRay" + Suffix, EMPTY, OBJ_TREND);
        ObjectsDeleteAll(0, rectangle_prefix + "Value Area LowRay" + Suffix, EMPTY, OBJ_TREND);
    }
    if (ShowMedianRays != None)
    {

        ObjectsDeleteAll(0, rectangle_prefix + "Median Ray" + Suffix, EMPTY, OBJ_TREND);
    }
    if (ShowKeyValues)
    {

        ObjectsDeleteAll(0, rectangle_prefix + "VAH" + Suffix, EMPTY, OBJ_TEXT);
        ObjectsDeleteAll(0, rectangle_prefix + "VAL" + Suffix, EMPTY, OBJ_TEXT);
        ObjectsDeleteAll(0, rectangle_prefix + "POC" + Suffix, EMPTY, OBJ_TEXT);
    }
    if (ShowSinglePrint)
    {

        ObjectsDeleteAll(0, rectangle_prefix + "MPSP" + Suffix, EMPTY, OBJ_RECTANGLE);
    }
    if (SinglePrintRays)
    {

        ObjectsDeleteAll(0, rectangle_prefix + "MPSPR" + Suffix, EMPTY, OBJ_TREND);
    }
}

bool GetHoursAndMinutes(string time_string, int& hours, int& minutes, int& time)
{
    if (StringLen(time_string) == 4) time_string = "0" + time_string;

    if (

        (StringLen(time_string) != 5) ||

        (time_string[2] != ':') ||

        ((time_string[0] < '0') || (time_string[0] > '2')) ||

        (((time_string[0] == '0') || (time_string[0] == '1')) && ((time_string[1] < '0') || (time_string[1] > '9'))) ||

        ((time_string[0] == '2') && ((time_string[1] < '0') || (time_string[1] > '3'))) ||

        ((time_string[3] < '0') || (time_string[3] > '5')) ||

        ((time_string[4] < '0') || (time_string[4] > '9'))
    )
    {
        Print("Wrong time string: ", time_string, ". Please use HH:MM format.");
        return false;
    }

    string result[];
    int number_of_substrings = StringSplit(time_string, ':', result);
    hours = (int)StringToInteger(result[0]);
    minutes = (int)StringToInteger(result[1]);
    time = hours * 60 + minutes;
    return true;
}

bool CheckIntradaySession(const bool enable, const string start_time, const string end_time, const color_scheme cs)
{
    if (enable)
    {
        if (!GetHoursAndMinutes(start_time, IDStartHours[IntradaySessionCount], IDStartMinutes[IntradaySessionCount], IDStartTime[IntradaySessionCount]))
        {
            Alert("Wrong time string format: ", start_time, ".");
            return false;
        }
        if (!GetHoursAndMinutes(end_time, IDEndHours[IntradaySessionCount], IDEndMinutes[IntradaySessionCount], IDEndTime[IntradaySessionCount]))
        {
            Alert("Wrong time string format: ", end_time, ".");
            return false;
        }

        if (IDEndTime[IntradaySessionCount] == 0)
        {

            IDEndHours[IntradaySessionCount] = 24;
            IDEndMinutes[IntradaySessionCount] = 0;
            IDEndTime[IntradaySessionCount] = 24 * 60;
        }

        IDColorScheme[IntradaySessionCount] = cs;

        if (IDEndTime[IntradaySessionCount] < IDStartTime[IntradaySessionCount]) IntradayCrossSessionDefined = IntradaySessionCount;

        IntradaySessionCount++;
    }
    return true;
}

bool ProcessSession(const int sessionstart, const int sessionend, const int i, CRectangleMP* rectangle = NULL)
{
    string rectangle_prefix = ""; // Only for rectangle sessions.

    if (sessionstart >= Bars) return false; // Data not yet ready.

    double SessionMax = DBL_MIN, SessionMin = DBL_MAX;

    for (int bar = sessionstart; bar >= sessionend; bar--)
    {
        if (High[bar] > SessionMax) SessionMax = High[bar];
        if (Low[bar] < SessionMin) SessionMin = Low[bar];
    }
    SessionMax = NormalizeDouble(SessionMax, DigitsM);
    SessionMin = NormalizeDouble(SessionMin, DigitsM);

    int session_counter = i;

    if (Session == Rectangle)
    {
        rectangle_prefix = rectangle.name + "_";
        if (SessionMax > rectangle.RectanglePriceMax) SessionMax = NormalizeDouble(rectangle.RectanglePriceMax, DigitsM);
        if (SessionMin < rectangle.RectanglePriceMin) SessionMin = NormalizeDouble(rectangle.RectanglePriceMin, DigitsM);
    }
    else
    {

        bool need_to_increment = true;

        for (int j = 0; j < SessionsNumber; j++)
        {
            if (RememberSessionStart[j] == Time[sessionstart])
            {
                need_to_increment = false;
                session_counter = j; // Real number of the session.
                break;
            }
        }

        if (need_to_increment)
        {
            SessionsNumber++;
            session_counter = SessionsNumber - 1; // Newest session.
            ArrayResize(RememberSessionMax, SessionsNumber);
            ArrayResize(RememberSessionMin, SessionsNumber);
            ArrayResize(RememberSessionStart, SessionsNumber);
            ArrayResize(RememberSessionSuffix, SessionsNumber);
        }
    }

    SessionMax = NormalizeDouble(MathRound(SessionMax / onetick) * onetick, DigitsM);
    SessionMin = NormalizeDouble(MathRound(SessionMin / onetick) * onetick, DigitsM);

    RememberSessionMax[session_counter] = SessionMax;
    RememberSessionMin[session_counter] = SessionMin;
    RememberSessionStart[session_counter] = Time[sessionstart];
    RememberSessionSuffix[session_counter] = Suffix;

    static double PreviousSessionMax = DBL_MIN;
    static datetime PreviousSessionStartTime = 0;

    if (Time[sessionstart] > PreviousSessionStartTime)
    {
        PreviousSessionMax = DBL_MIN;
        PreviousSessionStartTime = Time[sessionstart];
    }
    if ((FirstRunDone) && (i == _SessionsToCount - 1) && (PointMultiplier_calculated > 1)) // Updating the latest trading session.
    {
        if (SessionMax - PreviousSessionMax < onetick) // SessionMax increased only slightly - too small to use the new value with the current onetick.
        {
            SessionMax = PreviousSessionMax; // Do not update session max.
        }
        else
        {
            if (PreviousSessionMax != DBL_MIN)
            {

                double nc = (SessionMax - PreviousSessionMax) / onetick;

                SessionMax = NormalizeDouble(PreviousSessionMax + MathRound(nc) * onetick, DigitsM);
            }
            PreviousSessionMax = SessionMax;
        }
    }

    int TPOperPrice[];

    int max = (int)MathRound((SessionMax - SessionMin) / onetick + 2); // + 2 because further we will be possibly checking array at SessionMax + 1.
    ArrayResize(TPOperPrice, max);
    ArrayInitialize(TPOperPrice, 0);

    bool SinglePrintTracking_array[]; // For SinglePrint rays.
    if (SinglePrintRays)
    {
        ArrayResize(SinglePrintTracking_array, max);
        ArrayInitialize(SinglePrintTracking_array, false);
    }

    int MaxRange = 0; // Maximum distance from session start to the drawn dot.
    double PriceOfMaxRange = 0; // Level of the maximum range, required to draw Median.
    double DistanceToCenter = DBL_MAX; // Closest distance to center for the Median.

    datetime converted_time = 0;
    datetime converted_end_time = 0;
    datetime min_converted_end_time = UINT_MAX;
    if ((RightToLeft) && ((sessionend == 0) || (Session == Rectangle)))
    {
        int dummy_subwindow;
        double dummy_price;
        if (Session == Rectangle) converted_time = rectangle.RectangleTimeMax;
        else ChartXYToTimePrice(0, (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS), 0, dummy_subwindow, converted_time, dummy_price);
    }

    int TotalTPO = 0; // Total amount of dots (TPO's).

    for (double price = SessionMax; price >= SessionMin; price -= onetick)
    {
        price = NormalizeDouble(price, DigitsM);
        int range = 0; // Distance from first bar to the current bar.

        for (int bar = sessionstart; bar >= sessionend; bar--)
        {

            if ((price >= Low[bar]) && (price <= High[bar]))
            {

                if ((MaxRange < range) || ((MaxRange == range) && (MathAbs(price - (SessionMin + (SessionMax - SessionMin) / 2)) < DistanceToCenter)))
                {
                    MaxRange = range;
                    PriceOfMaxRange = price;
                    DistanceToCenter = MathAbs(price - (SessionMin + (SessionMax - SessionMin) / 2));
                }

                if (!DisableHistogram)
                {
                    if (ColorBullBear)
                    {

                        if (Close[bar] == Open[bar]) CurrentBarDirection = Neutral;
                        else if (Close[bar] > Open[bar]) CurrentBarDirection = Bullish;
                        else if (Close[bar] < Open[bar]) CurrentBarDirection = Bearish;

                        if (bar == 0)
                        {
                            if (PreviousBarDirection == CurrentBarDirection) NeedToReviewColors = false;
                            else
                            {
                                NeedToReviewColors = true;
                                PreviousBarDirection = CurrentBarDirection;
                            }
                        }
                    }

                    if (!RightToLeft) PutDot(price, sessionstart, range, bar - sessionstart, rectangle_prefix);

                    else
                    {
                        converted_end_time = PutDot(price, sessionstart, range, bar - sessionstart, rectangle_prefix, converted_time);
                        if (converted_end_time < min_converted_end_time) min_converted_end_time = converted_end_time; // Find the leftmost time to use for the left border of the value area.
                    }
                }

                int index = (int)MathRound((price - SessionMin) / onetick);
                TPOperPrice[index]++;
                range++;
                TotalTPO++;
            }
        }

        if (ShowSinglePrint)
        {
            if (range == 1) PutSinglePrintMark(price, sessionstart, rectangle_prefix);
            else if (range > 1) RemoveSinglePrintMark(price, sessionstart, rectangle_prefix); // Remove single print max if it exists.
        }

        if (SinglePrintRays)
        {
            int index = (int)MathRound((price - SessionMin) / onetick);
            if (range == 1) SinglePrintTracking_array[index] = true; // Remember the single print's position relative to the price.
            else SinglePrintTracking_array[index] = false;
        }
    }

    if (SinglePrintRays)
    {

        color spr_color = SinglePrintColor; // Normal ray color.
        if ((HideRaysFromInvisibleSessions) && (Time[WindowFirstVisibleBar()] >= Time[sessionstart])) spr_color = clrNONE; // Hide rays if behind the screen.

        for (double price = SessionMax; price >= SessionMin; price -= onetick)
        {
            price = NormalizeDouble(price, DigitsM);
            int index = (int)MathRound((price - SessionMin) / onetick);
            if (SinglePrintTracking_array[index])
            {
                if (price == SessionMax) // Top of the session.
                {
                    PutSinglePrintRay(price, sessionstart, rectangle_prefix, spr_color);
                }
                else
                {
                    if (SinglePrintTracking_array[index + 1] == false) // Above is a non-single print.
                    {
                        PutSinglePrintRay(price, sessionstart, rectangle_prefix, spr_color);
                    }
                    else
                    {
                        RemoveSinglePrintRay(price, sessionstart, rectangle_prefix);
                    }
                }
                if (price == SessionMin) // Bottom of the session.
                {
                    PutSinglePrintRay(price - onetick, sessionstart, rectangle_prefix, spr_color);
                }
                else
                {
                    if (SinglePrintTracking_array[index - 1] == false) // Below is a non-single print.
                    {
                        PutSinglePrintRay(price - onetick, sessionstart, rectangle_prefix, spr_color);
                    }
                    else
                    {
                        RemoveSinglePrintRay(price - onetick, sessionstart, rectangle_prefix);
                    }
                }
            }
            else
            {

                RemoveSinglePrintRay(price - onetick, sessionstart, rectangle_prefix);
            }
        }
    }

    if (EnableDevelopingPOC) CalculateDevelopingPOC(sessionstart, sessionend, rectangle); // Developing POC if necessary.

    double TotalTPOdouble = TotalTPO;

    int ValueControlTPO = (int)MathRound(TotalTPOdouble * ValueAreaPercentage_double);

    int index = (int)((PriceOfMaxRange - SessionMin) / onetick);
    if (index < 0) return false; // Data not yet ready.
    int TPOcount = TPOperPrice[index];

    int up_offset = 1;
    int down_offset = 1;
    while (TPOcount < ValueControlTPO)
    {
        double abovePrice = PriceOfMaxRange + up_offset * onetick;
        double belowPrice = PriceOfMaxRange - down_offset * onetick;

        index = (int)MathRound((abovePrice - SessionMin) / onetick);
        int index2 = (int)MathRound((belowPrice - SessionMin) / onetick);
        if (((belowPrice < SessionMin) || (TPOperPrice[index] >= TPOperPrice[index2])) && (abovePrice <= SessionMax))
        {
            TPOcount += TPOperPrice[index];
            up_offset++;
        }
        else if (belowPrice >= SessionMin)
        {
            TPOcount += TPOperPrice[index2];
            down_offset++;
        }

        else if (TPOcount < ValueControlTPO)
        {
            break;
        }
    }
    string LastName = " " + TimeToString(Time[sessionstart]);

    ObjectDelete(rectangle_prefix + "Median" + Suffix + LastName);

    index = MathMax(sessionstart - MaxRange - 1, 0);
    datetime time_start, time_end;
    if ((RightToLeft) && ((sessionend == 0) || (Session == Rectangle)))
    {
        time_end = min_converted_end_time;
        time_start = converted_time;
    }
    else
    {
        time_end = Time[index];
        time_start = Time[sessionstart];
    }
    ObjectCreate(0, rectangle_prefix + "Median" + Suffix + LastName, OBJ_TREND, 0, time_start, PriceOfMaxRange, time_end, PriceOfMaxRange);
    color mc = MedianColor;

    if ((double)(sessionstart - index) / (double)Max_number_of_bars_in_a_session * 100 >= ProminentMedianPercentage)
    {
        mc = ProminentMedianColor;
        ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_WIDTH, ProminentMedianWidth);
        ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_STYLE, ProminentMedianStyle);
    }
    else
    {
        ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_WIDTH, MedianWidth);
        ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_STYLE, MedianStyle);
    }
    ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_COLOR, mc);
    ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_BACK, false);
    ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_HIDDEN, true);
    ObjectSetInteger(0, rectangle_prefix + "Median" + Suffix + LastName, OBJPROP_RAY, false);

    ObjectDelete(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName);

    ObjectCreate(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName, OBJ_TREND, 0, time_start, PriceOfMaxRange + up_offset * onetick, time_start, PriceOfMaxRange - down_offset * onetick + onetick);
    ObjectSetInteger(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName, OBJPROP_COLOR, ValueAreaSidesColor);
    ObjectSetInteger(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName, OBJPROP_STYLE, ValueAreaSidesStyle);
    ObjectSetInteger(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName, OBJPROP_WIDTH, ValueAreaSidesWidth);
    ObjectSetInteger(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName, OBJPROP_BACK, false);
    ObjectSetInteger(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName, OBJPROP_HIDDEN, true);
    ObjectSetInteger(0, rectangle_prefix + "VA_LeftSide" + Suffix + LastName, OBJPROP_RAY, false);
    ObjectDelete(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName);

    ObjectCreate(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName, OBJ_TREND, 0, time_end, PriceOfMaxRange + up_offset * onetick, time_end, PriceOfMaxRange - down_offset * onetick + onetick);
    ObjectSetInteger(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName, OBJPROP_COLOR, ValueAreaSidesColor);
    ObjectSetInteger(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName, OBJPROP_STYLE, ValueAreaSidesStyle);
    ObjectSetInteger(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName, OBJPROP_WIDTH, ValueAreaSidesWidth);
    ObjectSetInteger(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName, OBJPROP_BACK, false);
    ObjectSetInteger(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName, OBJPROP_HIDDEN, true);
    ObjectSetInteger(0, rectangle_prefix + "VA_RightSide" + Suffix + LastName, OBJPROP_RAY, false);

    ObjectDelete(0, rectangle_prefix + "VA_Top" + Suffix + LastName);

    ObjectCreate(0, rectangle_prefix + "VA_Top" + Suffix + LastName, OBJ_TREND, 0, time_start, PriceOfMaxRange + up_offset * onetick, time_end, PriceOfMaxRange + up_offset * onetick);
    ObjectSetInteger(0, rectangle_prefix + "VA_Top" + Suffix + LastName, OBJPROP_COLOR, ValueAreaHighLowColor);
    ObjectSetInteger(0, rectangle_prefix + "VA_Top" + Suffix + LastName, OBJPROP_STYLE, ValueAreaHighLowStyle);
    ObjectSetInteger(0, rectangle_prefix + "VA_Top" + Suffix + LastName, OBJPROP_WIDTH, ValueAreaHighLowWidth);
    ObjectSetInteger(0, rectangle_prefix + "VA_Top" + Suffix + LastName, OBJPROP_BACK, false);
    ObjectSetInteger(0, rectangle_prefix + "VA_Top" + Suffix + LastName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, rectangle_prefix + "VA_Top" + Suffix + LastName, OBJPROP_HIDDEN, true);
    ObjectSetInteger(0, rectangle_prefix + "VA_Top" + Suffix + LastName, OBJPROP_RAY, false);
    ObjectDelete(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName);

    ObjectCreate(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName, OBJ_TREND, 0, time_start, PriceOfMaxRange - down_offset * onetick + onetick, time_end, PriceOfMaxRange - down_offset * onetick + onetick); // Adding onetick to put the value area bottom border to its real location as PriceOfMaxRange - down_offset * onetick puts it just below the bottom TPO, which itself is 1 tick deep.
    ObjectSetInteger(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName, OBJPROP_COLOR, ValueAreaHighLowColor);
    ObjectSetInteger(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName, OBJPROP_STYLE, ValueAreaHighLowStyle);
    ObjectSetInteger(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName, OBJPROP_WIDTH, ValueAreaHighLowWidth);
    ObjectSetInteger(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName, OBJPROP_BACK, false);
    ObjectSetInteger(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName, OBJPROP_HIDDEN, true);
    ObjectSetInteger(0, rectangle_prefix + "VA_Bottom" + Suffix + LastName, OBJPROP_RAY, false);

    if (ShowKeyValues)
    {
        ENUM_ANCHOR_POINT anchor_poc = ANCHOR_RIGHT, anchor_va = ANCHOR_RIGHT;
        if ((RightToLeft) && ((sessionend == 0) || (Session == Rectangle)))
        {
            time_start = time_end; // Inverting label display position.

            if (((Session != Rectangle) && ((ShowValueAreaRays == All) || (ShowValueAreaRays == Current) || (ShowValueAreaRays == PreviousCurrent))) // For non-rectangle sessions, it is already known that it is the current session, so just check if current session uses rays.
                    || ((Session == Rectangle) && ( // For rectangles, need to check which

Показано первые 50% кода (символов: 82978)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
8 297,80₽ ≈ $101.42