v6.8.1
This release is about scripts that used to stop running. Most of what is fixed here does
not change a number — it removes a TypeError, a ValueError or an AttributeError that
halted a script outright, in situations TradingView handles and keeps going through: an
na array index, a float index, a keyword argument spelled the way Pine spells it, a
mutating call on an array.slice view, a for loop over a matrix, a tuple-shaped
request.seed.
The second theme is drawings. A bar's script body can run several times — after every fill
with calc_on_order_fills, on every intra-bar tick in live mode — and until now the
discarded runs left their drawings and plot columns behind. That is fixed, together with a
set of copy bugs that produced chart objects the chart never showed.
Behavior changes
array.slicevalidates its bounds. An invalid range now raises instead of being
silently normalized, matching TradingView, which halts there withRE10045(and
RE10044for a reversed pair).index_from == index_tostays a legal empty slice.- An order with an unsizable quantity is not placed.
strategy.entry,
strategy.orderand the deferred-qty resolution require a positive finite quantity, so
NaNand infinity are dropped like a zero instead of halting the run in the lot
rounding. color.rgbno longer raises on out-of-range arguments. It clips them, truncates
fractional channels and acceptsna, the way TradingView does.- A number of parameter names changed to Pine's spelling (
str.contains,str.endswith,
str.startswith,str.postakestr;str.format_timetakesformat/timezone;
math.acos/asin/atantakeangle;math.todegreestakesradians;
math.toradianstakesdegrees;color.rgbtakesred/green/blue;
str.replacetakesoccurrence;natakesx;map.put_alltakesid2;
ta.alma/bb/bbw/cmo/mfitakeseries;ta.supertrendtakes
atrPeriod). Hand-written Pyne code passing any of the old names by keyword needs
updating; every internal caller was positional. strategy.exitlost its phantomoca_typeparameter. It was a 13th parameter Pine
does not have, and it shifted every parameter after it, so a positional call assigned
commenttooca_type,alert_messagetocomment, and so on.array.standardizeno longer thresholds int arrays. TradingView standardizes int
and float arrays identically; the old-1/0/1output was wrong.matrix.copy()is no longer a deep copy. Likearray.copy(), it copies only its row
storage; drawings, chart points and user-defined instances stay shared, which is what
TradingView does.
Features
strategy.opentrades.capital_held: the summed entry value of the open trades. It does
not follow the market and a short trade contributes just like a long one. The margin
percentages do not scale it, but a strategy with no margin requirement on either side
reportsna.array.new_table. PyneComp already compiled Pine'sarray.new<table>to it, so such a
script used to reach a function that did not exist.- Four new
labelsetters:label.set_point,label.set_xloc,
label.set_text_font_familyandlabel.set_text_formatting. strategy.entry,strategy.closeandstrategy.close_allaccept Pine's trailing
disable_alert, andrequest.dividends/request.earningsacceptcurrency. Without
them a script naming any of these raisedTypeError.- Overload dispatch selects on the exact argument type before widening. With
f(float)
andf(int)declared in either order, an int argument — literal, variable, series or a
typedna— takes the int one; only a script with no int implementation widens to
float. A container discriminates on its element type the same way, sampled from a real
one or read off the declared subscript of anna.
Fixes
Scripts that used to halt
- An
naarray index raisedTypeErrorinarray.get,set,remove,insert,
slice,fill,percentrank,max,minand both percentile functions. Measured on
TradingView:getandremovereturnna,setis a no-op,insertappends,slice
andfillresolve annabound to 0 or to the size, andpercentrank/max/min
behave as index 0. - A float index — from a division, from
math.round— halted with "list indices must be
integers". It is truncated now, across thearrayandmatrixnamespaces, always after
thenaguard. matrix.get/set/row/colraised on annaindex. They return element-typed
na, annaarray, or do nothing.for row in mover a matrix halted with "'Matrix' object is not iterable". The iterator
yields the row lists themselves, as TradingView documents, so writing through the loop
variable changes the matrix.- Every structural mutation of an
array.sliceview died with "'SequenceView' object has
no attribute 'append'" —push,insert,unshift,remove,pop,shift,clear.
The view is a live, writable index range now, clipped to the parent's current length, so
a stale sibling slice no longer raisesIndexErrorafter the parent shrinks. request.seedreturned a singlenafor a tuple expression, so the compiled
destructuring halted with "na is not iterable". A tuple expression yields a tuple ofna
of the same arity.str.splitwith an empty separator raised "empty separator". Pine returns the individual
characters.math.randomwithout an explicit seed returnednaon every draw: thenadefault was
handed to the generator, which XOR-ed it into its state.- A
matrix<float> m = nadeclaration madena(m)answerFalse, so the first matrix
call on it died with "'bool' object has no attribute ...". A subscripted user generic is
matched on its origin now. The same paths also gained PEP 604 union support, stopped
letting aboolanswer anintparameter, and no longer mergeNA(int)withNA(str)
in the selection cache.
Drawings
- A discarded body execution left its drawings behind. They piled up in the registries,
filled the script'smax_lines_countbudget and evicted live drawings. A new drawing
snapshot restores the six registries and every live drawing's fields — written back into
the same objects, so a handle held by a script variable stays attached to its chart
object. Plot data was not cleared either, so a re-executed bar exported the discarded
run's value under the real title and the later runs as<title> 0/<title> 1columns. - The var-slot snapshot cloned every var-held drawing, producing duplicates that carried
the same id, sat in no registry and never reached the chart. Measured on a 30-bar run:
three objects ended up carrying id 1, and no script variable pointed at the registered
one, so every laterlabel.set_*updated an object the chart never shows. - A Pine
.copy()on a label, line or box produced a field-wise clone with the source's
id that entered no registry, never reached the chart and never counted toward
max_*_count. The same call on an array, a map or a matrix raisedTypeError. Copies
now dispatch to the owning namespace, which assigns a fresh id, registers the clone and
enforces the cap. calc_on_order_fillsdid not re-execute the body at all when the script had no root
variable slots; a live every-tick script re-executed on fills with the option off; and
the last warmup bar continued by the live feed was counted twice, permanently offsetting
everyvarcounter and drawing for the rest of the session.
Values and semantics
str.replacepicked the wrong occurrence:occurrence=1replaced the first match, and
a source without an nth occurrence was still modified. Occurrences are 0-based and
enumerated by an overlapping left-to-right scan, so"aa"occurs at both index 0 and 1
of"aaa".array.sortandsort_indicesleft values around a singlenaelement unsorted,
because Python's comparisons againstnaare allFalse.nagoes to the end of a
numeric array and to the front of a string one.array.standardizeraised onnaelements instead of skipping them.- The percentile functions raised on an empty array and disagreed between their
arrayand
rollingtafaces about annapercentage. array.fillthrough a slice wrote nested lists into the parent array.time(timeframe="1M", timeframe_bars_back=1)landed in the month before the intended
one — always on the first of a month following a 30-day one, and on the first three days
of March — because the offset subtracted a month's nominal 30.4375 days before snapping
to the grid. A positive offset walks the grid one bar at a time now.color.rgbrejected everything but integers in 0-255. Measured on TradingView: a
fractional channel is truncated (127.5gives127), an out-of-range argument is
clipped, and annaargument counts as 0 for a channel and as fully transparent.strategy.orderran the backtest-only lot floor unconditionally, so in broker mode a
positive sub-lot quantity vanished before an intent was built.
Internals and docs
- The
naguards use the single positive testnot (x == x), which catches both
representations in one comparison. Measured on the per-bar guard: 18.3 ns down to 5.8 ns
for a non-navalue, the case every bar takes.na(float)itself went from 0.147 s to
0.039 s per million calls. - The strategy tests now require the whole TradingView reference to be consumed. The
comparator is a context manager that pairs entry rows with exit rows up front, drops the
trade left open at the end of a backtest, and fails if a trade is missing from the tail
of a run. Measured on the current corpus: 14576 closed trades compared across 12 tests. - The library reference documents
nahandling, index coercion, copy behavior, array
views, string replacement, strategy parameters and drawing semantics;math.random,
array.new_tableandstrategy.opentrades.capital_heldare documented, and the
ta.kc/kcwparameter tables no longer disagree with the code.