---
title: Key Levels
description: >-
  Prior-day and prior-week highs and lows plus the running day open, drawn as
  labeled horizontal levels that are calendar-correct on any chart interval.
---

<div class="flex gap-3 mb-6">
  <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-blue-50 text-blue-600 text-sm font-medium">
    Intermediate
  </span>
  <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-gray-100 text-gray-600 text-sm font-medium">
    5 min read
  </span>
</div>

Yesterday's high and low, last week's high and low, and today's open are the levels the market keeps reacting to, and half the annotations on any trading chart are someone maintaining them by hand. This recipe maintains them for you: five levels computed from calendar-anchored higher-timeframe data, drawn as thin lines with sticky price tags on the right. Because the levels come from `htf()` with calendar buckets, they are exactly the same on a 1-minute chart and a 4-hour chart, and they never repaint: a "prior day high" is always the prior *completed* UTC day.

```javascript title="key_levels.ks" lines wrap
//@version=2
define(title="Key Levels", position="onchart", axis=false, maxBarsBack=300);

var dayCol = input(name="dayCol", type="color", defaultValue="#f5a623", label="Daily color");
var weekCol = input(name="weekCol", type="color", defaultValue="#4a90d9", label="Weekly color");
var showOpen = input(name="showOpen", type="boolean", defaultValue=true, label="Show day open");
var labelOffset = input(name="labelOffset", type="slider", defaultValue=12, label="Label offset (bars)", constraints={min: 4, max: 40, step: 1});

timeseries data = ohlcv(symbol=currentSymbol, exchange=currentExchange);

timeseries d1 = htf(data, "1D");
timeseries w1 = htf(data, "1W");
var dayOpen = htf(data, "1D", {mode: "developing"}).open;

var pdh = d1.high;
var pdl = d1.low;
var pwh = w1.high;
var pwl = w1.low;

persist firstT = na;
if (isna(firstT)) { firstT = data.time; }

func lvl(x1, price, text, col) {
  if (isnum(price)) {
    var interval = isnum(data.time[1]) ? data.time - data.time[1] : 0;
    var rightX = data.time + labelOffset * interval;
    var ax1 = (isnum(firstT) && x1 < firstT) ? firstT : x1;
    line.new(ax1, price, rightX, price, { color: col, width: 1, lineStyle: "solid", stickyRight: true });
    label.new(rightX, price, text + "  " + tostring(price, "0.00"), { color: col, backgroundColor: "#1e222d", size: 11, stickyRight: true });
  }
}

if (isLastBar) {
  var DAY = 86400000;
  var curDay = timestamp(year(), month(), dayOfMonth());
  var dow = dayOfWeek();
  var dowOff = dow == "monday" ? 0 : (dow == "tuesday" ? 1 : (dow == "wednesday" ? 2 : (dow == "thursday" ? 3 : (dow == "friday" ? 4 : (dow == "saturday" ? 5 : 6)))));
  var curWeek = curDay - dowOff * DAY;
  var prevDay = curDay - DAY;
  var prevWeek = curWeek - 7 * DAY;

  lvl(prevDay, pdh, "PDH", dayCol);
  lvl(prevDay, pdl, "PDL", dayCol);
  lvl(prevWeek, pwh, "PWH", weekCol);
  lvl(prevWeek, pwl, "PWL", weekCol);
  if (showOpen) { lvl(curDay, dayOpen, "Open", dayCol); }
}
```

## How it works

**The levels come from confirmed higher-timeframe data.** `htf(data, "1D")` aggregates the chart's bars into calendar UTC days and, read as a plain value, gives you the prior *completed* day, so `d1.high` is the prior day's high with no repaint risk and no partial-period contamination. `"1W"` does the same with calendar weeks. This is the same no-repaint contract as the [Regime Filter](regime-filter.md) recipe; the details live in [Multi-Timeframe](/kscript/core-concepts/multi-timeframe).

**The day open is the one level that should move.** Today's open belongs to the *current, still-forming* day, which is exactly what `{mode: "developing"}` exposes. It updates once at the day boundary and then holds.

**Drawing happens once, on the last bar.** Lines and labels are [drawing objects](/kscript/functions/drawing-objects), not per-bar plots, so the whole render block is gated on `isLastBar`. Each level is one `line.new` from its own period's open to a point `labelOffset` bars past the last candle, plus one `label.new` price tag. `stickyRight: true` pins the tag to the right edge of the plot while you pan, so the labels behave like the axis tags you are used to.

**The `persist firstT` clamp handles shallow charts.** A weekly level's period open can predate the oldest loaded bar (a weekly line on a chart that only loaded three days); anchoring at a time the chart never loaded would not render, so the left anchor clamps to the first loaded bar.

## Customize it

- **Add monthly levels**: `timeseries m1 = htf(data, "1M");` then two more `lvl(...)` calls with `m1.high` / `m1.low` and a prior-month anchor (`timestamp(month() == 1 ? year() - 1 : year(), month() == 1 ? 12 : month() - 1, 1)`). `"1Q"` and `"1Y"` work the same way.
- **Prior close and midpoint**: `d1.close` is the prior day close; `(pdh + pdl) / 2` is the day's EQ, a favorite mean-reversion magnet.
- **Longer or shorter tags**: `labelOffset` sets how far right of the last candle the lines and tags sit; it is an input, so tune it from the settings panel.
- **Style per period**: the two color inputs keep daily and weekly levels visually distinct; add a `lineStyle` input (`"dashed"`, `"dotted"`) if you want weekly levels quieter.
