| //+------------------------------------------------------------------+
|
| //| DinexSpace | Daily High/Low & Previous Day Levels |
|
| //| Draws previous day high, low and close, today's open, today's |
|
| //| running high/low and (optionally) previous week high/low, one |
|
| //| segment per day, with a panel of levels and distance from price. |
|
| //| Values come from the symbol's own D1/W1 bars (broker server day).|
|
| //+------------------------------------------------------------------+
|
| #property copyright "(c) 2026 DinexSpace"
|
| #property version "1.00"
|
| #property description "Previous day high/low/close, today's open, today's high/low and previous week high/low."
|
| #property description "One segment per day, with a panel showing each level and its distance from price."
|
| #property strict
|
| #property indicator_chart_window
|
| #property indicator_buffers 0
|
| #property indicator_plots 0
|
|
|
| input group "Levels"
|
| input bool InpShowPD = true; // Previous day high / low
|
| input color InpColPDH = clrSpringGreen; // Previous day high colour
|
| input color InpColPDL = clrAqua; // Previous day low colour
|
| input bool InpShowPDC = true; // Previous day close
|
| input color InpColPDC = clrDarkGray; // Previous day close colour
|
| input bool InpShowDO = true; // Today's open
|
| input color InpColDO = C'255,176,0'; // Today's open colour
|
| input bool InpShowTHL = false; // Today's high / low (live)
|
| input color InpColTHL = clrWhite; // Today's high / low colour
|
| input bool InpShowPW = false; // Previous week high / low
|
| input color InpColPW = C'142,124,255'; // Previous week colour
|
|
|
| input group "Display"
|
| input int InpDays = 5; // Days of history
|
| input ENUM_LINE_STYLE InpStyle = STYLE_SOLID; // Line style
|
| input int InpWidth = 1; // Line width
|
| input bool InpLabels = true; // Labels with price (today)
|
| input int InpLblOff = 3; // Label offset (bars right of price)
|
| input bool InpPanel = true; // Levels panel
|
| input ENUM_BASE_CORNER InpCorner = CORNER_RIGHT_UPPER; // Panel corner
|
|
|
| const string PFX = "DNXDL_";
|
| #define NL 8
|
|
|
| string g_tag[NL] = {"PDH", "PDL", "PDC", "Open", "High", "Low", "PWH", "PWL"};
|
| string g_name[NL] = {"Prev. day high", "Prev. day low", "Prev. day close", "Today's open",
|
| "Today's high", "Today's low", "Prev. week high", "Prev. week low"};
|
| bool g_on[NL];
|
| color g_col[NL];
|
| datetime g_lastDay = 0;
|
|
|
| //+------------------------------------------------------------------+
|
| //| Level k of the day that is `d` days back (d = 0 is today). |
|
| //| Returns 0 when the data is not available. |
|
| //+------------------------------------------------------------------+
|
| double LevelValue(int k, int d)
|
| {
|
| switch(k)
|
| {
|
| case 0: return iHigh(_Symbol, PERIOD_D1, d + 1);
|
| case 1: return iLow(_Symbol, PERIOD_D1, d + 1);
|
| case 2: return iClose(_Symbol, PERIOD_D1, d + 1);
|
| case 3: return iOpen(_Symbol, PERIOD_D1, d);
|
| case 4: return iHigh(_Symbol, PERIOD_D1, d);
|
| case 5: return iLow(_Symbol, PERIOD_D1, d);
|
| }
|
| datetime dayStart = iTime(_Symbol, PERIOD_D1, d);
|
| if(dayStart == 0)
|
| return 0;
|
| int w = iBarShift(_Symbol, PERIOD_W1, dayStart, false);
|
| if(w < 0)
|
| return 0;
|
| return (k == 6) ? iHigh(_Symbol, PERIOD_W1, w + 1) : iLow(_Symbol, PERIOD_W1, w + 1);
|
| }
|
|
|
| void DrawSegment(int k, int d, datetime t0, datetime t1, double y)
|
| {
|
| string nm = PFX + g_tag[k] + "_" + IntegerToString(d);
|
| if(ObjectFind(0, nm) < 0)
|
| {
|
| ObjectCreate(0, nm, OBJ_TREND, 0, t0, y, t1, y);
|
| ObjectSetInteger(0, nm, OBJPROP_COLOR, g_col[k]);
|
| ObjectSetInteger(0, nm, OBJPROP_STYLE, InpStyle);
|
| ObjectSetInteger(0, nm, OBJPROP_WIDTH, InpWidth);
|
| ObjectSetInteger(0, nm, OBJPROP_RAY_RIGHT, false);
|
| ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false);
|
| ObjectSetInteger(0, nm, OBJPROP_HIDDEN, true);
|
| ObjectSetInteger(0, nm, OBJPROP_BACK, true);
|
| }
|
| ObjectMove(0, nm, 0, t0, y);
|
| ObjectMove(0, nm, 1, t1, y);
|
| }
|
|
|
| void DrawLabel(int k, datetime t, double y)
|
| {
|
| string nm = PFX + g_tag[k] + "_lbl";
|
| if(ObjectFind(0, nm) < 0)
|
| {
|
| ObjectCreate(0, nm, OBJ_TEXT, 0, t, y);
|
| ObjectSetInteger(0, nm, OBJPROP_ANCHOR, ANCHOR_LEFT);
|
| ObjectSetInteger(0, nm, OBJPROP_FONTSIZE, 8);
|
| ObjectSetInteger(0, nm, OBJPROP_COLOR, g_col[k]);
|
| ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false);
|
| ObjectSetInteger(0, nm, OBJPROP_HIDDEN, true);
|
| }
|
| ObjectMove(0, nm, 0, t, y);
|
| ObjectSetString(0, nm, OBJPROP_TEXT, g_tag[k] + " " + DoubleToString(y, _Digits));
|
| }
|
|
|
| void PanelCell(int row, int col, string text, color clr)
|
| {
|
| string nm = PFX + "p_" + IntegerToString(row) + "_" + IntegerToString(col);
|
| bool right = (InpCorner == CORNER_RIGHT_UPPER || InpCorner == CORNER_RIGHT_LOWER);
|
| bool lower = (InpCorner == CORNER_LEFT_LOWER || InpCorner == CORNER_RIGHT_LOWER);
|
| if(ObjectFind(0, nm) < 0)
|
| {
|
| ObjectCreate(0, nm, OBJ_LABEL, 0, 0, 0);
|
| ObjectSetInteger(0, nm, OBJPROP_CORNER, InpCorner);
|
| ObjectSetInteger(0, nm, OBJPROP_ANCHOR, right ? (lower ? ANCHOR_RIGHT_LOWER : ANCHOR_RIGHT_UPPER)
|
| : (lower ? ANCHOR_LEFT_LOWER : ANCHOR_LEFT_UPPER));
|
| // columns are placed from the panel's outer edge inwards
|
| int x = right ? 10 + (2 - col) * 95 : 10 + col * 95;
|
| ObjectSetInteger(0, nm, OBJPROP_XDISTANCE, x);
|
| ObjectSetInteger(0, nm, OBJPROP_YDISTANCE, 20 + (lower ? NL + 1 - row : row) * 15);
|
| ObjectSetInteger(0, nm, OBJPROP_FONTSIZE, 8);
|
| ObjectSetString(0, nm, OBJPROP_FONT, "Consolas");
|
| ObjectSetInteger(0, nm, OBJPROP_SELECTABLE, false);
|
| ObjectSetInteger(0, nm, OBJPROP_HIDDEN, true);
|
| }
|
| ObjectSetString(0, nm, OBJPROP_TEXT, text);
|
| ObjectSetInteger(0, nm, OBJPROP_COLOR, clr);
|
| }
|
|
|
| void UpdatePanel(double price, bool intraday)
|
| {
|
| if(!InpPanel)
|
| return;
|
| PanelCell(0, 0, "Level", clrGray);
|
| PanelCell(0, 1, "Price", clrGray);
|
| PanelCell(0, 2, "To level", clrGray);
|
| for(int k = 0; k < NL; k++)
|
| {
|
| double y = LevelValue(k, 0);
|
| bool ok = y > 0 && (intraday || k < 4 || k > 5);
|
| double dist = y - price;
|
| PanelCell(k + 1, 0, g_name[k], g_col[k]);
|
| PanelCell(k + 1, 1, ok ? DoubleToString(y, _Digits) : "-", clrWhite);
|
| PanelCell(k + 1, 2, ok ? (dist >= 0 ? "+" : "") + DoubleToString(dist, _Digits) : "-", dist >= 0 ? clrSpringGreen : clrAqua);
|
| }
|
| PanelCell(NL + 1, 0, intraday ? "DinexSpace" : "Lines need an intraday chart", intraday ? clrSpringGreen : clrOrange);
|
| }
|
|
|
| int OnInit()
|
| {
|
| bool on[NL] = {true, true, true, true, true, true, true, true};
|
| on[0] = on[1] = InpShowPD; on[2] = InpShowPDC; on[3] = InpShowDO;
|
| on[4] = on[5] = InpShowTHL; on[6] = on[7] = InpShowPW;
|
| color col[NL] = {clrNONE, clrNONE, clrNONE, clrNONE, clrNONE, clrNONE, clrNONE, clrNONE};
|
| col[0] = InpColPDH; col[1] = InpColPDL; col[2] = InpColPDC; col[3] = InpColDO;
|
| col[4] = InpColTHL; col[5] = InpColTHL; col[6] = InpColPW; col[7] = InpColPW;
|
| for(int k = 0; k < NL; k++)
|
| {
|
| g_on[k] = on[k];
|
| g_col[k] = col[k];
|
| }
|
| if(InpDays < 1 || InpDays > 60)
|
| return INIT_PARAMETERS_INCORRECT;
|
| g_lastDay = 0;
|
| return INIT_SUCCEEDED;
|
| }
|
|
|
| void OnDeinit(const int reason)
|
| {
|
| ObjectsDeleteAll(0, PFX);
|
| }
|
|
|
| int OnCalculate(const int rates_total, const int prev_calculated,
|
| const datetime &time[], const double &open[], const double &high[],
|
| const double &low[], const double &close[], const long &tick_volume[],
|
| const long &volume[], const int &spread[])
|
| {
|
| if(rates_total < 2)
|
| return 0;
|
| ArraySetAsSeries(time, true);
|
| ArraySetAsSeries(close, true);
|
| bool intraday = PeriodSeconds(_Period) < 86400;
|
| datetime today = iTime(_Symbol, PERIOD_D1, 0);
|
| if(today == 0)
|
| return 0; // D1 history not loaded yet: try again on the next tick
|
|
|
| if(intraday)
|
| {
|
| // Full redraw once per new day (or on first run); otherwise only today's segments move.
|
| int dFrom = (today != g_lastDay || prev_calculated == 0) ? InpDays - 1 : 0;
|
| if(dFrom > 0)
|
| ObjectsDeleteAll(0, PFX);
|
| for(int d = dFrom; d >= 0; d--)
|
| {
|
| datetime t0 = iTime(_Symbol, PERIOD_D1, d);
|
| if(t0 == 0)
|
| continue;
|
| datetime t1 = (d == 0) ? time[0] : iTime(_Symbol, PERIOD_D1, d - 1) - PeriodSeconds(_Period);
|
| for(int k = 0; k < NL; k++)
|
| {
|
| if(!g_on[k])
|
| continue;
|
| double y = LevelValue(k, d);
|
| if(y > 0)
|
| DrawSegment(k, d, t0, t1, y);
|
| }
|
| }
|
| g_lastDay = today;
|
| if(InpLabels)
|
| for(int k = 0; k < NL; k++)
|
| {
|
| double y = LevelValue(k, 0);
|
| if(g_on[k] && y > 0)
|
| DrawLabel(k, time[0] + InpLblOff * PeriodSeconds(_Period), y);
|
| }
|
| }
|
| UpdatePanel(close[0], intraday);
|
| return rates_total;
|
| }
|
| //+------------------------------------------------------------------+
|