FlowscopeDocs

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
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
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
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 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, 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
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.