TradingCharts

Debugging

Four channels help you understand what a running script is doing: the log.* family and the Logs pane (filters, source jump, scroll to bar), visible plots, the Problems panel, and Profiler mode.

log.info / log.warning / log.error

log.info("entering, close=" + str.tostring(close))
log.info("rsi={0,number,#.##} atr={1}", ta.rsi(close, 14), ta.atr(14))   // str.format-style placeholders

if ta.crossover(close, ta.sma(close, 20))
    log.warning("Cross up on " + str.tostring(bar_index))

if close < 0
    log.error("Negative close — bad data?")
  • One entry is written each time the call executes: once per historical bar, and on every tick of the live bar.
  • Each entry carries the level, the bar time (the bar's open time; the system time is shown on hover), the script (id@version), the message and the source line of the log.* call.
  • Live bar: the entries of the open bar are replaced on every tick (the pane always shows the latest tick's lines for that bar); once the bar closes they are final. They are not rolled back the way plots are.
  • Caps: at most 500 lines per bar (a warning log limit reached — further entries dropped is appended once) and 10,000 per execution; the Logs pane keeps the latest 10,000. Logs survive until the script restarts (re-publish, inputs change, symbol or timeframe change).
  • log.* is not allowed inside a request.security expression (it runs in another context).

The Logs pane

Open it with the Logs button in the editor header. It merges the logs of every execution you currently have on charts and offers:

Control What it does
Info / Warning / Error toggles hide a level (the calls still run and still count toward the caps)
Search box plain-text filter on the message; Aa = match case, ab = whole word, .* = regular expression (invalid patterns are flagged and match nothing); matches are highlighted
From date-time hide entries whose bar time is before the chosen moment
counter N / total how many lines the filters let through
source (hover a line) opens the editor at the log.* call that produced it
scroll to bar (hover a line) moves the chart to that bar, loading older history when needed

Tips: a log.* call inside a loop multiplies per bar and eats the 500-line budget quickly — collect loop values into an array or a string and log once after the loop; gate noisy calls behind an input.bool or a time range (input.time) so the useful history reaches further back.

Plot-as-print

The oldest trick: plot a numeric value you can read off the chart.

raw = (close - open) / open * 100
plot(raw, "body %", display=display.data_window)

display=display.data_window keeps the value out of the pane but puts it in the Data Window read-out so you can hover individual bars.

Table-based readout

A tiny table in a corner is often the fastest way to see the running state of several variables:

var table t = table.new(position.bottom_right, 2, 4, bgcolor=color.new(color.black, 20))
if barstate.islast
    table.cell(t, 0, 0, "RSI",     text_color=color.gray,  text_halign=text.align_left)
    table.cell(t, 1, 0, str.tostring(ta.rsi(close, 14), "0.00"),
                                  text_color=color.white, text_halign=text.align_right)
    table.cell(t, 0, 1, "ATR",     text_color=color.gray,  text_halign=text.align_left)
    table.cell(t, 1, 1, str.tostring(ta.atr(14), "0.00"),
                                  text_color=color.white, text_halign=text.align_right)

Breakpoints

A log.* call before and after a suspected hot section narrows a hang:

log.info("before heavy loop")
for i = 0 to 1_000_000 by 100
    …
log.info("after")

The last message that fires localises the problem.

Problems panel

The editor's Problems list shows compile diagnostics as you type. Click an entry to jump to the offending line. See Errors overview.

Compile vs runtime

  • A compile error prevents publish — you'll see it in the editor before the script runs.
  • A runtime error (runtime.error, a budget overrun, a request without data) stops the execution and shows on the indicator's legend and in the Problems strip; warnings injected by the platform (no data for a symbol, log limit reached) land in Logs and the script keeps running.

Where does the time go?

When the question is how slow rather than what value, switch on Profiler mode (Script menu): every significant line gets its share of runtime and its execution count right beside the code. See Profiling and optimization.

See also