This release is about numerical fidelity. Most of the rolling machines in ta.*, the
math.sum accumulator, the string formatters and Pine's float comparison rule were
measured against TradingView and reimplemented to match it bit for bit, so a script's
numbers now line up with the chart instead of merely being close. Alongside that, the
OHLCV v2 format learned the symbol's tick grid, atomic file publication works on Windows,
and several strategy-emulator and accounting bugs are fixed.
Because so much of this changes the last digits of computed values, the notes start with
what will look different after upgrading.
Behavior changes
- Comparison operators in scripts are now tolerant. TradingView compares floats with
an absolute 1e-10 tolerance at every magnitude, boundary included.<,>,<=,>=,
==and!=in Pyne code are rewritten to that rule by the new
FloatToleranceTransformer, which replacesNeGuardTransformerin the pipeline.
Integers keep exact semantics. Conditions that sat on a razor's edge may now flip. ta.*results change in the last digits. Every machine listed under Fixes below
now reproduces TradingView's own arithmetic. Golden-value or snapshot tests written
against previous PyneCore output will need to be refreshed.str.tostringandstr.formatprint different digits. Both start from the shortest
decimal that reads back as the same double, so
str.tostring(0.1, "#.####################")gives0.1and not0.10000000000000000555.- Plot CSV output is full precision. The writer's default float format is the shortest
round-trip string instead of 8 significant digits, so exported values carry more digits
than before. The plot writer also echoes the bar the script actually saw rather than the
raw candle. - OHLCV v2 header is now minor 1. Files written by this release carry the tick grid in
the previously reserved eight bytes. Readers accept any minor at or below their own, so
6.8.0 reads older v2 files, but PyneCore 6.7.x cannot read files written by 6.8.0. OHLCVWritertakes the tick grid as two integers. Themintick: floatkeyword is
replaced byminmove: int/pricescale: int, so fractional grids like 25/1000 or 1/32
stay exact.set_tick_info()lets a provider declare the grid after construction.Persistent +=accumulates naively. The transformer no longer turns augmented
assignment into a Kahan sum; TradingView accumulates plainly, and the compensated
version was a systematic divergence in every compiledvar x = 0.0; x += y.- The private
_alphaparameter ofta.emais gone.ta.rmano longer rides on
ta.ema; it runs Wilder's own step.
Features
- Pine's tolerant float comparison implemented from a single definition in
core/pine_compare.py, at both the operator layer and in the builtins measured to
compare tolerantly (ta.rising,ta.falling,ta.cmo,ta.mfi,ta.percentrank,
array.includes,array.indexof,array.lastindexof,array.percentrank). Builtins
measured to be exact are deliberately left exact. Adds EPSILON-aware lower/upper bound
helpers. - OHLCV v2 stores the symbol's tick grid in the header. On write, a price off the grid
promotes its column from an f32 delta to an absolute f64; on read, a delta-decoded price
within the f32 encoding error of a grid point is snapped onto it, so65399.99comes
back exactly instead of65399.990000000224. - Atomic file publication on Windows. The new
core/_file_iomodule opens files with
delete sharing, publishes throughFileRenameInfoExPOSIX-style renames with an
os.replacefallback, and provides one exclusive file lock overflock/LockFileEx.
Theruncommand's download lock is no longer a no-op off POSIX. - Volume clean-up is decided per feed:
OHLCVReaderexposeslossless_volumeand
ScriptRunneraccepts it, so a v2 file's absolute f64 volume is used as served. The
security child reads it from its own feed, since a context can run on a different file
and format than the chart. - The demo OHLCV generator produces more realistic markets: clustered volatility, trend
variation, gaps, wicks, mintick rounding and range-based volume with quieter weekends. - Library reference documentation updated: chart points, lookahead modes, request
fallbacks, namespaces, plus newsplits.mdandticker.md.
Fixes
TradingView exactness
math.sumreproduces TradingView's rolling compensated accumulator, including the exact
re-baseline rule (fixed-order Fast2Sum residue of the magnitude-shifted add). Length
changes rebuild the window from history instead of restarting the warmup.ta.smadrops itsround(..., 15), which broke the match on 17451 of 22282 EURUSD 60m
bars.ta.emasteps withprev + alpha * (source - prev);ta.rmaruns Wilder's own step.
ta.atr,ta.rsi,ta.macd,ta.tsiandta.dmibecame exact with them.ta.wmare-sums the whole window oldest-first every bar, and its na window is
forward-filled rather than compacted.ta.hmabecame exact as a result.ta.variance,ta.stdevandta.correlationmoved onto the measured expressions over
the exact rolling-sum machine.ta.devgrows its buffer so lengths beyond the default
max_bars_backstay addressable.ta.linregrecomputes its window per bar and anchors the line the way TradingView does;
the previous rolling update drifted to 1e-11.ta.mfiforms the money ratio first, which fixes 38% of bars, and applies the comparison
tolerance to the money-flow sums.ta.stochno longer clamps, so a source on the window high can round just above 100.ta.rcirewritten to TradingView's pipeline: min-anchored tie clustering, 0-based
average ranks and moment-form variances.ta.percentile_nearest_rankandta.percentile_linear_interpolationorder their window
tolerantly, so a window holding near-equal values returns the same element as
TradingView.ta.changedrops bothround(..., 14)calls; TradingView subtracts the raw doubles.math.avgmatches TradingView's two-branch sum: plain up to two arguments, Kahan with a
flush from three on.str.tostring/str.format: 16-digit fraction cap in plain notation, half-up for
tostringand half-even forformat, and a mask with required decimals drops a zero
integer part, so"#.0"formats0.5as.5.ta.cmoandta.mfino longer raiseZeroDivisionErroron a flat source; they return
naand100respectively, as measured.
Strategy and accounting
- A limit order the bar gaps past no longer takes market slippage. It fills at
max/min(limit, open), the price the intrabar walk would have given it, while a
gap-triggered stop keeps its slippage (#74). strategy.position_avg_pricere-weights the previous average when a position is
pyramided instead of dividing accumulated cost by the new size.- The
cash_per_ordercommission is deducted from the closed trade's ownprofitand
profit_percent, and the win/loss/even counters and gross classification wait for the
final figure. - The big-money entry gate quantization gained decade-based grids, float32 offset
membership and sub-1e5 inflation handling.
Data and runtime
ta.crossno longer short-circuits:crossoverandcrossundereach keep their own
previous-bar relation, so evaluating one no longer leaves the other stale and misses the
crossing on the next bar.- Legacy float32 volume restoration is applied only to legacy feeds. Running it on a v2
file truncated real decimals (a Binance 30m volume of9362.123462came back as
9362.12346) and diverged a session'sta.vwapfor the rest of the day. The aggregator
applies the restoration per source bar so a resampled file does not carry float32 dust
into its sums. - PyCharm's enhanced numeric stubs are closed over arithmetic, so an arithmetic result
stored in a Pyne-typed variable is no longer flagged. Nothing changes under pyright.
Performance
ta.wma,ta.linregandta.devread their window through the new
ReadOnlySeriesView.oldest_first()as raw list slices and cache length-only constants;
the per-bar cost at length 500 drops about five-fold with a bit-identical accumulation
sequence.ta.percentile_nearest_rank/ta.percentile_linear_interpolationreplace the per-bar
full sort with a rolling window, 2.5x to 100x faster depending on length.- One
ta.smacall drops from 1811 ns to 686 ns.