Skip to content

v6.6.1

Choose a tag to compare

@wallneradam wallneradam released this 25 Jul 17:14
· 78 commits to main since this release

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 .ohlcv file 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 --security mappings still win; the global map is the fallback.
  • pyne run --list-data now 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-run pyne data download command; 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 list now shows every package declaring a name, flags the conflicting rows and
    prints a Name 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 info for an unknown name lists the available plugin names instead of guessing
    pip install package names that may not exist.
  • --json output gained package and conflict fields.

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 na in 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 applies na() semantics to floats: nz(inf, -5) returns -5 (TV-verified).
    Previously only NA objects were replaced, so inf and -inf passed through.
  • != keeps TradingView semantics on na operands. A new load-time transformer rewrites != in
    loaded scripts to l == l and r == r and l != r, so na != x stays 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.
  • map canonicalizes nan keys to the interned constant, so an na key stays storable and
    retrievable.
  • fixnan detects 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 an NA object) for out-of-range history reads.
  • CSV writer canonicalizes nan as NaN including extra columns; the reader accepts lowercase
    nan.
  • safe_int catches ValueError and OverflowError on nan input; cast_bool, cast_int and
    cast_float gained nan branches; math.floor and math.ceil handle nan; _format_number
    emits NaN before the Decimal quantize step; drawing coordinate builders handle nan.
  • safe_div returns 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 the is_na function.
  • Sorted-based reducers in ta, math, array, matrix, strategy and string filter nan
    explicitly rather than relying on NA object 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_inf and na_nan from pynecore.types.na — the valued-NA
    machinery they belonged to is gone, native inf/-inf/nan replace them.
  • New: isna_num() in pynecore.types.na.
  • ScriptRunner accepts a config_dir argument, used to load the global symbol map.