Two reported issues are fixed here, both of them regressions of earlier releases: na passed to an
int-typed argument crashed the run, and a ta.* call inside a loop with a per-iteration length had
become an order of magnitude slower.
Fixes
-
naat an integer argument raised instead of answeringna(issue #79). The truncation
added for int-typed arguments went through a bareint(), whichNA.__int__refuses by design,
so 20 slots turned a legal script into a runtime crash — everytabledimension and cell
coordinate, plusstr.replaceandstr.substring.table.new(position.top_left, na, na), a
construct Pine's own documentation uses, died withTypeError: NA cannot be converted to int.
Each slot now substitutes the concrete integer TradingView substitutes there, measured on
TradingView: table dimensions and coordinates readnaas 0 per argument;str.substringreads
annabegin as 0 but annaend as the end of the source;str.replacereads anna
occurrence as the first one. Twonaguards were wrong alongside them:str.substringresolved
its positions before annasource, andstr.repeattestedx != x, which never sees a bare
NAobject. -
A library's unexported overload could break its exported one. When a library exported one
overload of a name and left another unexported, the once-per-run definition latch handed the
name to the export and declared itglobal, so the unexported definition — rebuilt every bar —
wrote over the module-level proxy the export decorator had registered. Method calls resolved
against that proxy and asserted with "No such method" on the first bar; five scripts in the
compatibility corpus died on it. -
A state-carrying definition inside a compound statement crashed on its first call. The
layout pass only walked the top level of each body, so such a definition was allocated a scope
and rewritten to read its state vector, but never received the hidden state parameter. -
Reversal close retries are throttled in the broker layer: markers are armed for every close
outcome and retried after the stale window, so a rejected close no longer redispatches on the
same bar.
Performance
-
ta.*in a loop with a per-iteration length (issue #80). Every iteration re-derived
math.sum's window walk from the bar's starting state, oneSeriesread per step. Twenty
lengths 20..400 over 25369 bars took 36.6s, against 3.7s for the same loop at a constant length.
The offsets a walk reads now travel as one native list, the re-baselines fold natively, and the
eviction walk memoizes its state per step, so an iteration needing fewer steps reads its answer
instead of re-walking. The same script now runs in 5.6s. A length that shrinks per iteration
runs in 17.5s from 40.8s — its walk shares the tail of its input rather than the prefix of its
fold, so it cannot memoize. Every plot value is unchanged: byte-identical output on eleven
scripts covering all three loop shapes,nasources, sawtooth lengths and windows past the
default lookback, and all 564 corpus scripts keep every metric.The rewrite also made an older defect visible: on an
nabar the eviction walk read one offset
below the ones that actually leave, so the newest leaving offset was subtracted twice and the
oldest never, and the error stayed in the compensated accumulator for the rest of the run. The
two ranges coincide on a stored bar, so nothing measured against TradingView moves. -
A library defines its exports once per run, not once per bar. A library main is a per-bar
entry point, so every bar allocated a fresh function object per export and ran the decorator
over it, while call sites anchor on the stable module-level proxy and never used them. A
20-export library drops from 8.1 to 2.6 us/bar.
Features
array.sortandarray.sort_indicesacceptsort_field, Pine's third parameter naming a
field of an object element. Measured on TradingView: the field is the sort key while the whole
element moves, and thenarule reads the field's type — a numeric field putsnalast
ascending and first descending, a string field puts it first. The parameter works positionally
and by name.