//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+