v6.9.0
This build was never installable. The published package was missing a data file it reads at
runtime, soimport pynecorefailed withFileNotFoundError. Install
v6.9.1 instead — it carries everything
below plus the packaging fix.
Pine int is a static type — the runtime is double-only, like TradingView
TradingView runs every number as a double; int only exists in the type checker. PyneCore now
does the same: an int-typed value travels as a float carrying an integral value, na(int) is
a plain nan, and truncation happens at the slots that genuinely consume an integer instead of
at storage. This is what makes int-typed expressions with a fractional payload (14 / 8 is
int-typed and equals 1.75 on TradingView) behave identically here.
bar_index,last_bar_index,last_bar_time, thesyminfoint fields,input.int(),
time()/year()/dayofweek(),array.size(),str.length(),ta.barssince(), the
strategy trade counters andcolor.r/g/bhand back floatsSeries[int]andPersistent[int]slots store floats;NA(int)/na_intare the native
nan(pickling stays exact)int()in a script is Pine's cast (truncate toward zero,nastaysna); inside a
@pyne libmodule it is the lib's own native truncation- Truncation at the consumer:
range()arguments, the index or slice bound of a Pythonlist,
strortuple,Series[...]offsets,str.substring/str.replacepositions,
math.randomseeds,tablecoordinates,strategy.closedtrades/opentradesindexes,
array.new_intsizes,timeframe.from_secondscounts and drawing-object x coordinates - Storage preserves the value:
array.new_int(1, 7 / 4)holds 1.75, as on TradingView - The plot CSV export,
str.tostring,str.formatandlog.*print an integral value without
a fractional part; the OHLCV reader parses extra fields as floats Seriessubscripts take a float offset on a single fast path (a 60% slowdown on a for-loop
indicator measured during development is gone)
The consequences for hand-written Pyne code are documented under
Types — int:
a plain f-string shows bar=0.0, so format with str.tostring or a format spec, and use
round() where a genuine Python int is needed.
Static Pine type inference and overload pinning
A new analysis pass infers Pine's static types over the script and stamps them on the AST —
scalars, shaped containers (array<T>, matrix<T>, map<K, V>), tuples and user classes —
following the measured TradingView algebra (int op int stays int for every operator, division
and modulo included). On top of it:
- Overload calls are resolved statically and pinned, so an int-typed value with a fractional
payload still picks the int implementation; the per-bar dispatch becomes a cache read.
PYNE_NO_TYPE_PIN=1disables the pin. A pin position with no runtime witness takes a
wildcard instead of refusing the whole site. - An unannotated helper is typed per call-site context (the join of the default's type and the
argument's type, as TradingView does it); contexts that disagree carry the pin as instance data. - Modules publish a type interface (
__pycache__/<stem>.<hash>.pynetypes.json), imported user
libraries are typed from their declared signatures, and cached bytecode is dependency-aware:
a changed interface invalidates the importer's.pyc. - New
@pyne edgegate:PYNE_EDGE_STRICT=1rejects constructs outside the edge subset and
reports one diagnostic per typing failure, pointing at the user's line. Off by default; lib
modules are never gated.
Three-state bool as a per-script switch
Pine v4/v5 keep a bool that may be na; v6 has no such state. The choice now belongs to the
script: script.indicator/strategy/library(..., na_bool=True) keeps the three-state bool, the
default is v6's two-state bool. NA(bool) is False with the switch off and a real na with
it on; Series[bool] history, array.new_bool, UDT bool fields, ta.change and nz follow.
An exported library function runs with the bool semantics of the module it was defined in, and
a library UDT field defaulting to na(bool) follows the calling script's mode.
Fixes
math.round(number, precision)follows the measured TradingView rule: half away from zero,
the tie decided on the exact product with a 1e-10 tolerance, a fractional precision used
continuously, precision capped at 16, a negative precision clamped to zero. Exact against the
measured outputs for every precision up to 15.math.round_to_mintickdecides its tie-break on the native int tick pair, so the float
pricescale/minmovecannot flip a measured tie.- Rolling
ta.percentile_nearest_rank/ta.percentile_linear_interpolationfollow
TradingView's na rank order: an na keeps a slot of its own, the interpolation is
unconditional, and an na bar no longer blanks the result.ta.medianreturns the mean of the
two middles,ta.changetakes the bool branch first. strategy.closedtrades/strategy.opentradesaccessors handle annatrade number instead
of raising.box,labelandlinecoordinates normalize at the library boundary (x truncated to the
bar grid, y untouched).- Broker engine: teardown joins the event-stream task before closing the store and the
transport; resting spot exit legs are cancelled before a full close and OCA sibling fills are
recognized regardless of event order; a read outage no longer halts the run — overdue reads
are abandoned and new exposure deferred, with repeated outage warnings throttled; stale
pending partial legs are retired on a re-used entry id; a venue-attributed cancel on a
reduce-only bracket leg is trimmed like an OCA sibling instead of tripping the
unexpected-cancel policy; envelope anchors persist therun_tag(store migration 7) so a
rotated bot no longer misnames the previous bot's orders; a skipped partial bracket close is
logged and its legs re-armed. - Loader:
_lower_treereturns the allocated slot layout beside the tree for consumers that
build the state vector themselves.
Tests
- New
aot_unsupportedpytest marker for scripts that exercise constructs a compiled backend
cannot answer; harness helpers in@pynetest scripts carry the__test_helper_prefix.