Changelog
Release notes for PYNE (hoox-pyne / pynescript).
This page
Manuals
[Unreleased]
[0.6.34] — 2026-11-09
Fixed
/ws/livescriptfull.countmatches the evaluated prefix. Opening snapshots used the ensure-window length while plots/series/bar_times(and later deltas) usedLiveSession.result()["count"]. AXIS then rejected every delta (count/base_indexvs cached length) and resubscribed — a full ~10k-point snapshot every tick._emit_ready/_emit_snapshotnow take count andbar_timesfrom the evaluated result. Pinned bytests/test_live_ws.py::test_script_full_count_matches_evaluated_prefix_not_ensure_window.- CORS preflight covers
/sessionand/data, and the datafeed allow-list includesX-AXIS-Client. AXIS live sessions hitPOST /session(outside the previous free CORS prefixes) and the standalone datafeed app omitted the client header fromAccess-Control-Allow-Headers. Pinned bytests/test_free_limits_trust.pyandtests/test_datafeed_app.py. - A hole in a stored series is healed without a client session. Missing minutes in the middle of an engine-owned series (a venue stall the feed jumped over, a walk that started after the stored anchor, a sparse
providebatch) make every script run over that window emit a Pinena— AXIS shows a gap in its indicators and logs "engine series stale (internal gap of N bars)" every minute. The tick path only filled one page per tick, and only while a data session was running: a quiet tab, or a hole the tick had given up on, left the series short of minutes until an unrelated full fetch happened to cover it. Two changes:- Give-up is now a cooldown, not a life sentence.
_gap_failuresrecords when a hole last failed, and_GAP_RETRY_S(300s) re-arms it; a transient upstream error used to block that hole start forever. - Background healer (
backend/api/gap_healer.py, started with the app). EveryPYNE_GAP_SWEEP_S(60s) it takes the recently written series (PYNE_GAP_ACTIVE_S, 900s) and fills up toPYNE_GAP_HEAL_MAX_PAGESpages into the widest hole (PYNE_GAP_HEAL_MAX_SERIES, 4 series/sweep) through the sameheal_series_gapsused by the tick path.PYNE_GAP_HEAL=0opts out; the sweep never raises, never blocks a request, and is skipped under pytest so a test's deliberate hole is never filled mid-case. SeriesStore.holes()/SeriesStore.active_keys()expose the internal holes (oldest first; series bounds are not holes) and the recently used series the sweep needs. Pinned bytests/test_gap_healer.py(15 cases: hole detection, edges, the cooldown, a session-less fill, upstream failure accounting, sweep selection, the off switch).
- Give-up is now a cooldown, not a life sentence.
Added
POST /runoptionaltimeframe. AXIS chart intervals (1m/1h/1d) and Pine periods (15,60,D) are accepted onRUN_SCHEMAandWS /ws/run. Empty/omit keeps the Runtime daily default. Exchange forms map the same way as pyne-workerto_pine_period(1m→"1", not monthly"1M"). Extra keys still →UNKNOWN_FIELDS./ws/liveencoding: "axb1-full". Opt-in AXB1 mode that also sends script snapshots (SNAPSHOT_PLOTS), single-bar plot deltas (PLOT_TIP), and multi-bar candle deltas (APPEND_BARS, a new columnar opcode).encoding: "axb1"remains the safe default with unchanged behavior, and any unsupported shape still falls back to JSON. The sharedtests/data/axb1-vectors.jsongolden suite now pins theAPPEND_BARSlayout.
Changed
- LSP hover / suggest cards. Kind kicker is an inline-code chip (
`function`) instead of italics, so AXIS Void / HOOX Signal / PYNE VolttextPreformatpaints it. Parameter and field lists with descriptions render as two-column Markdown tables.
[0.6.33] — 2026-11-04
Added
- Hosted runner resilience + audit.
PYNE_RUNNERticks now schedule per script: a timeframe due gate only fetches once the next bar can have closed (a1wjob is no longer polled every 60s), failed fetches/runs back off exponentially (60s doubling, capped at 30 min,forcebypasses), and every ok / error run is appended to a per-script audit log —GET /cron/history?script_id=&limit=,pyne runner history, and MCPpyne_runner_history. NewPYNE_RUNNER_WORKERS(default 2) runs tick jobs in a thread pool so one slow script cannot serialize the fleet. Webhook forward failures are persisted in cron state (last_forward_status) and history instead of only logging. - Redis runner store for multi-replica deployments.
PYNE_RUNNER_STORE_BACKEND=redis(REDIS_URLrequired) shares deployed scripts, cron state, and run history across API replicas; ticks serialize with aSET NXtoken instead of the filesystem flock. Default stayssqlite(single host)./healthreportsfeatures.script_runner_store;backend/runner/store.pyis now a backend-dispatching facade over its SQLite implementation orbackend/runner/store_redis.py(fake-client testable). - Runner cron state is now merge-written. Partial patches (e.g. a
fetch_failedstatus) no longer wipelast_bar_time/last_alerts.
Fixed
- Runner
fetch_failedstate reset. A failed fetch used to clear the recorded last bar time, forcing a needless re-run on the next tick.
[0.6.32] — 2026-11-02
Fixed
- documentSymbol on generic types. Typed locals such as
array<float>andmap<string, float>no longer crashtextDocument/documentSymbol(Specialize.argsis an expr, not a list). Outline still returns any symbols already collected if a later visitor step fails.
Added
- VS Code extension 0.5.6. VSIX re-pack for the outline fix; language server still comes from
hoox-pyne(python3 -m pynescript.langserver).
[0.6.31] — 2026-11-02
Added
- Compose
datafeedandmcpdaemons. Dedicated CCXT gateway (backend.datafeed_app, gunicornGUNICORN_APP) on host:5004and PYNE MCP (streamable-http) on:5003. Both start withdocker compose up/make docker-prod. MCP image is Dockerfile targetmcp. - GHCR
mcpimage.v*tags publishghcr.io/hoox-sh/pyne/{api,cli,lsp,mcp}:X.Y.Z(and:latest). Smoke importscreate_serverplusmcp/uvicornbecausepynescript.mcpis lazy. - VS Code extension 0.5.5. Marketplace / Open VSX / GitHub Release VSIX for the AXIS-matched hover, suggest, and peek chrome.
- VS Code TextMate bitwise operators. The Pine grammar now scopes
&,|,^,~,<<, and>>(Pine v6) without changing existing comparison/assignment tokens.#line comments highlight only when the rest of the token is not a#hexcolor literal. - VS Code snippets.
ta.macd,ta.bb,strategy.exit,for ... in(pineforin),input.color,input.timeframe, andinput.session. - Extension Development Host launch configs. F5 PYNE: Run Extension / Extension Tests (
type: extensionHost) from the repo root orvscode-extension/;npm run edh/test:edhdrive the installedcodethe same way.
Fixed
pynescript.selectSyntaxis now a contributed command (palette entry was previously dangling).- Extension test runner path and mocha harness (Electron runner skips the node:test manifest suite).
- docker
lsp.commandwith empty args gets a defaultdocker run -i --rmGHCR image; convert-to-v6 Python fallback recognizes Windows interpreters. - Prod compose starts every service.
make docker-prodandscripts/deploy_vps.shpassedapi(optionallyredis) todocker compose up, which leftlsp/clidown and skipped those image builds. They nowup --build -dthe whole project with profileslspandcli. Redis is a default daemon (ports still unpublished). - Datafeed body cap and session recycle. Standalone
datafeed_apprejects bodies over 5 MB (same as the Pro API). Prod datafeed setsGUNICORN_MAX_REQUESTS=0so in-process RAM sessions survive worker recycle. Nginx reloads only after api + datafeed are healthy.
Changed
pyne-mcp/pyne mcphonorPYNE_MCP_TRANSPORT(stdiodefault,sse/streamable-httpwithPYNE_MCP_HOST/PYNE_MCP_PORT). Compose pinsPYNE_API_URL=http://api:8080so a host export cannot point the container at production.- VS Code hover / suggest / peek chrome matches AXIS popovers: 1px hairline, void plates, accent selection, AXIS panel shadow, and inlay / ghost / parameter-hint / menu / notification cards across AXIS Void, Hoox Signal, and PYNE Volt. Hover and completion Markdown share a kind kicker, fenced signature, and docs-link footer.
- VS Code extension TypeScript host split into focused modules (
config,syntax,install,backend,lsp); workbench-theme switching remains off. - Mintlify vscode-extension page pins
vscode-languageclient^11 (matchesvscode-extension/package.json) and documents PYNE: Select Syntax Highlighting, bitwise grammar, and the new snippets. Inlay copy no longer implies type hints orinlayHint/resolve. - VS Code command descriptions, categories (Snippets, Themes),
.pinescriptworkspaceContains.
[0.6.30] — 2026-11-01
Added
- Visual Studio Marketplace. First listing of
hoox-sh.pyne0.5.4 viavsce publish(VSCE_PATonhoox-sh/pyne). Open VSX and the GitHub Release VSIX stay in place. - Scope-aware LSP semantic layer. New
langserver/analysis.pybuilds a Pine scope tree, declaration/member index, exact identifier ranges, and conservative type inference from the same ANTLR4 → ASDL AST. Completion now offers local variables/parameters/functions, UDT fields/methods, enum members, type constructors, imports, and built-in variables; hover shows inferred types and UDT members; definition/references/highlight/rename respect shadowing and return precise ranges. - Version-gated v6 lint rules. W104 (
transp=/strategy.* when=) and W105 (numeric boolean conditions) only run on//@version=6; v4/v5 scripts no longer get false positives. W101/C001 mask comments and string literals. - Style diagnostics are opt-in.
pynescript.diagnostics.styledefaults tofalse; C001/C002/C004 remain available to CLI users and editors that enable them. - Live editor settings.
initializationOptionsandworkspace/didChangeConfigurationnow drive formatting, snippets, diagnostics, inlay-hint types/parameters, and semantic-diagnostic gates without restarting the client. - Inlay hints are filtered to the requested range, support user function/method parameter names, use real metadata signatures, and are display-only (no type injection).
- Semantic tokens include user references, parameters, fields, methods, enum members, and imports in addition to declarations.
- Opt-in semantic diagnostics.
pynescript.diagnostics.semanticenablesS001(unknown field/method on a usertype, unknown member on a userenum) andS002(user-function call arity or parameter-name mismatch). Builtin calls and unknown receiver types are skipped, so the checks stay quiet on incomplete catalogs. - Metadata generator derives signatures/snippets/parameters from handler introspection,
_KWARG_ORDER,_TA_KWARG_ORDERS, and docstrings; regenerated plaintext + Fernet artifacts.
Fixed
- API error bodies drop traceback frames and source paths (
_sanitize_error_for_response); session/runner exception JSON uses a one-line client message. - vscode-extension
minimatchis overridden to^11.0.1(GHSA-g3hv-75wg-m249 globparts DoS). - CodeQL ReDoS on C001 trailing identifiers and hover
@taglines — both are linear scans now, not user-controlled regex. - PDF mermaid entity decode unescapes
&last so&lt;is a single-level decode. - TradingView® loop-args SMA. One
ta.smacall site reached several times per bar with different sources (ta.sma(close[i], n)inside afor) now shares a single history window and replaces the current-bar sample — TradingView®'s rule.published_patternon the vendored OpenPineScript goldens is green; 112 / 112 columns pass. - Stale-AST race.
didChangeupdates source immediately; features no longer combine the new text with the previous AST. Parse results commit only if the document version/source still match, and published diagnostics carry the document version. - Destructive formatting. The unparser drops prose/block comments, so commented buffers now use a safe whitespace pass (trim trailing spaces, normalize the final newline, leave multi-line strings alone) instead of deleting trivia or returning nothing. Range/on-type formatting applies the same pass and still refuses line-structure changes. C002 does not offer a format QuickFix when comments are present.
- Parse diagnostics use structured
SyntaxErrorDetailswith a non-empty range instead of a zero-width error at column 0. - W101/W104/W105 QuickFixes. W101 rewrites v4
security(...)torequest.security(...). W104 deletes the v6-removedtransp=/when=argument (multi-line calls included) and refuses when the removed span contains a comment; W105 rewrites the numeric condition asliteral != 0. All are verified by re-parsing before being offered. - W105 ranges now underline the numeric literal instead of the
if/whilekeyword. - UTF-16 / CRLF positions. Request positions and result ranges convert at the server boundary, so emoji or other non-BMP characters earlier on a line no longer shift hover/completion/navigation/semantic-token columns. Incremental
didChangeedits convert before slicing, preventing buffer corruption; diagnostics and rename edits across open documents convert per file. ASCII/LF buffers skip the pass. - Signature help no longer falls back from
obj.sma(tota.sma; it resolves exact builtins and UDT methods, and clamps the active parameter. - Fuzzy completion cache now actually caches the item list and lowercase fields instead of rebuilding them per keystroke.
- Format on save runs before the write via
vscode.executeFormatDocumentProviderrather than formatting after the file is saved. - Large documents (> 40 KB) parse off the event loop on open/save so completion and hover stay responsive.
Removed
- Inferred type injection from inlay hints.
inlayHint/resolveis no longer advertised or implemented, type hints carry nodata, and hints never emittextEdits. Inlay hints remain display-only (assignment type labels and parameter names), so applying a hint cannot modify the script.
Changed
- VS Code themes tuned for calm reading. Brand accents stay exact (void indigo
#939FFF, volt lime#B7EF09, orange signal#FE6A00); the extra green / cyan / amber token hues are gone. Comments — including//@…annotations — are neutral gray italic in every theme, strings are a light accent tint, numbers use the foreground, and punctuation / series builtins are gray. Surfaces and hairline borders are darker, and the hover / autocomplete widgets sit on dark-grey panels. - Themes renamed to the product names — AXIS Void, Hoox Signal, PYNE Volt (
pynescript.syntaxHighlightingvalues:none·void·signal·volt; legacyorangestill resolves tosignal). - Workbench theme switching disabled. The extension no longer writes
workbench.colorThemeon activation, install, or settings change.pynescript.themeand the PYNE: Select Workbench Theme command are commented out for now; the three themes remain contributed and selectable from VS Code's own Preferences: Color Theme picker. - Settings regrouped and rewritten into
PYNE: Appearance,PYNE: Language Server,PYNE: Editor Features,PYNE: Installation, andPYNE: Pro & Backend, ordered by how often they are changed. Descriptions now state the default, thenonebehaviour, and cross-link related keys.
[0.6.29] — 2026-11-01
Changed
- Inferred-type inlay hints removed entirely. The language server never annotates declarations anymore — inlay hints are parameter names only. The
show_typespath, its inference helpers, and theinlayHintsTypesserver/extension setting are gone; clients that still send the option are ignored. VS Code extension 0.5.4 dropspynescript.inlayHints.types. - Strategy broker parity overhaul (reference Pine). Market orders placed during bar N fill at the open of bar N+1 (pending market orders,
process_pending_ordersat bar start); fills quote on thesyminfo.mintickgrid and resting order prices round outward (away from the mark); reversal closes emit acloseevent withreversecomment at fill time on both hosts; entry comments propagate toopentrades.entry_comment; same-bar orders stay inert on their placement bar;strategy.exitbrackets placed against a not-yet-filled entry soft-no-op. Event flow per fill:entry/closethen afillorder event — both hosts stay in lockstep. - Reference-Pine defaults and
nasemantics.strategy()initial_capitaldefaults to 1,000,000;na(x)unwraps series/scalar wrappers before testing;fixnancarries the last non-nasample per call site (Pine does not seed with 0). - Parity fixtures regenerated (
tests/fixtures/parity/json/*.json) for the new event flow; the trail/restore goldens, risk day-resume bars, and dual-host lock tests updated to next-bar-fill semantics. ⚠️ The TypeScript event oracle (pine-worker/src/evaluator/events.ts) must mirror the new placement/fill flow. - VS Code extension README uses the HOOX brand header, documents the deployment-mode feature matrix (hosted Pro key / self-hosted local, remote, edge / none), and recommends PYNE MCP for agent hosts;
vscode-extension/FEATURES.mdcarries the full matrix.
Fixed
- SAR incremental state out-of-bounds write —
numba_sar_incgrew to a 10-float state but tests still allocated 5, corrupting the heap on rewind (double free or corruption/ SIGABRT in the test process). tests/test_corpus_runtime_expected_fail.pystill loaded classification helpers from the old thin CLI script; they moved topynescript.util.corpus_runtimein the parity-harness commit.- Stale supertrend warmup assertion —
ta.atr's RMA seeds via SMA, so the first non-na ATR lands on bar indexperiod-1, notperiod. 2492_ind_pdf_01_reversal_radar_v2corpus test — the file is a mis-collected planning markdown with no Pine body; compile now fails honestly per the fail-honest stub policy.- Lint clean: PLW2901/PLW3301 fixes in
fixnanand SAR clamp windows.
[0.6.28] — 2026-10-31
Added
- VS Code extension 0.5.3 — separate workbench theme and syntax highlighting.
pynescript.theme(workbench UI + hover cards;none/void/volt/orange, defaultnone= keep the user/system theme) andpynescript.syntaxHighlighting(Pine TextMate + semantic tokens;none/void/volt/orange, defaultvoid,none= active theme) are now independent settings with their own commands: PYNE: Select Workbench Theme and PYNE: Select Syntax Highlighting. Both acceptnone.
Changed
- Removed
pynescript.theme.applyWorkbench; settingpynescript.themetononesupersedes it. - Syntax palettes are applied as language-scoped
[pinescript]editor.tokenColorCustomizations/editor.semanticTokenColorCustomizationsloaded from the bundled theme JSON, so they work with any workbench theme.
[0.6.27] — 2026-10-31
Added
- VS Code extension 0.5.2 — PYNE product themes. Contributed PYNE Void, PYNE Volt, and PYNE Orange color themes matching the HOOX color packs and the AXIS editor's syntax roles (keyword → accent, string → green, number → amber, builtin → cyan, library → purple, type → amber). Hover and autocomplete widgets use the selected theme;
pynescript.theme+ PYNE: Select Theme switch between them. - README: Mermaid pipeline diagram, compact feature table, dedicated MCP section; removed the dated corpus snapshot.
Changed
- Extension token colors now come from the contributed themes instead of hardcoded
editor.tokenColorCustomizations.
[0.6.26] — 2026-10-31
Added
- VS Code extension 0.5.1. Library annotation hover cards (
//@function,//@param,//@returns,//@type,//@field,//@variable,//@description) with multi-line Markdown continuation; per-feature settings and toggle commands for every LSP capability; Pine snippets; semantic-token theme defaults; diagnostics severity mapping; format-on-save; auto-install ofhoox-pyne[lsp]with automatic venv creation for PEP 668 Python; backend URL + hostedpynescript.onlinetoggle; Install/Start/Test Backend commands; ESLint flat config and@vscode/test-electrontests. hoox-pyne-backendwheel. Standalone backend distribution (packages/backend) that packagesbackend/and exposes thepyne-backendconsole script;backend.app:main()andbackend/__main__.pymakepython -m backendwork from a pip install.- Pyodide engine 0.6.26. AXIS vendors the rebuilt
pynescript-0.6.26browser wheel.
Changed
make packagebuilds the main sdist/wheel and the backend wheel; newmake build-backend-wheel.- Docs updated for the extension release, backend wheel, and library annotation hover.
[0.6.25] — 2026-10-31
Fixed
- Selector-UDF string misclassification. A single UDF whose first param merely selects by string (
ma(type, src, len)) was misclassified as string-returning by the overload branch of_call_returns_string, so the result series became a string buffer andclose > upperkcompared Float64 vs Str (UFuncTypeError: ufunc 'greater') — or leaked an object array into an njit call (TypingError: non-precise array(pyobject)). Only a genuine multi-impl overload set now trips the string branch. (7 set05 scripts) - Tuple-returning builtin stored to a single var.
macdValue = ta.macd(...)treated the raw tuple as a float64 scalar →ValueError: setting an array element with a sequence._is_safe_numeric_exprnow rejects tuple-returning numba builtins (macd/dmi/supertrend/bb/kc/stochrsi/aroon/vwap) unless the expr is explicitly indexed(...)[k], wrapping the store insafe_float(first element). (3 set05 scripts) - UDF declared after a same-named input.
maType = input.string(...)followed bymaType(src, ...) =>rebound the Python def, so everymaType(...)call raised'str' object is not callable. Top-level UDF names are now hoisted before the body walk so the input renames tomaType__locwhile calls still resolve to the function. (2 set05 scripts) - Drawing/table handle classified as a UDT series. A
{'kind': …}drawing/table dict tripped_looks_like_object_handle_exprand went through the UDT series branch (t_arr[__bar_idx]) before the drawing branch could make it a scalar handle. The UDT branch now skips drawing RHS. (1 set05 script) - Crossover with a
Nonelevel. A security-tuple stub level ofNonecrashedfloat(None)in_cross_pair. Object mode now emitsna_num(level)(None → nan); njit numeric levels stay a barefloat()cast. (2 set05 scripts) - User array named
X_arrcolliding with a series buffer.var float[] ph_arrand the series buffer forbool ph(alsoph_arr) lowered to the same Python identifier, so the per-barph_arr[__bar_idx]write hitIndexError: list assignment index out of rangeon the user's short list. The user handle is renamed toX_arr__hdland threaded viaident_map. (8 set05 scripts)
Tests
tests/test_set05_corpus_regressions.py. Locks all five compiler defects above with minimal reproduction cases (transpile assertions + compile/run parity), bringing 22 previously-failing set05 corpus scripts to green.
[0.6.24] — 2026-10-26
Added
pyne corpusCLI. Rich front-end over the Runtime corpus engine (list+run) for set01–set06. Modes: interpret / compile / auto / parse. Shared engine lives inpynescript.util.corpus_runtime(scripts/corpus_run_runtime.py is a thin wrapper).
Changed
- Rich CLI volt palette. Shared
pynescript.util.rich_themetracks the HOOX landing/pynedata-color-pack=volttokens (accent#B7EF09, muted#9E9F98, border#3D3E37, fg#EEEEEE). Used bypyne/corpus/download-builtins/scripts/showcase.py.
[0.6.23] — 2026-10-26
Fixed
ticker.new(prefix, ticker)TV idiom.ticker_newnow follows TradingView®'s(prefix, ticker, session, adjustment)signature and joins toPREFIX:TICKER(one-arg full-symbol shorthand still works).request.security(ticker.new(syminfo.prefix, syminfo.ticker), …)matches the chart symbol instead of returning foreign na. Compile emit joins two-argticker.newthe same way.mode=compileno longer swallows parse errors.compile_scriptrefuses the corpus_MINIMAL_STUBsubstitution when the raw input is not already that stub, so garbage like@@@not pinefails witherror_kind=parseunder both interpret and compile.- Docs no longer describe the brand kit or Cloud Build. The README banner, the GCP page, and the
cloudbuild.yamlsections are gone./devops/gcpredirects to the Docker page. - Optimizer TPE follows the out-of-sample score. Holdout and walk-forward trials were split into TPE's good and bad sets by in-sample score, so the next suggestions walked the training peak. The split now uses
oos_scorewhen the trial has one, andis_scoreonly when it does not. - Cloudflare® Container setup. The readiness probe is
localhost/health(http://${pingEndpoint}; a bare/healthnever reached Flask). Gunicorn in the container matches the production entrypoint (gthread, 1 worker, 100 threads, 120s timeout, max-requests 5000). A WorkerADMIN_TOKENsecret is copied into the container when the instance starts. Wrangler incf/is 4.152.0.
Tests
- Coverage wave 3. Compiler emit/engine edges (array/matrix/map/UDT/switch/strategy compile scripts + interpret↔compile parity smokes), deeper
request.*/ host packing paths, arrays/strategy/TA-core helpers, backend app auth/404/stats edges.tests/test_known_bugs_regression.pylocks the two defects fixed above. - Coverage wave 2. Direct
numba_builtins*_inckernels (SMA/EMA/RSI/MACD/ATR/…),request.*/ drawing / Runtime host edge suites, LSPserver.pyhandler coverage (~99%), TAcommon.pyhelpers, statements/expressions Runtime edges, plus host/pine_facade pure helpers. - Broad unit coverage expansion. New suites pin previously thin modules: shared
strategy_risk_core, MCP serialize/catalog/dispatch/ops (optimize/runner/builtins), Redis/SQLite key-store fakes, backend services (backtest/chart render) + schemavalidate(), optimize space/objective/events edges, chronologicalseries_buffer, LSP protocol utils/workspace helpers, corpus sanitizer pure helpers, datafeed util/poll paths, runner CLI HTTP client, numeric/string/timeframe/utility Runtime edges, and AST error/visitor/collector/type_system.
[0.6.22] — 2026-10-25
Added
- VS Code palette toggles (VSIX 0.4.5). Toggle Diagnostics / Toggle Completion flip
pynescript.diagnostics.enabledandpynescript.completion.snippets. Toggle Inlay Hints, Toggle Folding, and Toggle Color Preview flip[pinescript]editor overrides (editor.inlayHints.enabled,editor.folding,editor.colorDecorators). Diagnostics off swallows squiggles client-side and clears the collection. Color preview is a real on/off (it previously only turned on, and inlay/folding wroteformatting.enabled).
[0.6.21] — 2026-10-25
Fixed
- A clamped series tick fills one page of the hole it skipped. When the stored anchor was older than
TICK_MAX_BARS, the tick wrote only the recent window and then treatednewestas current, so the minutes in between stayed missing (the Donchian axis hole). The hot walk is still clamped. After it, one page of the widest internal gap is written, andstalestays true so the client reloads the session. A start that adds no bars is abandoned after three tries. A week-long stall is still not a 200-page walk. request.currency_rate0/1-arg IndexError. The honest-NA rewrite guardedto_currencywithlen(args) > 0, so a short builtin-map call raisedIndexErrorinstead of defaulting to"EUR". Restoredlen(args) > 1.- Purge cascade walks the session journal.
drop_by_keyonly scanned in-memory sessions; a journaled-but-unloaded id survivedDELETE /data/seriesandresumerebuilt the thrown-away window after a worker recycle. Matching journal rows are now dropped too. - Stale pool recreate notifies remaining subscribers. Dropping a pooled session whose store window moved on publishes
SESSION_GONEso other tabs re-ensure instead of ticking a gone id. An empty store window is treated as stale. A feed batch against a released session emitsSESSION_GONErather than going silent.
Changed
pyne_sessionsis a true snapshot.describe_allno longer runs the idle TTL sweep, so an inspector pointed at the live journal cannot delete expired rows. Stringlast_timeanchors coerce forlag_bars/suspect.
[0.6.20] — 2026-10-24
Added
- MCP
pyne_axb1golden-vector check. Verifies the AXB1 encoder against the bundledtests/data/axb1-vectors.jsoncontract shared with AXIS (hex-exact per vector, fnv1a32 hash checks, codec reject-rule probes). Accepts inlinevectors/vectors_pathand anonlyname filter; callable in-process viapyne mcp call axb1. - MCP
pyne_sessionspool inspector (read-only). Snapshots every live session with its binding anchor against the store window:lag_bars, store bounds, and asuspectflag when the anchor is provably outside the store window (the pool-zombie shape). Optionalkeyfilter; never creates or drops sessions.
Fixed
- Stale pooled live sessions recreate instead of resuming.
ensure_live_sessionhits by content fingerprint, blind to the bars underneath: after a repair / replace / purge the store window could move hundreds of bars past a pooled session's birth anchor, and every resubscribe resumed the pre-repair window (overlays frozen on old bars across reloads and flushes). A hit lagging the store tail by more than the requested window now drops the entry and creates fresh over the current store; live sessions mid-tick keep sharing.DELETE /data/seriesalso cascades into the session pool (drop_by_key), so the purge no longer leaves bound sessions evaluating the window it just threw away. Pinned by a stale-recreate test, a healthy-share test, and adrop_by_keyunit test.
[0.6.19] — 2026-10-23
Added
-
Linter W104 (v6-removed kwargs). AST-based rule flags
when=onstrategy.*order calls andtransp=on drawing/plot calls (color.new/color()exempt) — both are ignored at runtime since v6 removed them. Surfaces in CLI,lint_script, and LSP diagnostics. -
Linter W105 (numeric literal in boolean condition). AST-based rule nudges
if 1/while 0/1 ? a : btoward an explicit comparison orbool()cast. The evaluator stays permissively compatible; strictness lives in lint, not runtime. -
export methodimport coverage.tests/test_library_export_method.pypins the full cross-script path (UDT + exported method viaregister_library_sourceand direct evaluation, alias construction, receiver-form call). -
String-interpolation scope +
booledge pins.tests/test_string_bool_edges.pylocks bare"{0}"staying literal,str.formatsubstitution,bool(na)/not na/na and/oredges, and permissive numeric conditions at runtime. -
strategy.risk.max_position_sizecontracts mode.PYNE_STRATEGY_RISK_CONTRACTS=1treats the value as an absolute contracts cap (reference Pine semantics) on both interpret and compile hosts; default stays pinned %-of-equity. Invalid values are ignored. Pinned bytests/test_strategy_risk_contracts.py(dual-host + invalid-input cases). -
strategy.entrypendingmax_fill_per_bar. Stop/limit entries now carry the kwarg into the pending book likestrategy.orderdoes, so large entries fill across bars on both hosts (default0= full fill, unchanged). -
AXB1 binary encoder + negotiated
encoding: "axb1"onWS /ws/live. Newpynescript.runtime.axb1— a pure-stdlib byte-for-byte mirror of the AXIS AXB1 v1 wire codec (axis/src/hp/axb1/encode.ts), pinned by the cross-repo golden vectors (tests/data/axb1-vectors.json, shared withaxis/tests/hp/axb1-vectors.json; 12 envelope vectors + FNV-1a hash checks asserted bytests/test_axb1.py).WS /ws/liveacceptsencoding: "axb1"onsubscribe: mappable frames (status, seriesfullsnapshots, forming re-tip deltas, closes, errors) leave asAXB1bytes; JSON remains the default, and unmapped frames (script frames, multi-bar deltas,idlestatus, control frames, anything without a subscription id) fall back to JSON untouched. A single-bar delta is classified re-tick vs append by the per-subscription cursor (bar time vs newest seen) because pyne's delta envelope is byte-identical for both — an append is never guessed as a tip.
Fixed
- Fundamental
request.*calls are honest-nawithout a provider hook.request.dividends/earnings/splits/financial/quandl/economic/currency_rateno longer return invented mock tables (hardcoded AAPL/MSFT values, static FX rates, canned Quandl/economic series) when no host supplies the data. Without afetch_fundamental(kind, symbol, **params)hook ondata_feed/data_provider(or a live feed FX pair forcurrency_rate) they returnnaand record afundamental_napolicy tag — matching the compile host, which already lowers these calls tona.request.seed(RNG utility) is unchanged. Pinned bytests/test_request_fundamentals_honest.py; mock-pinned assertions intests/test_evaluator.pyandtests/test_request_data_feed.pyupdated tona.
[0.6.18] — 2026-10-21
Added
- Public LSP docs for
documentLink/resolvetooltip.docs/pyne/lsp/features/document-link.mdxdocumentsdocumentLink/resolvefillingtooltipwith the URL when tooltip is unset (documentLinkProvider.resolveProvider=True). Architecture, VS Code extension, and LSP index capability tables list the resolve method. - LSP document-link resolve.
documentLink/resolvefillstooltipwith the URL. Advertised viadocumentLinkProvider.resolveProvider. - LSP 2-arg
ta.bbw(length, mult)parameter-name inlays.ta.bbw(20, 2)inlay aslength:/mult:(notsource:/length:). 1-argta.bbw(20)stayslength:; 3-argta.bbw(close, 20, 2)stayssource:/length:/mult:. - LSP arity-aware well-known parameter names. 1-arg
ta.cci/ta.adx/ta.mfi/ta.bbwinlay aslength:; 2-argta.cci(close, 14)stayssource:/length:, 2-argta.adx(14, 14)staysdiLength:/adxSmoothing:. - LSP well-known parameter-name inlays for more builtins.
textDocument/inlayHintuses Pine v6 names (ta.atrlength,ta.correlationsource1/source2/length,strategy.entryid/direction/qty,input.intdefval/title, plusta.cci/roc/mom/linreg/adx/mfi/bbw/dpo/crossover/crossunder) when metadata snippets are genericparamN. Existingta.sma/ema/… hints and assignment type hints are unchanged. - VS Code extension docs catch-up.
docs/pyne/lsp/vscode-extension.mdxdocuments the hostedpyne-lspmethods the 0.4.4 LanguageClient already forwards:textDocument/semanticTokens/range,textDocument/onTypeFormatting(trigger\n),textDocument/linkedEditingRange,inlayHint/resolvetype textEdits plus builtin parameter-name hints,textDocument/documentLink(http(s)in comments/strings), andtextDocument/documentColor/colorPresentation(#hex). GHCR example tagghcr.io/hoox-sh/pyne/lsp:0.6.19. VSIX remains 0.4.4. - Public LSP docs for documentLink and documentColor. Dedicated Mintlify pages
docs/pyne/lsp/features/document-link.mdx(textDocument/documentLinkforhttp(s)URLs in comments and strings) anddocs/pyne/lsp/features/document-color.mdx(textDocument/documentColor/colorPresentationfor#hex, namedcolor.*, and literalcolor.rgb/color.new/color()/color.from_gradient). GHCR client example tagghcr.io/hoox-sh/pyne/lsp:0.6.19. - LSP architecture and index docs catch-up.
docs/pyne/lsp/architecture.mdxanddocs/pyne/lsp/index.mdxnow list range semantic tokens, on-type formatting, inlay resolve plus parameter-name hints, linked editing, and document links. - Public LSP docs catch-up. Mintlify pages under
docs/pyne/lsp/features/now document hover Pine v6 function-reference links,textDocument/semanticTokens/range,textDocument/onTypeFormatting,inlayHint/resolveplus parameter-name hints, andtextDocument/linkedEditingRange. - LSP parameter inlay hints.
textDocument/inlayHintshows builtin parameter names before positional args (ta.sma(close, 14)→source:/length:). Assignment type hints andinlayHint/resolvetextEdits are unchanged. DELETE /data/seriesdrops one stored series. The engine's series store is its cache of the venue's OHLCV; a client that flushed its own dataset could not drop the engine's copy, so the engine kept serving the old (stale, holed) window. The route takes the same key fields asGET /data/seriesand removes the series' bars plus its metadata row. Per key only — the store is shared, so a purge never touches another series.- LSP inlay-hint resolve.
inlayHint/resolvefillstextEditsthat insert the inferred type annotation at the hint position. Advertised viainlayHintProvider.resolveProvider. - LSP on-type formatting.
textDocument/onTypeFormattingformats the just-completed line after newline using the same NodeUnparser as range formatting. Empty or unparsed documents return[]. Advertised viadocumentOnTypeFormattingProvider(trigger\n). - LSP linked editing ranges.
textDocument/linkedEditingRangereturns same-document ranges for the user ident under the cursor (keywords and builtin namespaces stay unlinked). Advertised vialinkedEditingRangeProvider. - LSP semantic tokens range.
textDocument/semanticTokens/rangereturns the same token legend as/full, clipped to the requested range. Empty or unparsed documents return an emptydataarray. Advertised viasemanticTokensProvider.range. - Bar-mode incremental
ta.volatility_regime(T2). Last-sample kernel matches full recompute: last-N numeric ATR samples →"low"/"medium"/"high"/"extreme"("medium"while the window is short). - LSP hover docs links. Builtin hover cards (
ta.sma,strategy.entry, …) include a markdown link to the public Pine v6 function reference. Keywords, types, and user declarations stay link-free. - Bar-mode incremental
ta.momentum_filter(T2). Last-sample kernel matches full recompute: last-N volume-weighted momentum (0.0while the window is short or volume_sum is 0). - Bar-mode incremental
ta.acceleration_factor(T2). Last-sample kernel matches full recompute: last-(period+1) momentum, clamp to [-2, 2], 0.0 while short or old_mom ~ 0. - Bar-mode incremental
ta.mean_reversion_score(T2). Last-sample kernel matches full recompute: last close/sma/stdev vs period warmup, score 0–100 (50.0while short or stdev is 0). - Bar-mode incremental
ta.market_condition(T2). Last-sample kernel matches full recompute: last close/atr vs SMA/stdev windows →"ranging"/"volatile"/"trending_up"/"trending_down"("ranging"while short). - Bar-mode incremental
ta.order_flow_imbalance(T2). Last-sample kernel matches full recompute: last-N buy vs sell volume (0.0while short or volume total is 0). - Bar-mode incremental
ta.volume_thrust(T2). Last-sample kernel matches full recompute: last close vs prev close and volume vs volume_sma (Falsewhile empty). - Bar-mode incremental
ta.liquidity_score(T2). Last-sample kernel matches full recompute: last-N volume/volatility/spread mix (50.0while short). - Bar-mode incremental
ta.fear_greed_index(T2). Last-sample kernel matches full recompute: last rsi/vix/put_call/breadth mix, clamp [-100, 100]. - Bar-mode incremental
ta.crowd_sentiment(T2). Last-sample kernel matches full recompute: mean of three last samples × 100, clamp [0, 100]. - Bar-mode incremental
ta.smart_money_flow(T2). Last-sample kernel matches full recompute: volume-scaled signed flow from last price_change vs time_since_high/low, clamp [-1, 1]. - Bar-mode incremental
ta.trend_confirmation_score(T2). Last-sample kernel matches full recompute: five last samples mixed, clamp [0, 100]. - Bar-mode incremental
ta.atr_stop(T2). Last-sample kernel matches full recompute: last close ± last ATR × multiplier. - Bar-mode incremental
ta.max_loss_level(T2). Last-sample kernel matches full recompute: last entry/account/max_loss_pct → stop price. - Bar-mode incremental
ta.profit_lock_level(T2). Last-sample kernel matches full recompute: last entry/current/trail_pct/direction → trailing stop.
Fixed
request.securityresamples allowlisted 1-argta.adx(length)/ta.mfi(length)on HTF (D-06). Same-symbolta.adx(14)(HTF high/low/close) /ta.mfi(14)(HTF high/low/close/volume) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*, 2-argta.adx(diLength, adxSmoothing), and 4-arg explicit-series adx stayna. Disk IR cache v36.request.securityresamples allowlisted 0-argta.obv()/ 1-argta.cmf(length)on HTF (D-06). Same-symbolta.obv()(HTF close+volume, running signed volume; 0 until 3 unique bars) /ta.cmf(14)(HTF high/low/close/volume) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*, 2-argta.obv(close, volume), and 5-arg explicit-series cmf stayna. Disk IR cache v37.request.securityresamples allowlisted 0-argta.nvi()/ta.pvi()on HTF (D-06). Same-symbolta.nvi()/ta.pvi()(HTF close+volume, seed 1000; later bars multiply by(1 + close_change)when volume decreases / increases) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 2-argta.nvi(close, volume)/ta.pvi(close, volume)stayna. Disk IR cache v38.request.securityresamples allowlisted 0-argta.accdist()/ta.wad()on HTF (D-06). Same-symbolta.accdist()/ta.wad()(HTF high/low/close/volume; accdist is CLV × volume running sum, wad is Williams A/D with first unique bar 0) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 4-argta.accdist(high, low, close, volume)/ta.wad(high, low, close, volume)stayna. Disk IR cache v39.request.securityresamples allowlisted 0-argta.tr()/ 2-argta.tsi(short, long)on HTF (D-06). Same-symbolta.tr()(HTF high/low/close; first unique barna) /ta.tsi(13, 25)(HTF close, extra=short, length=long) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 3-argta.tr(high, low, close)/ta.tsi(source, short, long)stayna. Disk IR cache v40.request.securityresamples allowlisted 2-arg / 3-argta.bbwon HTF (D-06). Same-symbolta.bbw(close, 20, 2)/ta.bbw(20, 2)(HTF source, extra=mult; width is2*mult*stdev/smawhile SMA ≠ 0) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.bbw(ta.sma(...), n, 2)and 1-argta.bbwstayna. Disk IR cache v41.request.securityresamples allowlisted 1-arg / 2-argta.stoch%K on HTF (D-06). Same-symbolta.stoch(14)/ta.stoch(14, 3)(HTF high/low/close, %K only; dPeriod stored unused) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 4-argta.stoch(source, high, low, length)stayna. Disk IR cache v42.request.securityresamples allowlisted 2-argta.pivothigh/ta.pivotlowon HTF (D-06). Same-symbolta.pivothigh(left, right)(HTF high) /ta.pivotlow(left, right)(HTF low; optional 3-arg OHLCV source) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v43.request.securityresamples allowlisted 3-argta.percentile_nearest_rank/ta.percentile_linear_interpolationon HTF (D-06). Same-symbolta.percentile_nearest_rank(source, n, percentage)/ta.percentile_linear_interpolation(source, n, percentage)(percentage a const int, 0 ok) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and non-int percentage stayna. Disk IR cache v44.request.securityresamples allowlisted 1-argta.dpo(n)/ 2-argta.crossover/ta.crossunderof OHLCV names on HTF (D-06). Same-symbolta.dpo(21)(HTF close,close[n//2+1] - sma(close, n)) /ta.crossover(close, open)/ta.crossunder(close, open)(both args OHLCV Names) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v45.request.securityresamples allowlisted 3-argta.correlationof OHLCV names on HTF (D-06). Same-symbolta.correlation(close, volume, 20)(both args OHLCV Names; extra=src_b field index) on a coarser TF run last-N Pearson on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v46.request.securityresamples allowlisted 2-argta.dpo(source, n)/ 2-argta.crossof OHLCV names on HTF (D-06). Same-symbolta.dpo(close, 21)(HTF source,src[n//2+1] - sma(src, n)) /ta.cross(close, open)(both args OHLCV Names; extra=src_b field index; either-direction last two unique HTF samples) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v47.request.securityresamples allowlisted 0-argta.vpt()/ 1-argta.wvad(n)on HTF (D-06). Same-symbolta.vpt()/ta.pvt()(HTF close+volume, first unique bar0.0, later addvol * (close-prev)/prev) /ta.wvad(n)(HTF high/low/close/volume; 0-arg defaults period 20) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 4-argta.wvadstayna. Disk IR cache v48.request.securityresamples allowlisted 3-argta.uo/ 3-argta.apoon HTF (D-06). Same-symbolta.uo(7, 14, 28)(HTF high/low/close; extra packsn2*1000+n3) /ta.apo(close, 10, 20)(HTF source, extra=fast, length=slow; APO is EMA(fast)−EMA(slow)) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v49.request.securityresamples allowlisted 1-argta.emv(n)on HTF (D-06). Same-symbolta.emv(14)(HTF high/low/volume; last-N valid ease-of-movement mean) on a coarser TF runs the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v50.
[0.6.17] — 2026-10-19
Fixed
WS /ws/liveno longer tears the plane down on a quiet socket.simple_websocketreturnsNoneon a receive timeout (it does not raise) — the live loop read that as a disconnect and closed the socket ~50 ms after the handshake. A slow history ensure or the gap between client heartbeats therefore dropped the subscription before its snapshot arrived (the client saw "no snapshot" and fell back to venue + REST). A timeout now keeps the socket alive; a real disconnect still closes it.
[0.6.16] — 2026-10-19
Fixed
- Session results ship the evaluated window's bar-time axis (
times). The engine's stored series can have gaps (a missed minute), so a client that joined the series by index displaced the plot — the band led the candles by the number of missing bars. The session envelope now carriestimes(the evaluated bars' timestamps) and a delta tick carries the tail's, so the client joins by time. AXIS already consumes it (meta.engineTimes→alignSeriesToTimes).
[0.6.15] — 2026-10-19
Added
- MCP server. Optional extra
hoox-pyne[mcp]ships a stdio Model Context Protocol server (pyne-mcp,python -m pynescript.mcp, Clickpyne mcp/pyne mcp config). Tools wrap everypyneCLI command in-process (parse, format, convert, lint, compile, prewarm, run, optimize, data, runner HTTP, facade list) plus structured parse/symbols/diagnostics,Runtime.run(pyne_execute), interpret/compile last-value parity, builtin lookup, and LSP hover/complete/signature. Resourcespyne://infoandpyne://builtins[/{name}]. Promptsreview_pine/debug_pine/convert_to_v6. Plot series are truncated; no disk writes; runner tools do not echo tokens. - MCP tools are executable from the CLI.
pyne mcp toolslists catalog names;pyne mcp call TOOL [PATH]runs any tool in-process (no MCP SDK; same{ok,...}JSON). First-class commands:pyne execute(Runtime.run),pyne symbols,pyne parity,pyne diagnostics,pyne builtin. - LSP document links.
textDocument/documentLinkreportshttp:///https://URLs in comments (//,/* */, hash# …) and string literals asDocumentLinkranges whosetargetis the URL. Empty or unparsed documents return[]. Advertised viadocumentLinkProvider. - LSP documentColor for
color.from_gradient.textDocument/documentColorreportscolor.from_gradient(value, min, max, color1, color2)as a 0–1 RGBAColorInformationwhen all five args are literals (numeric value/min/max plus namedcolor.*/#hextoken / quoted hex). Interpolation matches interpretcolor.from_gradient(RGBA lerp, clamp to[min, max], equal min/max → color1). Existing hex / named /color.rgb/color.new/color()paths are unchanged. - Bar-mode incremental
ta.rsi_oversold_overbought(T2). Last-sample kernel matches full recompute: last RSI sample vs two int levels →{is_oversold, is_overbought, rsi}(False/rsi: Nonewhile the series is empty or the last sample isna). Oversold isrsi < oversold; overbought isrsi > overbought. - Bar-mode incremental
ta.zigzag(T2). Last-sample kernel matches full recompute: last 2 numeric samples →(recent_high, recent_low, direction)(nan/nan/0 while fewer than 2 numeric samples). Direction is1if the last numeric is the pair high else-1; percent change above the threshold forces1.
Fixed
pyne mcp callexits non-zero on error findings.pyne lintfails on errors by default (--fail-on errors); the MCP call path only failed when the envelope hadok: false, so a script with a syntax error passed CI.pyne mcp call lint(andpyne diagnostics) now exit 1 when the payload carries error-severity findings.- The compile packer keeps
__alertsa list. An empty alert list was coerced to an empty float64 array, which broke truthiness checks in hosts (ValueError: The truth value of an empty array is ambiguous) and could drop the alert payload.__alertsnow passes through like__drawings/__events. WS /ws/runforwards the whole run envelope (librariesincluded). Published-library imports (import ns/Name/1) resolved overPOST /runbut failed over the WebSocket channel: the WS envelope mapper droppedlibraries(andtimeout_seconds/from_bar/to_bar). The mapping is now a shared helper (backend.app._ws_envelope_to_payload) that mirrorsRUN_SCHEMA, so the WS channel has the same surface as HTTP.- The Pro API image can no longer ship a broken WebSocket. gunicorn's
geventwebsocket…GeventWebSocketWorkerupgrades the socket and flask-sock upgrades it again — two101handshakes, a desynced frame stream, and every WS frame dropped (clients see close code 1002) while REST kept working. The image default isgthread(flask-sock owns the upgrade), the prod compose pins it, a repo guard (tests/test_docker_entrypoint.py) keeps every deploy path off the gevent worker, and CI now smokesWS /ws/runagainst the built image. WS /ws/livehistory ensure no longer blocks the socket loop.subscribe/resume/repairrun_ensure()on a worker so ping/pong keep moving. Per-id generation tokens skip late_attachafter unsubscribe/close; a resubscribe is not treated as a duplicate of a stale worker.request.securityresamples allowlistedta.cum(source)/ 1-argta.ao(fast)on HTF (D-06). Same-symbolta.cum(close)(running sum on unique HTF bars;naas 0) /ta.ao(5)(HTF hl2, SMA fast − SMA 34) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v34.request.securityresamples allowlisted 1-argta.change(source)on HTF (D-06). Same-symbolta.change(close)(length defaults to 1) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v35.
[0.6.14] — 2026-10-19
Added
-
LSP document colors.
textDocument/documentColorreports#rgb/#rrggbb/#rrggbbaacolor literals, quoted"#rrggbb"/"#rrggbbaa"strings,color.*named constants (color.red, …),color.rgb(r, g, b[, transp])with numeric literals, andcolor.new(color, transp)/color(color, transp)(Pine alias ofcolor.new) when both args are literals (namedcolor.*,#hextoken, or quoted hex) as 0–1 RGBAColorInformation. Pine transparency is 0–100 (0 = opaque).textDocument/colorPresentationrewrites the range as#rrggbb(or#rrggbbaawhen alpha ≠ 1), including when the original text was acolor.*name. Empty or unparsed documents return[]. Advertised viacolorProvider. -
LSP C002 QuickFix.
textDocument/codeActionapplies the same whole-documentTextEditastextDocument/formattingwhen lint warnings include C002 (line length > 120). Unparsed or unchanged source yields no C002 fix. Advertised asQuickFix. Convert-to-v6 / W001 / W002 are unchanged. -
LSP selection ranges.
textDocument/selectionRangeexpands from the identifier (or smallest AST node) under the cursor to the enclosing statement, then enclosingif/for/while/switch/onceblocks andFunctionDef/TypeDef/EnumDef. Empty or unparsed documents, or no node at the position, return[]. Advertised viaselectionRangeProvider. -
LSP folding ranges.
textDocument/foldingRangeforif/for/while/switch/onceblocks,FunctionDef/TypeDef/EnumDef, and//#region///#endregion(plus# regionhash comments). Empty or unparsed documents return[]. Advertised viafoldingRangeProvider. -
LSP W002 QuickFix.
textDocument/codeActionreplaces an old//@version=N(N < 5) with//@version=6on the existing pragma line (does not insert a second pragma). v5 still gets Convert-to-v6RefactorRewriteonly. -
LSP W001 QuickFix.
textDocument/codeActioninserts//@version=6at the document start when the version pragma is missing. Advertised asQuickFixalongside Convert-to-v6RefactorRewrite. -
LSP rename across open workspace documents.
textDocument/renameupdates the ident in every currently open document that contains that Pine ident (same rules: no keywords / builtin namespaces; valid Pine ident). Documents that are not open are not in the workspace edit.prepareRenamestays the cursor document's ident range. -
LSP document highlight and rename —
textDocument/documentHighlight,textDocument/prepareRename, andtextDocument/renamefor user identifiers (character-precise). Keywords and builtin namespaces (ta,strategy,math, …) are not renamed. Advertised viadocumentHighlightProviderandrenameProvider(prepareProvider). -
Compile-mode realtime multi-pass (D-04). Object-mode compile honors
Runtime.runrealtime_ticks/realtime_bars/realtime_from_bar/realtime_last_bar: last-barbarstate.isrealtime, intermediate ticks overwrite the same plot cell,varcommits once,varipre-inits,oncelatches only when confirmed. Numeric nopython stays historical unless the script already forced object mode (an active realtime window re-emits object mode). -
Realtime ticks from
DataFeed.poll_ohlcv(D-04). WhenRuntime.run(..., data_feed=)is passed and a realtime window is active, each last-bar tick evaluates the latest forming OHLCV from a sync poll (MockDataFeedis scriptable / no sleep;Noneis a no-op) on interpret and object-mode compile. Without a feed, ticks still re-visit the same historical OHLC.InterpretSession.update_last_baris unchanged.CCXTProDataFeed.poll_ohlcvreturns the last cachedwatch_ohlcv/fetch_latest_ohlcvcandle (no socket in the bar loop). -
Bar-mode incremental
ta.ema_cross_signal(T2). Last-sample kernel matches full recompute: last 2 samples of two series →{signal, strength, trend_direction}("neutral"/ 0 whilelen < 2; non-numeric samples coerce to 0.0). Buy on crossover with strength > threshold, sell on crossunder. -
Bar-mode incremental
ta.inside_bar_pattern(T2). Last-sample kernel matches full recompute: last 2 highs/lows →curr_high < prev_high and curr_low > prev_low(Falsewhilelen < 2; non-numeric samples coerce to 0.0). -
Bar-mode incremental
ta.gap_detector(T2). Last-sample kernel matches full recompute: last high/low vs previous close →{gap_size, gap_type, gap_percent}(type1up,-1down,0none; zeros while any sample is missing, including bar 0 / na prev_close). -
Bar-mode incremental
ta.double_top_bottom(T2). Last-sample kernel matches full recompute: last-N highs/lows →{pattern_type, strength, breakout_level}("none"/ 0.0 while the window is short or fewer than 3 numeric highs). -
Bar-mode incremental
ta.engulfing/ta.hammer(T2). Last-sample kernels match full recompute: engulfing uses last 2 opens/closes (high/low unused; both flags False and strength 0.0 whilelen < 2); hammer uses last 1 OHLC (defined on bar 0). Same dict keys (is_bullish/is_bearish/pattern_strength,is_hammer/is_doji/pattern_strength). -
Bar-mode incremental
ta.fractal(T2). Last-sample kernel matches full recompute: chart high/low, warmup2*period+1(both flags False); current bar is a high/low fractal if it equals the window max/min. Same dict keys (is_high_fractal,is_low_fractal). -
Bar-mode incremental
ta.range/ta.max/ta.min(T2). Last-sample kernels match full recompute: range is highest−lowest (two call-site slots, highest then lowest), 2-arg max/min reuse the sliding-extreme kernels. 1-arg max/min stay whole-series full-path. -
Bar-mode incremental
ta.stoch_smooth(T2). Last-sample kernel matches full recompute: raw stochastic per bar (partial window while warming up; na if any high/low/close in the last-N window is non-numeric), thenEMA(stoch, smooth_k), thenEMA(that, smooth_d). -
Bar-mode incremental
ta.rsi_divergence(T2). Last-sample kernel matches full recompute: last-(period+1) min/max scaled to [-1, 1]; 0.0 whilei < period, when fewer than 2 numeric values are in the window, or when the range is 0. -
Bar-mode incremental
ta.sma_weighted(T2). Last-sample kernel matches full recompute: last-N weighted SMA withweight_type"linear"(default, weights 1..n),"quadratic"((i+1)**2), or"sqrt"((i+1)**0.5). na while the window is short or any slot is non-numeric. -
Bar-mode incremental
ta.ichimoku/ta.apo/ta.emv(T2). Last-sample kernels match full recompute: Ichimoku reuses highest/lowest windows (stable six-slot order), APO isEMA(fast) - EMA(slow), EMV is the last-N mean of per-bar ease-of-movement (na on bar 0 / zero volume / flat range). -
Bar-mode incremental
ta.skewness/ta.kurtosis/ta.beta(T2). Last-sample kernels match full recompute: population skew and excess kurtosis over the last-N calendar window (na while any slot is non-numeric; 0.0 when stdev is 0), beta ascov(s1,s2)/var(s2)(0.0 when var(s2) is 0). -
Bar-mode incremental
ta.r_squared/ta.comovement(T2). Last-sample kernels match full recompute: r_squared is corr² clipped to [0, 1] (0.0 when either variance is 0; na while the window is short or any slot is non-numeric), comovement is the percent of last-N-1 deltas that share sign. -
Bar-mode incremental
ta.volume_weighted_momentum(T2). Last-sample kernel matches full recompute: last-N(Δprice * vol) / sum(vol)(0.0 when volume_sum is 0; na while the window is short). -
Bar-mode incremental
ta.rci/ta.bb_pct/ta.atr_normalized(T2). Last-sample kernels match full recompute: rci is Spearman rho of time vs value ranks (volatility mixin gated), %B is(close-lower)/(upper-lower)×100clipped to [0, 100] (50.0 when bands collapse), atr_normalized is ATR/close×100 (na when close is 0). -
Bar-mode incremental
ta.cumulative_delta/ta.volume_momentum(T2). Last-sample kernels match full recompute: cumulative_delta is last-N signed volume (+volif close>prev,−volif close<prev; 0.0 while the window is short), volume_momentum is the period-SMA volume ROC clipped to [-100, 100] (0.0 while the window is short or the old SMA is 0). Duplicate mixin copies ineconomics.py/advanced.pystay in sync.
Changed
- Public product docs are end-user and developer only. Mintlify (
docs/pyne/**) no longer carries operator shipping (personal PyPI account, Trusted Publishing / API-token how-to, GCP cost estimates, VPS deploy wiring)./devops/pypi-publishand/devops/publish-checklistredirect to Contributing. Audience rules live indocs/WRITING.md. - PYNE docs overview (
docs/pyne/index.mdx) no longer dumps an in-page "What's new" changelog; it points at GitHub releases and compatibility.
Fixed
request.securityresamples allowlistedta.vwap()/ta.vwap(source)on HTF (D-06). Same-symbol 0-argta.vwap()(HTF hlc3) / 1-argta.vwap(close)on a coarser TF run cumulative VWAP on unique completed HTF bars (sum(price×HTF volume)/sum(volume); interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 2-arg anchor / 3-arg bands stayna. Disk IR cache v33.request.securityresamples allowlisted 2-argta.ao(fast, slow)/ 3-argta.linreg(source, n, offset)on HTF (D-06). Same-symbolta.ao(5, 34)(HTF hl2, SMA fast − SMA slow) /ta.linreg(close, 14, 1)(offset inextra; 2-arg is still offset 0) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v32.request.securityresamples allowlistedta.swma/ta.ao()/ 1-argta.range(n)on HTF (D-06). Same-symbolta.swma(source)(fixed 4-period) / 0-argta.ao()(HTF hl2, SMA 5 − SMA 34) /ta.range(n)(HTF high − HTF low over n unique bars) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 2-argta.ao(fast, slow)stayna. Disk IR cache v31.request.securityresamples allowlisted 2-argta.kama/ta.rising/ta.fallingon HTF (D-06). Same-symbolta.kama(source, n)(Kaufman fast=2, slow=30) /ta.rising(source, n)/ta.falling(source, n)on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*andta.kama3/4-arg stayna. Disk IR cache v30.request.securityresamples allowlistedta.cog/ta.highestbars/ta.lowestbarson HTF (D-06). Same-symbol 2-arg(source, length)forms and 1-argta.highestbars(n)(HTF high) /ta.lowestbars(n)(HTF low) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v29.request.securityresamples allowlistedta.mode/ta.percentrank/ta.changeon HTF (D-06). Same-symbol 2-arg(source, length)forms on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v28.request.securityresamples allowlistedta.median/ta.dev/ta.varianceon HTF (D-06). Same-symbol 2-arg(source, length)forms on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v27.request.securityresamples allowlistedta.highest/ta.lowest(2-arg and 1-arg) andta.rangeon HTF (D-06). Same-symbolta.highest(source, n)/ta.lowest(source, n)/ta.range(source, n)and 1-argta.highest(n)(HTF high) /ta.lowest(n)(HTF low) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stayna. Disk IR cache v26.- Nested list/dict contents roll back on unconfirmed realtime ticks (D-04). Interpret snapshots copy one extra list/dict nesting level (
array.new<array<float>>()/ list-of-lists / dict-of-lists), so an unconfirmeda.get(0).push(x)does not leak into the next tick. Restore still writes into the same outer object;varipis skipped. Object-mode compile copies inner lists/dicts the same way. Deeper nesting and Matrix/Map internals stay best-effort. Historicalrealtime_ticks=1is unchanged. Disk IR cache v24. request.securityresamples allowlistedta.dema/ta.temaand 1-argta.wpr(length)on HTF (D-06). Same-symbolta.dema(source, n)/ta.tema(source, n)/ta.wpr(n)(HTF high/low/close) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*, 4-arg WPR, andta.kama3/4-arg stayna. Disk IR cache v25.request.securityresamples allowlistedta.hma/ta.vwmaand 1-argta.cci(length)on HTF (D-06). Same-symbolta.hma(source, n)/ta.vwma(source, n)/ta.cci(n)(typical price / HTF hlc3) on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 4-arg CCI stayna. Disk IR cache v24.request.securityresamples allowlistedta.cmo/ta.stdev/ta.linregon HTF (D-06). Same-symbol 2-arg(source, length)forms on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*stillna.request.securityresamples allowlistedta.cci/ta.roc/ta.momon HTF (D-06). Same-symbol 2-arg(source, length)forms on a coarser TF run the interpret TA helper on unique completed HTF bars (interpret and object-mode compile), with the samegaps_on/lookahead_onasta.sma. Nestedta.*and 4-arg CCI stayna. Disk IR cache v23.request.securityhonorsgaps_on/lookahead_onon provider-backed HTF OHLCV (D-06). When adata_provideror feed returns a coarser OHLCV series with bar times, interpret aligns it to chart bars and applies the same bucket-start na-gaps / period-start lookahead leak as chart HTF resample (provider_htf_ohlcv). Chart-length / no-timestamp payloads (ChartOHLCVProviderignoringinterval) stay stubs with unused merge args. Nestedta.*, LTF, and passthrough paths are unchanged.- Compile-mode
request.securityconsumes provider/feed HTF merge (D-06). Object-mode compile now aligns coarser timestampeddata_provider/data_feedOHLCV the same way interpret does (gaps_on/lookahead_on). Chart-length / no-timestamp stubs stay unused-merge. Nestedta.*, LTF, and passthrough paths are unchanged. Disk IR cache v22. strategy.risk.max_intraday_lossresumes the nextsyminfo.timezonecalendar day (D-02). The halt and the day-scopedmax_intraday_filled_orderscap now use DST-aware midnight-to-midnight buckets (same rules astimeframe.change); a bar that is still yesterday inAmerica/New_Yorkstays blocked.max_drawdownremains a permanent halt.max_position_sizeis still %-of-equity.CCXTProDataFeed.poll_ohlcvreturns the last cached watch/fetch candle. Sync and network-free so the realtime bar loop can form last-bar ticks from a live CCXT Pro stream without opening a socket per tick. Empty cache is stillNone.WS /ws/livesendsauth.okas soon as the upgrade handshake authenticates. AXIS was blocking connect on that frame while the engine hashed the key; a handshake-authed socket now greets immediately so subscribe is not UNAUTHORIZED.- Engine series keys accept AXIS futures aliases and CCXT
defaultTypefollows the market.linear/USDT-Mcanonicalizes toswap,inverse/COIN-Mtofuture. Live feeds and the cached CCXT provider are per(exchange, market)so a USDT-M chart does not reuse the spot Binance client. - In-place array / matrix / map / UDT mutations roll back on unconfirmed realtime ticks (D-04). Intermediate interpret ticks restore container contents into the same objects (aliases keep identity);
varipcontainers persist. Object-mode compile copies list/dict contents the same way. - Unconfirmed realtime ticks roll back broker fills and pending orders (D-04). Interpret and object-mode compile snapshot
StrategyState/CompileStrategyBroker(pending book, open/closed trades, position, equity peaks, events, strategy hist) and restore after intermediate ticks, so last-barstrategy.entrywithrealtime_ticks=Nfills once. Pending OHLC processing stays once per bar (begin_bar/process_pending_ordersremain outside the tick loop). Historicalrealtime_ticks=1is unchanged. Trail stops ratchet from forming-bar high/low after restore (still OHLC-path, no tick path). - Trail stops ratchet on forming-bar realtime ticks (D-01). After
poll_ohlcvand after each unconfirmed broker restore, pendingtrail_*stops follow the forming bar's high/low (interpret + object-mode compile;InterpretSession.update_last_bartoo). Fills still roll back on unconfirmed ticks. Historicalrealtime_ticks=1is unchanged. Still OHLC-path (no intra-bar tick path). - Open-trade MAE/MFE follow forming-bar realtime ticks (D-03). After
poll_ohlcvand after each unconfirmed broker restore, per-trademax_drawdown/max_runupfollow the forming bar's high/low (interpret + object-mode compile;InterpretSession.update_last_bartoo). Fills still roll back. Historicalrealtime_ticks=1is unchanged. Still OHLC-path (no intra-bar tick path). Disk IR cache v23. InterpretSession.update_last_barrolls back broker fills on forming ticks (D-04 leftover). Bar-openStrategyState.snapshot()is restored before each unconfirmed last-bar tick (pending book, open/closed trades, events); threestrategy.entryticks still fill once. Confirmedappend_barscommits. Historical appends without ticks are unchanged.- Compile-mode
alert()/alertcondition()firings are exported. Object-mode compile records the same envelope as interpret (message,freq,bar_index,time,source);/runmode=autono longer drops them when compile wins. Nopython numeric scripts still returnalerts: [].
[0.6.13] — 2026-10-18
Added
- LSP signature help —
textDocument/signatureHelpfor Pine builtins (frombuiltin_metadata.jsondetail/snippet) and userFunctionDef. Trigger characters(and,;activeParameteris the top-level comma count inside the innermost enclosing call. Advertised viasignatureHelpProvider.
Changed
- Live P3 push shape. Forming re-ticks ship last-value tails only and coalesce on the feed thread (75 ms); close/multi-slot batches flush immediately so
seqandcloseframes stay ordered. Compact (BNBUSDT) and pair-form (BNB/USDT) series identities match on tick so journaled sessions survive the AXIS key unification. - Live gunicorn topology (P2). Production compose now hard-pins
GUNICORN_WORKER_CLASS=gthread(a leftover 0.6.11geventwebsocketvalue in the host.envcan no longer restore broken WS frames), defaultsGUNICORN_THREADS=100andGUNICORN_TIMEOUT=120, and raises recycle toGUNICORN_MAX_REQUESTS=5000so a live/ws/livesocket is not torn down every few hundred REST ticks. The retired systemd unit/drop-in match gthread. VPS nginx already upgradeslocation /ws/with a 3600s read timeout.
Fixed
- Compile-mode
request.securityresamples the same allowlisted HTF shapes as interpret (D-06). Same-symbol simple OHLCV,close[1], andta.sma/ema/rsi/atr/wma/rmaon a coarser TF now go through the interpret HTF helpers in object mode (gaps_on/lookahead_onhonored on those paths) instead of chart passthrough orna. Nestedta.*, foreign tickers, LTF, and unparseable TFs are unchanged. - A
kind: seriessubscription now keeps its series store — and its socket — moving. The engine's live feed advanced sessions walk-free (apply_feed_candles) but never the series store, and asubscribeforkind: seriesreturnedsession_id: None, soLiveConnection._attachbailed before any feed listener existed. A series therefore reportednewestfrozen at the bar its history was ensured at:GET /data/serieslagged the venue forever, every re-subscribe answered the same stalefullsnapshot, and the bars that would have healed it streamed past on the feed with nowhere to land (observed live: a 1m SOLUSDT series reportingnewestexactly three bars behind the market at every repair, so an AXIS chart could only advance when the client's staleness repair ran). Two halves of one fix:_emit_readynow attaches the feed for series-kind subscriptions under the registry's own live id — stable per client + series, so a re-subscribe replaces the listener instead of stacking one per frame — andattach_feedupserts every batch into the store (persist_feed_bars, throttled per series toPERSIST_MIN_MSbecause a kline stream pushes the forming bar on every trade: a new slot always persists, a re-tick of the current one at most once per window). Upserts are by time and never raise — a store failure logs and leaves the feed alive — and the same sink also keeps the store advancing for script-kind feed subscriptions. Covered by four tests intests/test_live_push.py(bounds advance, forming row upserted + throttle honoured, fail-soft store, and end-to-end subscribe → listener → delta frame + store bounds).
Security
- JSON API key-store writes are flock-serialized and replaced atomically.
APIKeyStore._savelocks a sibling.lockfile andos.replaces a tempfile in the same directory so a concurrent writer cannot truncateapi_keys.jsoninto invalid JSON. Hash-only layout is unchanged; production compose still uses sqlite. - Alert webhook POSTs pin to the IP from one DNS lookup.
http_post_jsonno longer connects by hostname after a cached SSRF verdict: itgetaddrinfos once (cache stays for request-timeis_webhook_url_safeonly), refuses RFC1918/metadata unlessALERT_WEBHOOK_ALLOW_PRIVATE=1, connects to that IP, and sets HTTPS SNI/Hostto the original hostname so certificates still validate against the name. Redirects stay refused.
[0.6.12] — 2026-10-17
Fixed
WS /ws/run,WS /ws/liveand/datafeed/watchnow actually exchange frames (F-30 correction). The 0.6.11 default —geventwebsocket.gunicorn.workers.GeventWebSocketWorker— completed the HTTP→WS upgrade but then corrupted every frame: that worker's handler upgrades the socket itself (wsgi.websocket) while flask-sock ignoreswsgi.websocketand hijacksgunicorn.socketto re-frame the same socket. The app raised immediately after the101, so Werkzeug's HTTP error response was written where a WS frame belonged. Clients saw it as a protocol error after a successful handshake — Chromium reportsInvalid frame header, and a strict client aborts with1002 reserved bits must be 0(the first byte ofHTTP/...,0x48, sets RSV1). AXIS therefore kept silently falling back to REST, exactly as before F-30, with reconnect churn on top. The default worker class is nowgthread, which exposesgunicorn.socket— the transport flask-sock documents for Gunicorn — andGUNICORN_THREADSdefaults to 100 (one thread per live WS connection). Verified against the built image: agthreadcontainer answers the handshake with a well-formed frame ({"type":"error","code":"UNAUTHORIZED",…}) while the gevent-websocket container produces the reserved-bits protocol error.syncstill cannot upgrade, andgevent-websocketremains installed but is no longer selectable by default.
Changed
- The worker-class contract in the docs/comments was inverted and is now accurate.
docker/entrypoint-api.shandbackend/requirements.txtclaimed "sync/gthread workers cannot upgrade" and that gevent + gevent-websocket made the flask-sock routes "upgrade natively". Neither holds: gthread is the flask-sock-compatible worker, and the gevent-websocket worker is the one that breaks framing. (Comment-only elsewhere; no behaviour change for an explicitGUNICORN_WORKER_CLASSoverride.)
[0.6.11] — 2026-10-17
Added
- Engine-owned subscription plane over one socket (
WS /ws/live, F-10–F-15). A single connection now carries N subscriptions: handshake and per-frame auth,subscribewith autonomous history ensure (a miss fetches through the last closed bar), journal-backed resume, per-exchange CCXT Pro feeds (watchOHLCVForSymbolsfan-in with a REST-poll fallback and a walk-free session commit), a per-subscriptionseqplusclosed_uptowatermark, delta/close push emission, and the degraded REST tail route (GET /session/<id>/tail) for clients that cannot upgrade. Advertised on/healthunderendpointsandfeatures.live_stream, so AXIS detects it without probing. - Refcount-pooled shared sessions by content hash (F-29). Tabs running identical scripts attach to one pooled session instead of each paying a full-window create:
acquire_sharedreturns(id, created),release_shareddrops references (idle TTL still owns expiry), and capacity, journal and evict paths stay consistent;/statsreports the shared count. - Opt-in delta envelopes for session tick/append routes.
POST /session/<id>/tick,POST /session/<id>/appendandPOST /data/session/<id>/tickacceptdelta: trueand answer tail-only: the last cells ofplots/seriesplus adeltablock (base_index/count/tail_len) for positional merging (full = cached[:base_index] + tail), or flags-only for unchanged data-session ticks (no plots/series at all — the client reuses its cache). Small fields (events/drawings/alerts/meta) stay full. Window trims still take the full path, and unshapely results fall back to the full envelope instead of a corrupt delta. Advertised asfeatures.session_delta; clients that never send the flag see byte-identical responses. Covered by delta cases intests/test_backend_sessions.pyandtests/test_data_series.py(including tail-equals-full comparisons and flags-only unchanged ticks). - Live sessions survive worker recycles and container restarts. Every session mutation is journaled to SQLite (
backend/datastore/session_log.py:sessions+session_barstables underPYNE_SESSION_DB, default/data/sessions.dbwhen/dataexists, memory-only otherwise). The bar log mirrorsInterpretSession._ohlcv_dataexactly — create writes the full bars, tick replaces the last, append extends — so the first access after a restart rebuilds the session with onecreate_sessionover identical bars under its original id, and ticks are O(1) again after that single re-evaluation. This also fixes the session churn from gunicorn--max-requestsrecycling, which previously dropped every in-flight session silently. The rebuild is a rebase (indicators identical; strategy fills may differ as with a client-side rebase),GET /session/<id>answers journaled-but-unloaded sessions from the row without rebuilding, and all journal writes are best-effort (an unreachable db degrades to memory-only). New knobsSESSION_TTL_SECONDS/SESSION_MAX_SESSIONS(defaults 900 / 64, unchanged). Covered bytests/test_session_persistence.py(HTTP create → tick → append → simulated restart → tick round-trips, TTL expiry, capacity, data-session binding). ccxtships in the Pro API image./data/series/fetchand/data/sessionticks need an exchange feed, and without it every data tick failed503 CCXT_UNAVAILABLE.
Changed
- The API image now defaults to the gevent WebSocket worker (F-30).
gthread/syncworkers cannot upgrade, so/ws/run,/ws/liveand/datafeed/watchsilently fell back to REST under Docker. The default worker class is nowgeventwebsocket.gunicorn.workers.GeventWebSocketWorker(single worker, since greenlets share the process the live sessions require), tunable viaGUNICORN_WORKER_CLASS—gthread/syncrestore the old behavior, whereGUNICORN_THREADSapplies.geventandgevent-websocketwere added tobackend/requirements.txtand thepro/testextras. - Cached CCXT providers and a longer tick-walk reuse window. Every
/data/sessiontick built a freshCCXTProvider, so each cache-missing tick paidloadMarkets(a ~3 s floor) before fetching. One provider is now cached per(exchange, credentials)with a 30-minute refresh, fetches are serialized per exchange (ccxt rate-limit state is per object), and the tick-walk reuse window widened 5 s → 12 s so staggered chart and indicator ticks share a walk. Measured:provider.fetchp50 3219 ms → 274 ms,http.requestp95 3440 ms → 287 ms. - The VPS deploy path is docker-only.
scripts/deploy_vps.shno longer installs or restarts a systemd unit (the old drop-in kept a second runtime bound to the same port while backend fixes never reached the live container). It now rsyncs the tree, rebuilds and recreates the compose base + prod overlay (api+redis) with volumes preserved, waits for healthy and smokes:5002. .env.examplepinsPYNE_DATA_DIRto the persistent volume. The engine-owned series store defaults to a relativedata/that a container restart discards; the documented value is now/data/series.POST /data/session/<id>/tickresponses now includestale(walk was clamped because the stored anchor was too old).
Fixed
- Concurrent session ticks share one upstream walk (singleflight + cross-session reuse). AXIS ticks one data session per script instance (chart + N indicators) against the same series within seconds of each other; each tick paid its own CCXT walk for identical candles, and on the single gunicorn worker those walks serialized behind each other — the per-tick seconds observed from AXIS live mode.
sync_data_sessionnow shares the walk per series forTICK_WALK_REUSE_S(5 s): concurrent ticks join the in-flight walk instead of stacking round trips, and sequential ticks for other sessions reuse a fresh covering walk. The ticking session itself always refetches so forming-bar re-ticks observe every revision; truncated walks (hitTICK_MAX_BARS) are never shared. Covered bytest_concurrent_session_ticks_share_one_upstream_walk,test_concurrent_ticks_singleflight_one_walkandtest_walk_cache_expires_for_new_dataintests/test_data_series.py. - Live-session ticks no longer backfill runaway histories (connection-storm fix).
POST /data/session/<id>/tickfetched candles from the stored anchor with no bar cap, so a stale series (cached restore, failed first fetch, symbol/interval switch) walked CCXT pages across the whole gap — up toMAX_FETCH_PAGES×FETCH_PAGE_LIMIT= 200,000 bars of sequential upstream round trips per tick. One such tick pinned an HTTP request for 145–240 s, serialized every other request on the same series behindkey_lock, and wrote ~200k junk bars into the series store per tick; on gunicorn (1 worker × 4 threads, 120 s timeout) a few charts exhausted the pool and the timeout kills dropped every in-flight connection, producing the "connection issues several times a minute" symptom. Now: the walk is capped atTICK_MAX_BARS(2,500), a stale anchor is clamped to a bounded recent window instead of paging the whole gap, and the tick response flagsstale: trueso AXIS can re-sync history deliberately. The upstream walk also runs outsidekey_lock(only the fast local commit — liveness check, persist, session advance — holds it), and a tick aborts with404 SESSION_GONEwhen the session is released mid-flight instead of persisting for a dead session. - Series retention ceiling.
SeriesStore.providenow trims the oldest bars beyondMAX_SERIES_BARS(200,000 — 2× the largest legit window), so a runaway backfill or a chatty client cannot grow a series without bound. - The PYNE_DEBUG access log was silently dropped under
make run.python -m backend.appnames the module__main__, whichbackend.logging_setupdoes not manage (its prefixes arepynescript/backend), so the per-requestMETHOD /path -> status in mslines and the slow-request lines never appeared while engine/datafeed lines did.backend/app.pynow logs under an explicitbackend.applogger; gunicorn was already correct. .envis now honored bypython -m backend.appand gunicorn (previously only Docker Composeenv_fileread it). A guardedpython-dotenvloader runs at import, existing environment variables always win, and withoutpython-dotenvinstalled it is a quiet no-op.python-dotenvwas added tobackend/requirements.txtand the[pro]extra.X-Api-Keyis allowed cross-origin. The header was missing fromAccess-Control-Allow-Headers(and Flask-CORSallow_headers), so AXIS could not send authenticated requests to the Pro API fromhoox.shwithout a failed CORS preflight.- The deploy rsync no longer ships
.git/or.env. Syncing live git metadata corrupted the host tree once the VPS.gitdiverged, and the host never uses.gitoperationally;.envis excluded too, so a local dev override (e.g.PYNE_DEBUG=1) can never enable verbose logging in production.
Security
- Redis key store is no longer reachable from the internet; auth is opt-in. The compose
redisservice published6379on all interfaces without a password; automated scanners wiped the key store (FLUSHALL) and staged cron miner payloads (backup1-4). The service now publishes no ports (internal network only — the API is unaffected) and accepts--requirepassviaREDIS_PASSWORD, withREDIS_URL=redis://:PASSWORD@redis:6379/0as the matching API side (explicitREDIS_URLstill wins for Memorystore). Generate withopenssl rand -hex 32.
[0.6.10] — 2026-10-14
Added
PYNE_DEBUGdevelopment logging flag — one env var turns on detailed logging across the execution engine and the datafeed. SetPYNE_DEBUG=1to log the interpreter bar loop (start/end, bars + ms + bars/ms, aborts, timeouts), the compile pipeline (eligibility, cache HIT/MISS, transpile, JIT warm, object-mode / nopython fallback), prewarm (builtins warm, per-script results, total ms), delta calculation (append_barsdelta size + start index,update_last_barforming-bar ticks), the datafeed (CCXT Pro connect / subscribe / updates / reconnects, RESTfetch_ohlcv, the/datafeed/*gateway andWS /datafeed/watch), and every HTTP request (method, path, status, ms). It also sets thepynescriptandbackendloggers toDEBUG; third-party chatter (urllib3,numba,matplotlib,asyncio,werkzeug) stays atWARNING. OptionalPYNE_DEBUG_SCOPE=pynescript.runtime,pynescript.compilernarrows logging to a logger allowlist. Implementation is split between the newpynescript.debugtoggle (env parsing, memoized on the raw env string so a live flip takes effect without a restart),backend/logging_setup.py(level policy, handler install), and_dbg(...)/_stats.*call sites insidepynescript.runtime.host,pynescript.compiler.engine,pynescript.util.datafeedandpynescript.util.data. Gates sit at run / batch / request boundaries rather than inside per-bar loops, and log payloads are never built when the flag is off, so the disabled path stays cheap; debug output is verbose by design and should stay off in production.GET /stats— public (no API key) process-wide runtime statistics, documented in the route docstring and advertised underendpointson/health. Returnscounters(per-metric totals with dimension breakdowns, e.g. runs by resolved mode, auto backend, compile fallback reason),latencies(count / avg / min / max / p50 / p95 in ms, backed by a bounded reservoir of the last 512 samples per metric),gauges(in-flight requests, active sessions + capacity + high-water mark, largest single delta append, host compile-cache entries, bound datafeed sessions and live watch connections), plus livecompile_cacheandsessionssnapshots and the currentPYNE_DEBUGconfiguration. Backed by the new dependency-freepynescript.statsregistry (thread-safe counters / latencies / gauges, every update wrapped so a metrics failure can never fail a run). In-process only — counters reset on worker restart, which is honest for the single-worker gunicorn setup the live sessions require.- Engine + datafeed statistics —
pynescript.statscall sites now record interpreter bar-loop duration and bars evaluated (one-shot and per-session), compile cache hit/miss split by memory / sanitized / disk / IR-share, prewarm outcomes, delta append size and forming-bar tick latency, CCXT realtime stream subscribes and reconnects, historical provider fetches and bars, gateway fetch outcomes, dropped candles and WS watch connections. - Engine-owned OHLCV store — PYNE Pro can now own market bars for every-tick live mode. Bars persist in SQLite under
PYNE_DATA_DIR(defaultdata/), keyed by the canonical series keyexchange|market|SYMBOL|interval(for examplebinance|spot|BTC/USDT|1h). Upserts are keyed by unix-secondtime, and the later write wins. A forming bar is re-written in place. Implemented inbackend/datastore/series.py, without Flask or CCXT. The wire contract isdocs/devops/engine-owned-data-plane.mdxin the AXIS repo. /data/series*routes (backend/api/data_series.py) —GET /data/series(bounds; count 0 when unknown),POST /data/series/provide(upload closed bars, max 5,000 per request, otherwise413 BATCH_TOO_LARGE),POST /data/series/fetch(walks CCXTfetch_ohlcvpages forward fromnow - history_barsand persists;history_barsdefaults to 5,000 and caps at 100,000; upstream failure is502 UPSTREAM, CCXT missing is503 CCXT_UNAVAILABLE), andGET /data/series/bars(newest window, ascending,limitdefaults to 10,000 and caps at 100,000). The CCXT provider and candle mapping are shared with/datafeed/ohlcv./data/session*routes (backend/app.py) —POST /data/sessionbuilds a live interpret session over the stored window and binds it to the series key. It returns the/sessionenvelope plussession_id,cache: "hit", anddata: {key, count, newest}. When the store holds fewer thanhistory_barsbars it returns409 DATA_MISSwithhaveandneed.POST /data/session/<id>/ticktakes{exchange, symbol}only. It returns409 SESSION_KEY_MISMATCHfor another series, fetches candles from two bars before the stored newest, persists closed bars, re-ticks the forming bar withupdate_last_bar, and appends newer bars withappend_bars. The response addsappended,forming, andunchanged. Upstream failure is502 UPSTREAMand keeps the session.DELETE /session/<id>releases it as before.- Health
features—live_modes: ["every-tick", "bar-close"]anddata_session: true, which AXIS uses for capability detection (D3). The/data/*routes are listed underendpoints.
Changed
- Docs export minifier no longer shreds identifiers (
scripts/docs/generate-exports.mjs). The markdown-emphasis strippers_([^_]+)_and__([^_]+)__were not word-boundary anchored, so they paired the underscores of different identifiers whenever two appeared in one sentence:PYNE_DEBUG=1 and PYNE_DEBUG_SCOPE=xmatched_DEBUG=1 and PYNE_and shippedPYNEDEBUG=1 and PYNESCOPE=x. Every generatedllm.txttherefore lost identifier spellings —ADMIN_TOKENshipped asADMINTOKEN(33 occurrences), plusPYNEDEBUG,frombar,sessionid, and others — degrading the packs AXIS and the agents read for exactly the env-var and field names they need most. Both patterns are now anchored with lookarounds, so real emphasis / strong still collapse while snake_case identifiers,__bar_idx, and env-var names survive intact.
Fixed
Six long-standing failures, plus one defect in the docs export pipeline that made every generated LLM context pack lossy.
chart.point.copy(pt)silently dropped its argument._call_prefers_array_methodreturned True for any attribute receiver, sochart.point.copywas lowered toarray.copybefore thechart.pointbranch could run, emittingarray_copy_value(None). The point becameNone,pt2.priceread throughudt_get_field(None, …)as NaN, and the strategy/plot silently plotted nothing. The chart.point namespace is now recognised and excluded from the collection-method path (_is_chart_point_namespace).- A numeric multi-return UDF was forced into object mode.
f(float a, float b) => [a + 1.0, b + 2.0]is markedfunc_returns_sequenceso a single-targeta = f()keeps the tuple as a handle — but that same marker also demoted the multi-unpack[u, w] = f()to object mode, cutting the nopython stay rate for that shape. Such functions are now recognised as numeric-tuple UDFs (excluding string/UDT/import returns) and keep float series. The unpack also emits direct__tup[i]indexing: theisinstance(__tup, (tuple, list))guard cannot be narrowed by Numba, and it alone was enough to fail the njit warm-up. - Interpret and compile disagreed on every titled
fill(). Interpret wrote the per-bar band colour into theseriescolumn; compile packs series into float64 arrays and therefore cannot emit a colour string, so it emitted null. Any script usingfill(..., title="…")therefore rendered differently depending on mode. The interpret fill column is now null; the band is still described completely byplot_meta(kind="fill",plot1/plot2,color), so nothing is lost for the frontend. - The parity harness reported a hard MISMATCH for arbitrarily-titled fills.
is_fill_background_keymatched series by name only, sofill(p1, p2, title="BE Zone")fell through to a numeric-parity failure even though the difference was colour-vs-null and there was no number to compare. Fill classification is now value-aware: a column whose every non-NA cell is anrgb()/rgba()string is a fill series regardless of its title. Numeric parity is unchanged —_is_nonnumeric_only_differencestill hard-fails any cell that is numeric on both sides. - Two stale assertions, updated to the invariants that actually hold.
test_udt_na_field_access_no_scalar_getitemrequired the UDT guard to be inlined asisinstance(__u, dict); commit8bc8f41dmoved that guard into theudt_get_fieldbuiltin (the inlined walrus is aSyntaxErrorinside list comprehensions), so the test now accepts either spelling.test_get_price_pine_series_endpointsassertedline.newstores aPineSeries;0ad37af0began snapshotting endpoints to plain numbers soexport_for_apicould not re-read.currenton the last bar and diverge from compile — a strictly newer, deliberate change — so the test now asserts the resolved values.
Documentation
- New endpoint pages for previously undocumented surface.
api/endpoints/sessions(O(1) forming-bar ticks vs the O(n) full re-walk, O(delta) appends, tick rollback semantics, TTL/capacity, the single-worker constraint, and response windowing),api/endpoints/data-plane(series key rules, the four/data/series*routes,/data/sessionbinding,DATA_MISS/SESSION_KEY_MISMATCH, and the API-key requirement), andapi/endpoints/stats. Five of the preceding ten commits had shipped user-facing routes with no docs page at all. devops/observabilityrewritten aroundPYNE_DEBUGwith real captured trace excerpts — a cold compile run, a warm cache hit, and an O(delta) session append — plusGET /stats, per-process and reservoir-window invariants, and a failure-modes row for "no engine debug output" (gunicorn inherits its environment from the parent, not the operator's shell).api/indexendpoint table extended with the session, data-plane, stats and runner rows.index.mdx"What's new" was stale at 0.6.7 and now covers 0.6.9 and the post-release work.llms.txt/llm.txt/ exports are regenerated fromdocs.jsonviascripts/docs/generate-exports.mjs, never hand-edited. Every response shape in the new pages was captured from the running app rather than inferred from source.
[0.6.9] — 2026-10-13
Added
-
Response windowing on
POST /run— optionalfrom_bar/to_barrequest fields (inclusive bar indices intodata, negative counts from the end, either side may be omitted). Trims the serialized envelope only: the bar loop still runs over every bar, so indicator values, strategy state, NaN warm-up, and Pine parity are untouched. Measured on 20k bars against a local Pro API: 1,068.8 KB → 28.0 KB (38x smaller) for a 500-bar window, with the windowed series verified byte-equal to the full run's tail. Windowing is a no-op when the fields are absent — the unwindowed envelope is unchanged and gains nowindowkey. When a window is applied the response carrieswindow: {from_bar, to_bar, bars, total_bars}, becausecountstill reports bars evaluated; a client seeingcount=20000with a 500-long series needs that to tell a window from a short history.meta.profile.barsis rewritten to the windowed length and flaggedwindowed. Events and drawings carrybar_indexand are filtered to the window; objects with onlybar_time(strategy fills) have no index to match on and are kept, so trimming can never silently drop a fill. Implemented at the serialization boundary (backend/middleware/window.py) rather than inside the runtime, which leaves the compile path and every parity surface untouched. -
Live evaluation sessions over HTTP —
POST /session,GET /session/<id>,POST /session/<id>/tick,POST /session/<id>/append,DELETE /session/<id>. A session keeps the parsed script, its series, and its TA state alive, so re-ticking the forming bar is O(1) instead of re-evaluating every bar. Measured on 20k bars: full run 1,087.8 ms →update_last_bar0.130 ms (8,343x) andappend_bars0.127 ms (8,572x). Session init costs ~443 ms, so a session breaks even after its first tick. Tick and append both accept the same optionalfrom_bar/to_barenvelope window as/run; combined with a 500-bar window the same live update costs 0.227 ms and 37.2 KB, against 1,087.8 ms and 1,068 KB for a full run. Interpret only —compilehas no resumable evaluator state and is rejected withMODE_UNSUPPORTED.
Changed
- The Pro API now runs a single gunicorn worker (
-w 1, was-w 2) indeploy/pynescript-api.service,deploy/pynescript-api.service.d/tuning.conf,docker/entrypoint-api.sh, anddocker-compose.prod.yml. Session state is per-process, so a second worker would 404 on roughly half of all follow-up calls — a session created on one worker is invisible on the other. Correctness, not tuning: gevent still handles thousands of concurrent connections per worker and--max-requestsrecycling is unchanged. Both systemd files had to change: the drop-in wins on conflict, so a stale-w 2there silently overrides the base unit — exactly the failure mode the file's own comment warns about. The Cloudflare® container was alreadyGUNICORN_WORKERS=1. - Session store bounds: 15-minute idle TTL, 64 concurrent sessions, 30-second sweep. Capacity overflow returns 503
SESSIONS_FULLrather than growing until the OOM killer arrives. - Table export parity:
table.cellnow stores all v6 style kwargs (width, height, halign, valign, size, font, formatting, tooltip) in reference positional order (width, height, text_color, halign, valign, size, bgcolor, tooltip, font_family, formatting), and both export paths (export_for_api,export_compile_events_for_api) emit cell style,force_overlay, frame/border widths, andmerged_cells— AXIS bottom-panel tables get proportional columns, tooltips, and merges without a wire change on its side. - Compile drawing extras:
export_compile_events_for_apinow emits the box text/border extras, label tooltip/text extras, and polyline curve/overlay/fill fields the interpret host already emitted. Also adds the missingtext.align_*enum constants (halign + valign) and storesbox.newtext kwargs — both hosts produce identical dicts for AXIS paint. - OKF bundle:
okf/is an Open Knowledge Format v0.2 cache of the package, the Pro API, and the docs. The pre-commit hook drafts, links, and lints it. Generated parsers and the Pine corpora are left out of the map.
Fixed
-
/healthnever advertised the live-session endpoints.POST /session,…/tick,…/append,GET/DELETE /session/<id>were routable but absent from the healthendpointsmap, so the API reported 28 endpoints and no mention of sessions./healthis the discovery surface AXIS and agents read to learn what a host can do, so an unadvertised route reads as a route that does not exist. Two tests now guard it, in both directions: every session route is advertised, and every advertised session route is routable with keys byte-identical to Flask's rule strings so a rename in the decorator cannot desynchronise discovery from routing. Verified the guard fails when the entries are removed. The checks are deliberately scoped to the session routes rather than the whole map:/healthadvertises some routes only when a subsystem is enabled (runner_enabled()/scheduler_enabled()), so a whole-map invariant would flag that intentional conditional advertisement as drift. -
Interpreter/compile parity harness could not classify bgcolor differences (7 of 13 outstanding failures).
fill_background_onlywas computed solely from keys present on one side, so aBackgroundseries present in both runs — with colour strings ('rgba(...)') from interpret andNonefrom compile — fell through to a hardMISMATCHand was unrepresentable as the known compile-path fill gap.compare_series_mapsnow routes such keys to a separate, reportedfill_value_diffsbucket and lets them satisfyfill_background_only. The tolerance is deliberately narrow:_is_nonnumeric_only_differencereturns False the moment any disagreeing cell is numeric on both sides, so a genuine numeric difference on a fill key is still a hard mismatch. Only colour/NA cells on fill-shaped keys are absorbed, and they stay visible in the result rather than being dropped. -
array.copy(na)emitted a deadlist(None)into generated code.array.copyinlinedlist(x) if isinstance(x, (list, tuple, np.ndarray)) else [], which for a literalNoneargument renders aspt2 = (list(None) if isinstance(None, ...) else []). It never executed — theisinstanceguard is False — but the text reads like a crash and is whattest_chart_point_copy_not_list_noneguards against. Now routed through anarray_copy_valuebuiltin, matching howarray_sortis already handled. -
Generated docs packs no longer shred digits: the emoji strip in
scripts/docs/generate-exports.mjsused bare\p{Emoji}, which also matches ASCII digits participating in keycap sequences. Everyllm.txt/llms.txttherefore shipped mangled text —AGPL-3.0-onlybecameAGPL-.-only,ADR-001becameADR-,/v/chatbecame/v/chatwith digits eaten. Now strips\p{Extended_Pictographic}plus the skin-tone / variation / combining-keycap codepoints, so real emoji go and version numbers, ADR ids, and license identifiers survive. -
AXIS docs pack pointed at the wrong repository: the export pipeline hardcoded the PYNE repo URL for every product, so
/axis/docs/llm.txtannouncedRepository: https://github.com/hoox-sh/pyne. Each product now carries its ownrepoUrl. -
VPS Pro API memory growth: gunicorn workers now recycle (
--max-requests) on both the Hetzner systemd unit and the Docker entrypoint (GUNICORN_MAX_REQUESTS). Without recycling, workers grew past 1.6 GB each on the 3.8 GB VPS until swap filled 100% and evenGET /healthtook 6–14 s, so AXIS reported the engine as down. The unit is now versioned atdeploy/pynescript-api.service(+cors.confdrop-in) andscripts/deploy_vps.shinstalls it before restart.
Security
-
undici TLS certificate validation bypass (CVE-2026-84961 / GHSA-w293-vg96-wgc3, high) and five further undici advisories are closed in
cf/by anoverridesentry pinningundicito^7.29.1(resolves 7.30.0).BalancedPoolused to deep-clone its constructor options throughJSON.parse(JSON.stringify(...)), which cannot represent functions — aconnect/tlsoption carrying acheckServerIdentitycallback was silently dropped before reaching the TLS layer, so a certificate the caller's validator was written to reject was accepted.undicireachedcf/only as a transitive dev dependency (wrangler→miniflare); the sole runtime dependency is@cloudflare/containers, so the vulnerable path never shipped. Fixed regardless — a silently-dropped certificate validator is the wrong thing to leave lying in a tree that runs in CI. Verified with a cleannpm ci: resolves 7.30.0,npm auditreports zero undici advisories, andwranglerstill runs. -
sharp librsvg CVE-2026-96889 (GHSA-wq5f-xc86-pv6w, high) closed by pinning
sharpto^0.35.5(resolves 0.35.5) incf/. Samewrangler→miniflaredev chain; the bump pulls matching@img/sharp-libvips-*1.3.4 platform binaries and nothing else. -
brace-expansion DoS (2 high, 1 medium) closed in
vscode-extension/by pinningbrace-expansionto^5.0.12(resolves 5.0.12) undervscode-languageclient→minimatch. The three advisories were stack exhaustion via uncontrolled recursion inexpand_()(GHSA-qhr7-859c-m2p7) andparseCommaParts()(GHSA-6j4f-fj2g-mc7p), and quadratic-time expansion of{a},b}input (GHSA-q2hr-2g5m-vwhr). 5.0.12 is the strictest floor across all three.Both trees verified with a clean
npm ci(not an incremental install):npm auditreports 0 vulnerabilities incf/andvscode-extension/,wranglerstill runs, and the extension still compiles. Dependabot is now at zero open alerts for this repository.
Docs
- README version strings refreshed to 0.6.8 (PyPI + all three GHCR tags verified present).
Known limitation
Sessions are interpret-only (compile has no resumable evaluator state; create_session rejects it), and strategy fills are not rolled back across ticks — fills accumulate and strategy series history is overwritten rather than appended, the same caveat as the realtime tick loop in Runtime.run. Indicators and alert() conditions are unaffected. A live strategy driven through /session/<id>/tick needs that fixed first.
0.6.8 - 2026-09-26
Added
-
Tables in the bottom panel: Users can now move tables drawn by a script into a separate tab in the chart's bottom panel. To move a script's tables to the panel, open the "More" menu in the script's status line and select the "Move tables to bottom" option. To move the tables back to the chart, select "Move tables to chart" from the "More" menu or from the context menu opened at the top of the panel's tab. Tables in the bottom panel have different positioning and cell-sizing rules from those on the chart. All tables stack vertically in order from first to last, regardless of the position and force_overlay arguments of each table.new() call. The cells of each table also stretch as necessary to fit the allocated width and height within the pane, without truncating the displayed text. Additionally, users can select and copy the text from tables in the bottom panel, unlike tables displayed on the chart.
-
Improved line wrapping in square brackets: We've improved the line wrapping behaviors for code within square brackets ([ ]). Previously, all line-wrapped history-referencing operations or tuples required indenting each line after the first by any number of spaces that was not a multiple of four. The only exception was for square brackets enclosed in a set of parentheses, because code within parentheses can contain any amount of indentation, whether zero or a multiple of four spaces. We've extended the indentation flexibility for code in parentheses to all code between square brackets. Now, wrapped code within square brackets can use any amount of indentation without restriction.
Changed
- Interpret hot path loads call-site, assignment, and TA state by attribute
instead of
getattr, reuses each TA dict key across bars, and skips repeated argument checks for steadyta.sma/ema/rsi/stdev/bb/atr/highest/lowest. Calendar names (year,month, …) still materialize on first read. On a 2000-bar interpret bench, mixed TA went from 135 ms to 113 ms andplot(close)from 12.5 ms to 10.0 ms.
Fixed
ta.uono longer copies one buying-pressure ratio into all three averages. Interpret uses the three-window incremental kernel. Compile emitsnumba_uoin nopython mode.
0.6.6 - 2026-09-22
Runtime last-sample TA, convert-to-v6 identifier safety, webhook SSRF, LSP nested completion.
Fixed
ta.ao()no longer rebuildshl2every bar when the identifier is absent; the full-recompute path returns the last SMA sample instead ofNone. Period-onlyta.stoch/ta.cci/ta.wprskip series cap-slice copies on the incremental path. Period-onlyta.dmiuses the same last-sample incremental path. Incrementalta.bbshares one SMA+stdev window instead of two nested deques.ta.cog/ta.modeuse last-sample incremental kernels.- Convert-to-v6 leaves
ninsidefor n =bodies as the loop variable. - Interpret
color.*named constants use the Pine v6 palette (color.greenis#22AB94), matching compile_color_const. - Linter
C001only fires on snake_caseta.*assignments (fastMA/smaare quiet;pyne lintmatches the LSP filter). - Convert-to-v6 no longer rewrites v5 UDF definitions named
security/financial/ otherrequest.*leaves torequest.<name>(...) =>. v3period =/for n =stay user identifiers;n == 0still becomesbar_index. - LSP
strategy.completion keeps nestedrisk.*insert text; completion resolve no longer restores a fully-qualified snippet afterta.. Hover documents additional namespaces and drawing/collection types; barelinestays a type card. line.fillis cataloged as an alias oflinefill.newso AXIS pre-eval does not suggestline.all. Compile fillplot_metastampsplot1/plot2; interpret fill color is per-bar.
Security
- Alert webhooks unwrap IPv4-mapped / 6to4 / decimal IPv4, refuse HTTP
redirects, and re-check the URL at POST time.
POST /run/batchnow returnsWEBHOOK_URL_BLOCKEDinstead of silently skipping. - Oversized request bodies return JSON
PAYLOAD_TOO_LARGE(413). - Git OAuth device-flow
verification_urivalues are allowlisted togithub.com/gitlab.com. - Hosted runner GET
/scripts//scripts/:id//cron/jobsredactwebhook_urlwhenADMIN_TOKENis set and the request is unauthenticated. - Client
timeout_secondsis capped (default 120s,PYNE_RUN_TIMEOUT_MAX) so a huge value cannot hold a gunicorn worker until SIGKILL. POST /preview/chart,/preview/indicator, and/backtest/quickvalidate against their schemas (unknown fields rejected).
0.6.5 - 2026-09-14
Convert-to-v6 no longer rewrites user UDF names, parameters, or unpack targets.
Fixed
ta.*/math.*/ticker.*prefixes apply only to calls. UDF definitions (hma(...) =>), parameters namedmin/max/mode, and unpack targets ([rsi, dev] =) stay user identifiers. set01–04 scripts older than v6 parse 323/323 after convert.
0.6.4 - 2026-09-14
Convert older Pine to v6 in the editor, LSP, CLI, and HTTP.
Added
- Editor Convert to Pine v6: AXIS overflow menu + command palette, VS Code
PYNE: Convert to Pine v6/ lightbulb, LSP code action, andPOST /lsp/convert. Source-level rewrite from any older version (missing pragma = v1) — colors /n/ timeframe idents,ta.*/math.*/request.*namespaces,study(→indicator(, typedinput.*(),iff/offset. Not a semantic v6 migrator.
Changed
pyne convert --to 6now runs the full v1-v5 pipeline, not only leftoverstudy(/request.*names.
0.6.3 - 2026-09-14
Hosted script runner on Flask / VPS / container, plus pyne runner CLI.
Added
- Optional Flask hosted runner (
PYNE_RUNNER=1): SQLite script registry,POST/GET/DELETE /scripts,GET/PUT /cron/jobs,POST /cron/run. Background bar-close polling is a second switch (PYNE_RUNNER_SCHEDULER=1). Docker / VPS / Cloudflare® Container pick it up via env; default remains off. - CLI
pyne runnertalks to that API:deploy,list,show,delete,tick,jobs,enable,disable(--url/PYNE_API_URL).
0.6.2 - 2026-09-12
P1p plot-parity tail on official TV builtins.
Fixed
- Interpret UDF series parameters:
s[1]inside a function now tracks the per-call-site argument stream when the caller passed a scalar (src = close; updown(src)). Official Connors RSI and the TV builtin script set are 0 MISMATCH vs compile.
0.6.1 - 2026-09-12
Correctness follow-up on 0.6.0 dual-host risk, InterpretSession, and HTF
resample, plus the session API that landed after the v0.6.0 tag.
Added
- Persistent
InterpretSession: deltaappend_bars, realtimeupdate_last_barticks, TA rollback, confirm-on-append.
Fixed
strategy.cashas a qty-type identifier now selects cash mode on both interpret and compile (string"cash"was the only working form).- Compile
begin_barreceives bar time so day-scoped fill caps and consecutive-loss days roll onRuntime.run(mode="compile"). - Pending fills are risk-gated at fill time on both brokers; covering leftover cannot reverse-open after an intraday halt.
- Session
barstateno longer leaks across appends; confirm overwrites strategy history;islastis false on a confirmed bar when more bars follow;_once_firedrolls back with the bar-open snapshot. - HTF
lookahead_onleaks each bucket's final value from the period start on historical bars (not developing-as-of-this-bar);close[1]resamples previous HTF bars (same-TF falls back to chart history); bare D/W/M buckets followtimeframe.change(Monday weeks,syminfo.timezone). - Codecov per-flag uploads set
disable_searchso reports stay isolated.
Changed
- Disk IR cache v16 (
begin_barbar time, calendarchart_timezone(),strategy.cashqty-type emit). - Docs: PyneTS as standalone package (no
pynets/submodule); retired linter codes C003/W102/W103; version stamps 0.6.1.
Security
- wrangler 4.131.0 (sharp 0.35.4, GHSA-rgj7-g3m4-5g8c).
0.6.0 - 2026-09-10
Parity increments across strategy risk, realtime scope, timeframes,
request.security barmerge, and the linter.
Added
- Strategy risk:
strategy.risk.max_intraday_loss(value, type)honors percent-of-equity vs cash on both brokers; interpret enforces intraday loss plus the day-scopedmax_intraday_filled_orderscap, with order-level fill counting on both hosts. - Realtime: intrabar rollback of the
varscope plus series currents on interpret realtime ticks (varippersists);oncefires once from confirmed state. - Timeframes:
timeframe.changeD/W/M on the exchange calendar (syminfo.timezone, UTC default; DST-aware days, Monday weeks, calendar months); compile routes calendar TFs through object mode. request.security:gaps_on/lookahead_onhonored on the HTF resample paths (bucket-start na-gaps, forming-bucket reads); presence-vs-effect policy tags (gaps_lookahead_providedvsgaps_applied/lookahead_applied).
Changed
- Docs:
onceon grammar/ASDL/builder/unparser, interpret + compile pages, compatibility, glossary, FAQ, missing-features. Version table 0.6.0. docs/known_divergences.md: F-12…F-16 closed; D-02/D-04/D-06 narrowed to their documented residuals.- Disk IR cache v14 (calendar routing changed codegen).
Removed
- Linter: retired legacy rules
C003(indentedifwithout "braces"),W102(histogram → plotcandle),W103(var int x = na→ 0); codes stay retired so history stays greppable. LSPC003noise filter removed with the rule.
[0.5.0] - 2026-09-07
Performance release across the whole stack, plus several correctness fixes surfaced by the work.
Changed
- Slotted AST nodes. ASDL generator emits
@dataclass(slots=True); the sharedASTbase carries__slots__for evaluator call-site stamps. Removes the per-node__dict__(large scripts allocate tens of thousands of nodes). Regenerate viapython src/pynescript/ast/grammar/asdl/tool/generate.py. - LSP typing latency (~3-5×).
didChangeno longer runs two full ANTLR parses (the linter accepts a pre-builttree=), and parse+lint now run debounced (250ms,PYNESCRIPT_LSP_DEBOUNCE_MS) on a worker thread so the event loop stays responsive. Semantic tokens, inlay hints, hover decl maps, and workspace/symbol results are memoized per document version; completion items, fuzzy-filter fields, and categories are cached per metadata load; references/definitions dedupe is O(1) per line. - TA incremental coverage.
ta.max/ta.min/ta.rangenow use the incremental kernels;ta.highest/ta.lowest/ta.wpr/ta.stochincremental use monotonic-deque sliding extremes (amortized O(1)/bar instead of O(period) scans);ta.rcirank computation is O(n log n) (was O(n²) per bar);ta.vwmaincremental drops its O(period) na-scan. - Per-bar
importstatements hoisted out of hot paths (+=assignment, subscript call-sites,switch, overload dispatch);_commit_unwritten_historyiterates a cachedhistory ∩ varintersection. - Parse-cache hit scrub is a specialized stack walk (was generator BFS);
Runtime._parse_scriptno longer performs a second redundant full-tree walk. - Builder: single-line token fast path skips the per-node
stop.textsubstring allocation; simple string literals skipast.literal_eval. - Backend:
/runapplies a server-side default timeout (PYNE_RUN_TIMEOUT, 30s) so pathological scripts cannot kill a gunicorn worker; PBKDF2 key hashing is LRU-cached (~50-100ms → O(1) per authenticated request); SSRF DNS verdicts are TTL-cached; optional off-thread webhook delivery (ALERT_WEBHOOK_ASYNC=1); chart renderer uses the thread-safe OO matplotlib API (pyplot globals raced under--threads 4). - OHLCV pack/list caches are bounded by tracked bars
(
PYNE_OHLCV_CACHE_MAX_BARS, default 2M), not just entry count. - Strategy
position_size/position_avg_price/closedtradesend-of-bar history is capped at 512 entries.
Fixed
- Five compiler/evaluator subtree walks used
node.__dict__.values(), which silently collected nothing on slotted nodes and broke UDFvar-local and history-series detection; traversal now goes through_fields. _as_seriessame-bar cache could false-hit on a different series (single interned-int fingerprint): fingerprint uses the two newest samples and the host clears the cache every bar.- OHLCV pack cache evicted from the list cache, so the pack cache was never bounded.
didChangewithout a priordidOpencrashed the LSP handler (now treated as an empty open); closed documents leaked into the workspace parse-error set.
0.4.4 - 2026-09-05
Added
onceconditional structure (Pine Script™, August 2026). Executes its block the first time the optional condition is true on a closed bar, then never again. Soft keyword so existingonceidentifiers still parse. Interpret honors realtime rollback (unconfirmed ticks can re-fire); compile is historical (isconfirmedalways true).
0.4.3 - 2026-09-04
Added
pynescript convert --to 5|6— source-level v5 ↔ v6 rewriter (//@version,study(→indicator(on the way to v6, baresecurity(/financial(/ … ↔request.*). Comments and string literals are left alone. Not a semantic migrator (bool-as-int,natightening).
Fixed
- Compile
plot(..., display=)bitfield is folded intoplot_attrssoplot_metacarries it (follow-up to 0.4.2). - UDF
var+ history (x[1]) is per call site; interpret no longer drops every-other-barnavs compile (e.g.moon_phases.pine). table.merge_cellsno-ops onnacoordinates instead ofint(None)on the last bar.- Remaining CodeQL: stack traces not returned in alert-forward errors; ReDoS regexes rewritten as linear scans.
Changed
- Pro API key store (breaking for SHA-256-only records): keys are
PBKDF2-HMAC-SHA256 (
v2:). JSON files keyed by the raw secret are rehashed on load. Orphaned 64-hex SHA-256 records are skipped — remint those keys. - CI: ruff E/F/W over
backend/; VS Code VSIX packaged with@vscode/vsce(@types/vscodepinned toengines.vscode1.91);download-artifact@v8; PyPI publishskip-existingso a duplicate tag run does not 400. - Dependabot weekly updates landed (Actions, docs, vscode-languageclient 10, TypeScript 7, wrangler).
0.4.2 - 2026-08-26
Fixed
- Compile
plot(..., display=)is stored onplot_attrssoplot_metaexports the display bitfield. - First CodeQL pass: errors, high, and medium alerts on the tagged tree.
0.4.1 - 2026-08-26
Fixed
- Compile
plot_metabackfills hline linestyle from__drawings.
0.4.0 - 2026-08-25
Changed
- VPS origin is Hetzner
pynescript.online(204.168.138.51) —scripts/deploy_vps.shdefaults to SSH hostpynescriptand skips AXIS dist (PWA is on Cloudflare® Pages). API-only gunicorn behind nginx;axis-pwa.serviceis optional.
[0.3.18] - 2026-08-25
Added
- AXIS contract parity:
plot_metaexports Pine visual params (offset,histbase,trackprice,join,editable,show_last) on interpret and compile hosts; omitted keys equal Pine defaults. plotcandle/plotbarexport OHLC as close-primary series plus<title>.open/.high/.lowsiblings referenced fromplot_meta(open/high/low/close), withwickcolor/bordercolor.- Drawing/table exports gain stored-but-unexported styling: box
extend/border_style/text styling, label tooltip/alignment/formatting,
polyline curved/fill_color/force_overlay, table frame_width/border_color/
border_width plus
merged_cells. - LSP builtin metadata carries canonical Pine v6 signatures for plot-family builtins.
Fixed
- Positional
plot(...)calls misread linewidth/style indices (now linewidth = 3rd arg, style = 4th per Pine v6 signature). table.clear(t, r0, c0, r1, c1)clears only the requested range;table.merge_cellsrecords ranges and exports them.- Compile-mode
plot_metano longer hardcodeslinewidth=1when source declares constant linewidth/style/offset/histbase. - Compile IR cache no longer shares entries whose titles/kinds/attrs diverge (metadata bleed across sources).
- Positional wickcolor/bordercolor args on plotcandle/plotbar are captured (previously kwargs-only).
[0.3.17] - 2026-08-19
Fixed
- Compile object-mode residuals — user
round()UDF call sites pass free/chart formals; missing libraryalias.method(...)stubs arenanot PythonNone; same-aritynegate(float|bool|color)dispatches by argument type so hex colors stay off float64 series; method overloads on UDT fields (this.wins.getAvgProfit()) pick the field's type, not the outer receiver.
[0.3.16] - 2026-08-19
Fixed
- Compile object-mode corpus residuals (set06) — UDF
int m = ifstays a local (not scriptm_arr); nested UDFs still receive script-levela_arrwhen a param shadowsa; UDFvar voldoes not steal chartvol_arr(get_countsarity);Type.new()locals mark UDT returns sos.strengthis notfloat(dict); statement-formx = switchno longer emits invalidx = if;chart.point.copy/box.copyclone dicts instead oflist(None). - Numba object-mode helpers —
Noneno longer TypingErrorsnumba_max/min/absand related scalars;timestampskips a leading timezone string;valuewhenand running max/min fall back on object arrays; Pineint(na)isna(pine_int, not Pythonint(nan));ta.pivothighna lengths;ta.cumusessafe_float. - Matrix handles — UDF/
kronresults stay list-of-lists objects; builtins do notlen()a numpy scalar. - Corpus sanitize — keep trailing commas on wrapped
=>calls; tab-indented bodies after) =>; drop Hugo/markdown tails after a complete script; keep nested/* */comments; stub jinja/markdown planning docs. - Grammar —
NEWLINE+before indented=>/ if / for / while / switch bodies.
Changed
- Docs: missing-features / implementation-status / roadmap / progress report aligned with compile object-mode residual recovery (P1p plot MISMATCH tail still open).
[0.3.15] - 2026-08-19
Added
pynescript download-builtins— catalog + download TradingView® builtin Pine templates via pine-facade (--list/--yes/--limit).scripts/search_clone_pine_pool.py— search and shallow-clone GitHub Pine repos for corpus collection.cf/— Cloudflare® Containers Worker that fronts the Pro API and keeps a named instance warm.
Improved
- LSP hover — types/qualifiers (
series/float), namespaces (tainta.sma), user functions/assignments/type/enum, and longer keyword briefs. Builtin cards keep signature fence + params when metadata has them.
Fixed
- Compile set06 residuals — missing
array/map/matrixhelpers,for+continueincrement, for/while-as-expression emit, multi-value and default-onlyswitch,/* */comments, mapfor-inpairs,ta.dmiscalar assign,matrix.setexpression form,npunpack shadowing, nopythonTypingErrorobject-mode retry, tuple/UDT stores off float64 series. - Corpus sanitize — RST/Hugo/MDX chrome, mustache
{{IDENT}}, indentedstudybodies, column-1 ternary tails, torn string fixtures.
[0.3.14] - 2026-08-18
Fixed
strategy.position_avg_price— repeatingstrategy.entry("L")no longer overwrites a filled position (avg was tracking last close). Extra same-direction entries only whenpyramidingallows; interpret and compile.strategy()leverage vs margin — whenleverage=is set it wins (margins derived from it).margin_long/margin_shortonly apply when leverage is omitted. Compile broker accepts those kwargs the same way.
Changed
- Docs / comments: PYNE open-entry cap is
pyramiding + 1(TVpyramidingdefault 1 ≡ PYNE 0). Unused compile-brokerreplace_same_idkwarg removed. - Tests: leverage-vs-margin (both set), compile margin-only 5× cash sizing, same-id pyramid VWAP (third fill blocked), pending same-id limit/stop replacement; free-tier rate/slot no-ops when the switch is off.
- Free-tier
/runguards are opt-in —FREE_TIER_LIMITS(default off). Bar/script/rate/concurrency and chart/mock-onlydata_sourceapply only when set to1/true/yes/on. Production compose still enables them (FREE_TIER_LIMITS=1). Healthfeatures.free_tier_limitsreports the flag. Pro API / endpoint abstracts no longer read as always-on. - Product landing and end-user hub list
pyne optimize/POST /optimize.
[0.3.13] - 2026-08-17
Fixed
- Optimize scores broker fills (not
strategy.exitplacements); trail-only exits; warmup pairing; JSON-safe study scores. - Walk-forward train+test run cap; HTTP
min_trades=0/ 400 mapping; CLI walk-forward windows; continuous Random/TPE sampling; grid product cap. - Incremental
ta.dpo/ta.kstdispatch;timeframe.change("1M")is monthly; compile table cells/colors and deleted linefills.
[0.3.12] - 2026-08-17
Added
- Strategy hyperparameter search —
pynescript.optimize(TPE / random / grid, holdout + walk-forward) scores realRuntimestrategy events.POST /optimize(same free-tier gates as/run) andpyne optimize. Not/backtest/quick; not a Pine builtin. - Real
timeframe.changeon interpret and compile (UTC fixed-width buckets; bar 0 is a new period). - HTF
request.securityallowlist includesta.wmaandta.rma. - Incremental interpret kernels for
ta.aroon,ta.dpo,ta.donchian, andta.kst. - Dual-host plot/drawing identity: compile geometry-only AXIS export, plot_meta kinds, coordinate snapshot at create/set.
[0.3.11] - 2026-08-16
Added
- Incremental interpret
ta.nvi/ta.pviplus matching compilenumba_nvi_inc/numba_pvi_inc. - Flask
POST /runtimeout_secondsandPOST /run/batchlibraries. - Dual-host goldens: Supertrend mid±factor·ATR, trail OHLC, foreign
request.*→na, compile plot keys.
Changed
- Interpret
ta.pvt/ta.vptis cumulative (matches compile / TV). Bar 0 is0.0. pynets/submodule pin v0.2.0 (interpret + JS compile). Python Runtime remains the oracle.
Fixed
- Compile MACD signal SMA-seeds the MACD line; OBV skips the first close change.
- Compile
ta.ao/ta.aroonkernels (were all-na). - Compile foreign
request.securitytuple unpack no longer invents chart close. - Compile titled
bgcolor/ emptyplot(..., title="")keys match interpret (disk IR v10). - Compile
strategy.exitkeeps the Pine exit id for trail events.
[0.3.10] - 2026-08-16
Added
- Incremental interpret kernels for
ta.obv,ta.wad/wvad,ta.cmf, andta.klinger(PYNE_TA_INCREMENTAL).
Changed
- Runtime interpret hot path (Round 9): direct Assign/
plot/Call dispatch, skip unused derived OHLCV series, plot bar-reuse. Same-machine bench @ 2000 bars: minimal 2.7×,ta_sma2.0×,ta_combo1.45×.PYNE_SERIES_RINGstill default off. ta.vwap()with no source still updateshlc3when that identifier is absent from the script.
[0.3.9] - 2026-08-16
Added
FunctionDef.returns— UDF/method return types survive parse → unparse (int ilog2(...)).- Incremental
ta.median/ta.cmoNumba kernels; statementhline/fillstay nopython with synthesized drawings. - Thread-local ANTLR lexer/parser reuse (warm SLL DFA across distinct sources).
- LSP Docker image
ghcr.io/hoox-sh/pyne/lsp(stdiopyne-lsp, slim[lsp]only). Published onv*tags with api/cli.
Changed
- Grammar left-factors typed names; bare
x =isAssign,=reassignment only on attribute/subscript. - Evaluator:
varhistory carry at bar start; series maxlen matches host ≥1000;_pine_site_idfor UDF/call-expr history. - pyne-vscode publisher namespace is
hoox-sh(extension idhoox-sh.pyne).
Fixed
Runtime.run(mode="auto", libraries=)forwardslibrariesinto interpret fallback.- Windows CLI
--helpno longer crashes on cp1252. Open VSX unknown-publisher no longer fails Build & Release. - CORS — AXIS product Origins +
/healthfree CORS path (also in 0.3.8 notes). - Build & Release: Create Release no longer downloads Docker Buildx cache artifacts.
[0.3.8] - 2026-08-15
Added
- Compile UDT field defaults on
Type.new()(omittedbool x = falsestaysFalse;bool(np.nan)no longer trips flags). Fixes interpret↔compile071Entry plot. register_library_sourcefinalizes library exports soRuntime.run(..., libraries=)/POST /runimport ns/Lib/1actually binds members.- Supertrend first-party goldens lock the simplified mid±factor·ATR contract (interpret full/inc + Numba).
- LSP: user-enum completion/hover/outline; soft-keyword hover;
plot(ta.leaf insert; drop C001/C003 false positives.
Fixed
trail_points=0/nano longer disables a validtrail_offset(interpret + compile).- VPS deploy AXIS health probe uses
:80(not stale:8081).
Changed
- Compile disk IR cache meta version 7 → 8 (UDT defaults).
- Docs honesty: tick-offset
profit/loss, omitted bid/askna, H1 Runtime unify done.
[0.3.7] - 2026-08-15
Added
Runtime.run(..., libraries=)— optional[{namespace, name, version, source}]registered viaregister_library_sourcebefore interpret so AXISimport ns/Name/verresolves published git folders. Pro APIPOST /runaccepts the samelibrariesfield.
Changed
- Runtime hot path: skip series dual-write when
PYNE_SERIES_RING=1; tick-offset exits, incremental MA, plot pack, kernels.
Removed
- Colocated
pine-worker/TypeScript extra tool (parser/evaluator port). Lives in the siblingpine-workercheckout, not this repo.
[0.3.6] - 2026-08-13
Added
- Binary search in UDT arrays (Pine August 2026):
array.binary_search(),array.binary_search_leftmost(), andarray.binary_search_rightmost()acceptsort_field(const int field index, default 0, or const string field name) so they can search arrays of user-defined types. The array must be sorted by the same field in ascending order. Interpret + compile object-mode, with dual-host parity tests. - Runtime
timeout_seconds: optional wall-clock circuit breaker on interpret (every 32 bars); partial results withtimed_out+error_kind=runtimefor edge/cron budgets (shared by Pro API and pyne-worker). linefill.newexport —DrawingRegistry.export_for_apiserializes line fills astype: "linefill"quads (line1 + line2 endpoints) so AXIS can paint the band.- *Compile drawing set* fold_* —
fold_compile_drawing_mutationsappliesline.set_*/label.set_*/ … onto live handles and drops set events so compile/rundrawings match interpret final state. - Compile drawing
*.delete—line.delete/label.delete/box.delete/polyline.delete/table.deleteemitkind: 'delete'events on__drawings(target =*.newhandle);fold_compile_drawing_mutationsdrops deleted objects (was MVP no-op). force_overlayon export — line/box/label payloads includeforce_overlayfor AXIS pane routing.
Changed
- H1 dual-host: pyne-worker
pynescript_backendis a thin wrap over packagepynescript.runtime(strict OHLCV validation only); vendor via./scripts/sync_vendor.sh.
[0.3.5] - 2026-08-12
Fixed
- Drawing export (
line.new) —export_for_apino longer drops lines whosexloc.bar_indexis past the last bar (classicbar_index + 1onbarstate.islast). Extrapolates from series period; emptybar_timespasses bare bar index for AXIS logical mapping.
[0.3.4] - 2026-08-10
Added
- Package Runtime SoT (
pynescript.runtime): bar-loop host, series, CustomEvaluator live in the installable package;backend.*re-exports for Pro API. - First-party dual-host TA goldens (ATR / Supertrend / Keltner) and full
test_ta_incrementalCI gate. - Strategy exit surface: pending stop/limit + OCA;
from_entrymulti-leg (interpret + compile);qty_percent; minimal trail (interpret + compile); compile risk halt cascade (allow_entry_in,max_position_size,max_drawdown,max_cons_loss_days,max_intraday_loss,max_intraday_filled_orders); open/closed trade fields + MAE/MFE. request.securityhonesty + HTF resample: policy meta on Runtime; same-symbol coarser TF OHLCV bucketing; allowlisted simpleta.sma/ema/rsi/atron HTF.- Realtime host simulation:
realtime_last_bar/realtime_ticks/realtime_bars/realtime_from_barforvaripmulti-tick tests. - Free-tier Pro API guards (bar/script caps, rate, concurrency, SSRF-safe webhooks, chart/mock-only free data).
- Hash-only JSON API key store; first-party fixtures under
tests/fixtures/first_party/. - pine-worker series lookback polarity + parity smoke (
series[1]previous bar). - Plot host:
plot.style_*constants, style/linestyle capture, plotshape size export.
Fixed
- EMA dual-host seed (full-list SMA seed matches incremental/Numba).
ta.atrWilder RMA on interpret + Numba.- AugAssign / tuple unpack series binding; unparser
visit_Simple; linter C004/W002. - Enum/string series history so
d[1]works for plotshape flips. - vscode-extension transitive
brace-expansionDependabot high (2.1.4).
Changed
- CI Core runtime gates parity, strategy, series, TA incremental, first-party goldens, runtime package, free-limits.
- Docs:
docs/known_divergences.md, audit sprint status notes.
[0.3.3] - 2026-08-09
Fixed
- Corpus residual (C1, set01–04): dual-namespace user methods vs bare ta aliases
(
method dmi/float dmi = dmi(...)no longer mis-routes tota.dmiafter series assign);line.get_price/ line getters soft-na onnaline or endpoints and coerce PineSeries samples;request.securityOHLCVT +timelist unpack on different TF; sanitize dangling binary ops inside unclosed trailing calls (truncated docs scrapes). ta.dmisoft-na on unresolved /nalength (aligned with other TA period soft-na).
Changed
- Local open-source corpus set01–04 (2477 scripts, not shipped in git): parse 99.96%
(2476/2477) and Runtime interpret 100% excl. EXPECTED_FAIL (2466 OK + 11 intentional
demos); set01 Runtime 249/249. Harness classifies path-listed intentional demos
(library
runtime.error, lower-TF guards, pathological loops) as EXPECTED_FAIL. - Docs / landing: README, compatibility, roadmap, missing-features, and marketing numbers updated to the 2026-08-09 corpus snapshot (not TradingView® platform parity).
[0.3.2] - 2026-08-09
Changed
- Console scripts: preferred names are
pyneandpyne-lsp. Legacypynescript/pynescript-lspremain installed as aliases (same callables). Import package is stillpynescript; PyPI dist ishoox-pyne. Docs, VS Code auto-detect, and editor client configs preferpyne*with fallback topynescript*.
[0.3.1] - 2026-08-09
Added
- Strategy average-price models (pynescript extension):
strategy(..., avg_price_model=)"stock"(default) — multi-leg FIFO reweight ofposition_avg_priceon partial close (TV-like)"futures"— sticky net AEP until flat (linear USDT-M / BTCUSDT-style)"inverse"— accepted; sticky reduce (harmonic add deferred)- Tokens:
strategy.avg_price_stock/avg_price_futures/avg_price_inverse
- Leverage for futures UI (pynescript extension):
strategy(..., leverage=N)- Scales percent/cash default qty:
qty = margin × leverage / price - Margin held = notional / leverage; free cash adjusts accordingly
- Simple
strategy.margin_liquidation_pricewhen leverage > 1 - Derives TV-style
margin_long/margin_short% as100/leverage - Read-back:
strategy.leverage
- Scales percent/cash default qty:
- Dual-path wiring: interpret + compile broker + compiler emit for both options
- Docs: stock vs futures avg semantics; TV vs PYNE notes on
inputbeforestrategy()
Fixed
- Compile broker ctor no longer emits
name_arr[__bar_idx]for strategy kwargs (undefined at ctor time). Const-like input/literal defvals fold into ctor (e.g.lev = input.float(10)thenstrategy(..., leverage=lev)→leverage=10).
Changed
- Compile emit allowlist also wires
default_qty_type/default_qty_valueintoCompileStrategyBroker(...).
[0.3.0] - 2026-08-06
First public PYNE release. PyPI distribution name is hoox-pyne
(plain pyne / PyNE is taken by an unrelated package; import/CLIs remain
pynescript / pynescript-lsp). Install: pip install "hoox-pyne[lsp]".
Added
- Alert engine (
AlertsMixin): TV-stylealert.freq_*normalization, once-per-bar dedup, once-per-bar-close gating,alertconditionfire-on-true, host helpersexport_alerts/export_alerts_from_evaluator. - Dual-host alerts export: Pro API + pyne-worker
Runtimeclear/exportalerts(and optionalalert_conditions) on interpret/run. - L2 alert webhooks: Pro API
backend/alert_forwarder.py(webhook_url,ALERT_WEBHOOK_URL, last-bar filter, batch JSON); pyne-worker edge webhooks + cron last-bar delivery. Docs:docs/pyne/runtime/alerts.mdx. - Roadmap residual backlog IDs H1–L3 (dual-host, corpus tail, warm compile, series/TA, optional fidelity, long-horizon); see
docs/ROADMAP.md(2026-08-01). L2 closed (Pro API + edge). - Corpus C1 residual goldens: bare
tonumber,math.isfinite, strategyclosedtrades/opentradesentry_id/comment/max_drawdown/max_runup accessors; tests intests/test_corpus_runtime_residuals.py. - Interpret↔compile plot parity harness:
scripts/compare_interp_compile.py(multiprocess series compare with--file-list,--timeout-sec,--ignore-hline-keys,--ignore-fill-keys, and wave workers). - Parity tests:
tests/test_interp_compile_parity.py,tests/test_dividend_yield_parity.py, and R8/R9 kernel suites. - Compiler:
time_arron the compiled execute signature;numba_timestamp/numba_utc_parts; titledfill()series export;clear_numba_function_cacheswith corrupt-cache recovery. - Compile path for
numba_rci/ta.rci. - Strategy events system: StrategyEvent dataclass, full emission from strategy.* builtins, parity test corpus.
- pine-worker/ as colocated extra tool: TypeScript evaluator port + Python to TS converter script.
- var / varip declaration modes and ReAssign support.
- Multi-target Docker image (
api/api-dev/lsp),docker-bake.hcl, prod compose overlay, Makefile docker helpers. - Key-store backends selectable via
STORE_BACKEND(json|sqlite|redis) for multi-worker / multi-replica deploys. - PyPI publish workflow (Trusted Publishing on
v*tags) and package build job in CI. - Compiler disk IR/module cache (
PYNE_COMPILE_DISK_CACHE, default on) + typedCompileError*hierarchy +prewarm_numba_builtins(). - Runtime structured errors:
error_kind(parse|compile|runtime|data|order|mode),error_type,error_bar(API/runforwards).
Changed
- GitHub / package metadata for org
hoox-sh/pyne: project URLs, Docker image source label, docs, CONTRIBUTING, and PyPI Trusted Publisher owner. Seedocs/pyne/devops/publish-checklist.mdx. - PyPI distribution name is
hoox-pyne(import/CLIs remainpynescript/pynescript-lsp). Avoids collision with upstream elbakramerpynescriptand the unrelated pre-existingpyne/PyNEproject on PyPI. - Default image version labels / bake / Cloud Build substitution aligned to 0.3.0.
- Compile
request.securitypolicy: same-symbol simple OHLCV only; other foreign tickers and complex expressions resolve tona. - Disk IR meta version bumped when titled fill series export landed (and again for R8/R9 parity kernels).
- Interpret bar-loop residual wins (visit/Call arg plans, series last-sample, residual TA): ~1.24×
ta_combovs Round 5 (~137 ms @ 2k bars). - Compiler stays numeric for more history/math/chart surface; viewport right bar time is
(n_bars-1)*60000in compile mode. - Runtime
mode=auto: non-emptyinputsforces interpret with clear fallback reason; object-mode compile no longer requires Numba. - VS Code extension rebrand: PYNE — Pine Script™ for VS Code (
pyne0.3.0), HOOX logo icon, marketplace description as part of the HOOX open trading stack, TradingView® / Pine Script™ trademark disclaimer, and richer TextMate syntax highlighting. - VS Code extension packaging: esbuild-bundle
vscode-languageclientinto the VSIX, explicitonCommandactivation, resilient command handlers, and shared output channel. - CI rewritten for the post-AXIS-extract repo: Python lint/test matrix, package build, Docker smoke; removed dead
frontend/jobs. require_admin_tokenenforcesADMIN_TOKEN+X-Admin-Token(fail-closed); prod compose drops host source mounts viavolumes: !override.pyproject.tomlproject URLs, Alpha classifier, Python 3.13,proextra includesredis.- Updated documentation (ROADMAP, missing_features, implementation status, LSP plan, devops Docker) to reflect current state.
Fixed
- R8/R9 interpret↔compile corpus parity: foreign-na / MTF
request.security, Heikin-Ashi security, TA call-site slots, UDF series locals per Call site, series assign bar key(site, name), PineSeries snapshot for typed float/nz/array.set(BBI ring buffer),ta.vwap(hlc3[, anchor]),time(...)[1]call-expr history, strategyposition_size/avg/closedtrades[n]end-of-bar history, Pine==/!=withna(na==naTrue; other na compares False vianumba_pine_eq/ne). - Builtin kwargs merge no longer drops explicit trailing
None/ Pinena(e.g.array.push(id=a, value=na)), unblocking many corpus library scripts. - Corpus C1 8-agent residual pass:
str.replace4-arg/occurrence + coerce; richertimestampdate strings + TZ-first; series negative/na/OOB index →na; TA float/series periods; color hex/string channels;syminfo.prefix/tickerdual-mode; array get/set soft index +index_2d_to_1dstub polyfill;hour/dayofmonth/… series+timezone arity. - set05 6-agent pass:
timestamp(9999,…)year-first + calendar overflow;strategy.initial_capital =reassignment;timenow/dayofweek.*; sanitize keepstype == "SMA"ternary chains; v4random/offset/round_to_mintick+ticker.pointfigurefull arity; call-site cache stored on AST node (fixes id reuse collisions). - set05 residual round 2 (6 agents): bare TA series
obv/accdist/vwap;ta.linreglength<2→na;ta.kama2-arg; UDF name clobber restore; array.push soft arity +newcoloraliases; multi-island sanitize merge for UDF defs; missing UDF soft-na; int()/tonumber soft coerce; ticker.modifyadjustment=; kwargs merge + timestamp const-fold + static for-to. - Round 6 multi-agent pass (perf + correctness + error handling + compiler coverage).
- Compiler nopython kernels:
ta.dmi/ta.adx/ta.supertrend/ta.alma/ta.percentrank(match interpret oracle). - Incremental interpret TA for residual full-history paths:
mfi,sar,kc/kcw,alma,correlation, percentiles (behindPYNE_TA_INCREMENTAL). - Strategy exit commission and exit slippage on interpret + compile paths; bad order args emit events instead of silent fills.
- Stable
CRYPTO_KEY/METADATA_KEYresolution for Fernet metadata encryption (GitHub secrets wired). - User series no longer shadows bare builtins (
ad/tr/obv/pvt):plot(ad)emits the user series instead of re-emitting the Chaikin A/D stub. highestbars/lowestbarsuse negative TradingView®-style offsets (Aroon parity).- Compile Wilder RSI matches interpret (was a rolling SMA of gains).
- NaN-safe EMA/RMA seed for ATR custom
ma_functionand nested DEMA. - UDF last assign of
nano longer retains a prior tuple unpack (ADX early zeros). math.avgpropagatesna;ta.rocuses the standard formula;wmarequires a full non-nawindow;ta.cumtreatsna/ IEEE NaN as 0.request.security: foreign tickers and complex expressions resolve tonainstead of inventing chart close;dividend_yield/ CVI interpret↔compile parity.- Import stub plot cells are not serialized as color strings.
auto_fibinterpret and compile raise the same insufficient-pivot errors;for/toauto step;chart.pointobject dtype.- Interpreter:
ta.rising/ta.falling/ta.highestbars/ta.lowestbarsno longer raiseTypeErroron Pinena(e.g. VIDYA warmup on MA-STER). - Crossover equality aligned with TV/numba (
<=/>=on previous bar); short series rising/falling in bar mode. - Body
TypeErrorin call dispatch no longer soft-fails tona(signature mismatches still soft); strategystrategy()apply fails closed. - Compile object-mode:
array.sort/sort_indiceshonorsort_field;array.fillrange;map.keys/valuesnot coerced viasafe_float. - Corpus sanitize: multi-version islands, UI chrome, safer ternary/call/type-field repairs without FP on
?in input titles. - CI Ruff E,F,W gate: F821/
Anyimports and F401 unused imports cleaned for green CI on main.
Removed
- Stale
Dockerfile.api(folded into multi-targetDockerfile). - Dead
technical_refactored.pyand internal refactoring notes from the published package tree. - Broken AXIS-only GitHub workflows (
axis-nightly, PWA/e2e jobs) — AXIS CI lives in jango-blockchained/axis.