# Repainting and confirmed values

> Choose deliberately between live and confirmed values, so signals do not appear and vanish on the forming bar.

Repainting means a value visible now can change before it becomes final. That is
not always a bug: a forming candle's high, close and volume, and indicators computed
from them, naturally move until the candle closes. What matters is choosing
deliberately between live and confirmed information.

## Confirmed and forming views

Every period subscription has both views:

```flowscope
script "Views"

data (
  chart = subscribe(data.ohlcv)
  h4 = subscribe(data.ohlcv, timeframe: 4h)
)

plot (
  confirmed = plot.line(title: "Last confirmed 4h close", style: linestyle.step)
  live = plot.line(title: "Forming 4h close", color: color.gray, style: linestyle.dashed)
)

on chart.update {
  confirmed.plot(h4.close)
  live.plot(h4.forming.close)
}
```

- `h4.close` is the last completed 4-hour close. It stays put until the next 4-hour
  candle confirms.
- `h4.forming.close` is the developing 4-hour close and changes with every update.

The same holds for open, high, low, volume and the other fields.

## Choose the event that matches the promise

Use `on chart.update` for visuals that should follow the forming candle, and
`on chart.close` for signals that promise candle-close confirmation:

```flowscope
script "Close-confirmed cross"

data chart = subscribe(data.ohlcv)

plot (
  average = plot.line(title: "EMA 20", color: color.blue)
  signal = plot.marker(title: "Cross up", shape: shape.up, color: color.green)
)

on chart.close {
  let ema = ta.ema(chart.close, 20)
  average.plot(ema)
  if ta.crossover(chart.close, ema) {
    signal.plot(chart.low)
  }
}
```

A close-confirmed signal appears one bar later than an intrabar one, but it cannot
disappear because the candle moved back before closing. Strategies place orders in
`on chart.close` for the same reason.

## Higher-timeframe indicators

Higher timeframes are where accidental repainting is most common. A stepped 4-hour
EMA on a lower-timeframe chart, built from confirmed closes only:

```flowscope
script "Confirmed 4h EMA"

data (
  chart = subscribe(data.ohlcv)
  h4 = subscribe(data.ohlcv, timeframe: 4h)
)

plot trend = plot.line(title: "4h EMA 21", color: color.blue, width: 2, style: linestyle.step)

state ema: float? = null

on h4.close {
  ema = ta.ema(h4.close, 21)
}

on chart.update {
  trend.plot(ema)
}
```

The EMA advances once per confirmed 4-hour candle, so the unfinished candle cannot
move it. If the developing value is useful, plot it separately and name it as such.

## Looking back never looks ahead

History indexing always looks backwards: `chart.close[1]` is the previous close,
`h4.high[1]` the 4-hour high before the last confirmed one. The confirmed view of a
higher timeframe already points at the latest completed period, so there is nothing
to shift to hide the forming one.

## Pivot location is not signal time

`ta.pivotlow` and `ta.pivothigh` need the requested number of right-hand bars
before a pivot is confirmed. With three right bars on a 5s chart, that means
three later candles, about 15 seconds after the pivot candle closes. Moving an
entry marker back to that pivot makes the history look earlier than the actual
decision was. A negative plot offset or a drawing at `chart.time[3]` changes
placement, not when the information became available.

Keep entry markers at detection time. If you also draw the old pivot, label it
as structure and keep it distinct from an entry. An earlier developing signal
can disappear; show it separately rather than promising a confirmed pivot with
no confirmation delay.

## What confirmation does not freeze

Closed-bar logic prevents changes caused by the still-forming candle. It does
not freeze source history: corrected or newly loaded bars, different warm-up
history, edited inputs and changed markets can change a recalculation. In replay,
a higher-timeframe candle is confirmed only when its own close is reached; a
completed chart candle inside it is insufficient.

To verify a script, compare detection bars while stepping replay forward and
after reloading the same history with the same inputs. Record any differences.
See [build and verify](/docs/scripting/guides/build-and-verify) for the full loop.

## Drawing at the live edge

`chart.isLast` is true in `on chart.update` for the newest, live bar. It is false
throughout history, during a [bar replay](/docs/app/replay), and always in
`on chart.close`. Compute levels on every bar, then draw them under `chart.isLast`
with a stable key, so each update moves the same drawing instead of adding one:

```flowscope
script "Live 4h high"

data (
  chart = subscribe(data.ohlcv)
  h4 = subscribe(data.ohlcv, timeframe: 4h)
)

state lines = entities.linePool(max: 1)

on chart.update {
  let t = chart.time
  let h = h4.high
  let start = h4.time
  if chart.isLast && t != null && h != null && start != null {
    lines.get("h4-high").set(start, h, t, h, color: color.red, extend: extend.right, text: "4h high")
  }
}
```

Use `chart.isRealtime` when a close handler needs to know whether the script is live.

## A checklist

1. Is each signal live or close-confirmed?
2. Does every higher-timeframe read use the confirmed or the forming view on
   purpose?
3. Are developing plots named as developing?
4. Do live drawings update one stable key instead of adding new ones?

There is no rule that a script must never repaint: a live tape tool should update
continuously, a candle-close alert usually should not. Make the choice visible in
titles and names.
