v6.6.1
Highlights
Float na is now a native IEEE-754 NaN instead of an NA wrapper object. This removes
Python-level dunder dispatch from per-bar arithmetic and matches TradingView's own internal
representation. Non-float na (int, string, color, drawing ids, UDTs) keeps the NA object,
and NA(float) still works, so already-compiled scripts keep running unchanged.
Two new features land alongside it: a workdir-level symbol map that translates
TradingView-canonical symbols to your provider's native ones, and plugin name conflict
detection in the plugin CLI.
Features
Global symbol map
A new optional workdir/config/symbol_map.toml translates the TradingView-canonical symbols a
script references (NASDAQ:AAPL, BINANCE:BTCUSDT) into the provider-native symbols your data
files carry — so request.security() contexts resolve without an explicit --security mapping
on every run.
[symbol_map]
"NASDAQ:AAPL" = "capitalcom:AAPL"
"BINANCE:BTCUSDT" = "ccxt:BYBIT:BTC/USDT:USDT"
"NASDAQ:AAPL:60" = "capitalcom:AAPL" # per-timeframe override- New
pyne data map <tv-symbol> <provider-symbol>command adds or updates an entry, creating
the file with a documented header when absent and preserving existing entries and comments. - One entry serves both backtest (the
.ohlcvfile is derived through the provider's own
get_ohlcv_path, so per-provider naming overrides are honored) and live runs (a native
PluginSymbol). - A missing or malformed map file yields an empty map — it never breaks a run.
- Explicit
--securitymappings still win; the global map is the fallback. pyne run --list-datanow reports, per cross-symbol requirement, whether the map
resolves it, which file that maps to and whether the file exists. For a mapped-but-missing
file it prints a ready-to-runpyne data downloadcommand; for an unmapped symbol it lists
existing data files whose ticker matches, ignoring the exchange prefix.- Documented in
docs/overview/symbol-map.md, with pointers from the configuration and
request.security()pages.
Plugin name conflicts
Two installed packages can declare the same pyne.plugin entry point name. That used to
silently resolve to whichever one importlib.metadata returned first.
pyne plugin listnow shows every package declaring a name, flags the conflicting rows and
prints aName conflicts:block naming the packages involved.pyne plugin info <name>refuses an ambiguous name, lists the packages that declare it and
tells you to uninstall all but one.- Loading an ambiguous plugin now fails with an explicit error instead of picking arbitrarily.
pyne plugin infofor an unknown name lists the available plugin names instead of guessing
pip installpackage names that may not exist.--jsonoutput gainedpackageandconflictfields.
PyneCore version requirement in plugin metadata
pyne plugin info now shows the plugin's complete PyneCore requirement (Needs PyneCore)
rather than only the lower bound. get_plugin_metadata() returns the full specifier as
requires_pynecore and keeps min_pynecore for the lower bound.
Performance
- Evaluating a bare
nain a compiled script drops from 112 ns to 4.3 ns:NA(None)goes
through the type cache like every other type,na()with no argument returns a module
constant, and the module-property transformer emits a constant attribute load instead of a
function call.na(x)predicate calls are unchanged. - Float arithmetic no longer dispatches through
NA.__add__and friends on na operands — the
operand is a native nan and the CPython float fast path applies.
Fixes
nz()now appliesna()semantics to floats:nz(inf, -5)returns-5(TV-verified).
Previously onlyNAobjects were replaced, so inf and -inf passed through.!=keeps TradingView semantics on na operands. A new load-time transformer rewrites!=in
loaded scripts tol == l and r == r and l != r, sona != xstays falsy now that float na
is a native nan. Because the rewrite happens at load time, previously compiled scripts get
the correct semantics without recompilation, and compiled sources keep the readable
(l) != (r)form. Complex operands are walrus-bound so side effects evaluate once.mapcanonicalizes nan keys to the interned constant, so an na key stays storable and
retrievable.fixnandetects nan-only holes and passes inf through, matching TradingView.- Typed series carry their element type through the slot layout, so a float series returns nan
(not anNAobject) for out-of-range history reads. - CSV writer canonicalizes nan as
NaNincluding extra columns; the reader accepts lowercase
nan. safe_intcatchesValueErrorandOverflowErroron nan input;cast_bool,cast_intand
cast_floatgained nan branches;math.floorandmath.ceilhandle nan;_format_number
emitsNaNbefore the Decimal quantize step; drawing coordinate builders handle nan.safe_divreturns raw inf, -inf or nan on a zero denominator instead of valued-NA
singletons — native IEEE semantics now provide the same behavior.- The persistent transformer emits a
lib.na()call for a missing initializer instead of a
bare name that resolved to theis_nafunction. - Sorted-based reducers in
ta,math,array,matrix,strategyandstringfilter nan
explicitly rather than relying onNAobject identity.
API changes
- New:
discover_plugin_entry_points()returns every entry point per plugin name
(dict[str, list[EntryPoint]]);discover_plugins()is unchanged and still returns one. - New:
get_plugin_package(),normalize_package_name(),parse_pynecore_requires(),
parse_pynecore_requirement(),min_pynecore_version(). - Removed:
na_inf,na_neg_infandna_nanfrompynecore.types.na— the valued-NA
machinery they belonged to is gone, native inf/-inf/nan replace them. - New:
isna_num()inpynecore.types.na. ScriptRunneraccepts aconfig_dirargument, used to load the global symbol map.