[PyneTS]
TypeScript / Bun library port of PYNE — parse, unparse, Runtime.run. Python remains the semantic source of truth.
PyneTS
PyneTS (@hoox-sh/pynets, currently 0.2.0) is the TypeScript / Bun library for Pine Script: parse, unparse, and Runtime.run. Public names match Python pynescript. Python pynescript.runtime is the source of truth — when semantics disagree, Python wins.
This is not a Cloudflare Worker, not a Numba compile path, and not a TradingView platform substitute.
Note
This PYNE checkout pins the pynets/ submodule at annotated v0.2.0 (@hoox-sh/pynets 0.2.0 — interpret + JS compile, matching npm). Python pynescript.runtime remains the semantic oracle.
Install
bun add / npm install / esm.sh. CLI still needs Bun.
Runtime
na is null. Lookback, TA call-sites, foreign security → na.
CLI
check / format / run / dump / info. Pipes stay JSON.
Compile
JS bar-loop emit. mode interpret | compile | auto.
Parity
Compare plots against Python Runtime.run on the same bars.
Ecosystem
PYNE · PyneTS · pyne-worker · pyne-agent-worker · AXIS · HOOX.
Abstract
Most TypeScript Pine ports rewrite the language. PyneTS does not. It is the library-shaped port of PYNE: the same ANTLR grammar, the same ASDL field names (kind, lineno, col_offset, …), the same interpret contract.
Source (.pine / .pyne)
→ shared PYNE .g4 (TS ANTLR target — not forked here)
→ ASDL AST
→ bar-loop (interpret | JS compile | auto)
→ plots / series / events / drawings / alerts
Standalone checkout: github.com/hoox-sh/pynets. PYNE consumes it only as the pynets/ git submodule — never copy sources into hoox-sh/pyne.
import { parse, unparse, Runtime } from "@hoox-sh/pynets";
const src = `//@version=5
indicator("sma")
plot(ta.sma(close, 3))
`;
const tree = parse(src);
unparse(tree);
const out = new Runtime("AAPL").run(src, [
{ close: 1 }, { close: 2 }, { close: 3 }, { close: 4 },
]);
// out.plots, out.series, out.count
// new Runtime("AAPL", { mode: "compile" }) — JS bar-loop emit (not Numba)
// mode: "auto" tries compile, then interpret
Conceptual model
Invariant: PyneTS is a library you import. pyne-worker is the production Python Cloudflare isolate for POST /run. AXIS engines still call Python (Flask, Pyodide wheel, Worker proxy) — they do not import @hoox-sh/pynets today.
Interface surface
| Name | Role |
|---|---|
parse(source) | ANTLR → ASDL tree. Throws PinescriptSyntaxError |
unparse(tree) | Tree → normalized source |
dump(tree) | Debug dump |
tokenize(source) | Lexer tokens |
new Runtime(symbol, options).run(source, bars, extra?) | Bar-loop evaluate |
Runtime.stream(source) | Push-driven re-eval |
Runtime.runProvider(source, provider) | Fetch bars then run |
compileScript / transpile | JS emit (not Numba) |
CLI pynets | check format run dump info |
Default mode is interpret. Constructor and per-call extra accept mode: "interpret" | "compile" | "auto".
What this is not
| Confused with | Reality |
|---|---|
| pyne-worker | Python Cloudflare Worker. Vendors pynescript.runtime. POST /run. See pyne-worker. |
| pyne-agent-worker | NL authoring host. Not an evaluate library. See agent. |
Python pyne run | Compile-only smoke on synthetic bars. PyneTS pynets run calls Runtime.run. |
| Numba | Python compile backend. PyneTS compile is JS emit (object-mode analog). |
| AXIS engine | AXIS does not load this package. |
Internals (repo paths)
Standalone (/home/jango/Git/pynets or the published package):
| Path | Role |
|---|---|
src/index.ts | Public barrel — do not re-export generated ANTLR |
src/ast/helper.ts | parse / unparse / dump / tokenize |
src/ast/nodes.ts | Hand-written ASDL nodes |
src/generated/ | ANTLR TS — do not hand-edit; bun run generate |
src/runtime/interpret.ts | Runtime, interpret host |
src/runtime/compile/ | JS emit (transpile / compileScript) |
src/cli.ts | TTY CLI |
test/interpret_*.test.ts | Focused interpret tests |
PYNE checkout: pynets/ submodule. Grammar SoT stays in PYNE resource/*.g4.
Invariants & edge cases
- Python wins. Do not invent TradingView platform behaviour that Python does not implement.
naisnull. Non-finite in/out isna.na == nais true. Any other comparison involvingnais false.- Lookback:
x[0]current,x[1]previous, out of range or negative →na. - TA is one sample per bar, state keyed by call-site (Python incremental kernels).
request.securityforeign / HTF without a feed →na. The chart series is never silently reused as another symbol.- Do not fork the grammar. Edit
.g4only in PYNE, then regen here. - Do not edit
src/runtime/compile/*andsrc/runtime/interpret.tsin the same agent turn. - License: AGPL-3.0-or-later.
Worked examples
Library (Bun)
import { parse, unparse, Runtime } from "@hoox-sh/pynets";
const src = `indicator("t")
plot(close[1])
plot(na == na ? 1 : 0)`;
const tree = parse(src);
console.log(unparse(tree));
const out = new Runtime("TEST").run(src, [
{ close: 10 },
{ close: 20 },
]);
// last bar: plots[0] = 10 (previous close), plots[1] = 1
Node 20+ / browser
import { parse, Runtime } from "@hoox-sh/pynets";
<script type="module">
import { Runtime } from "https://esm.sh/@hoox-sh/pynets";
</script>
Bun imports TypeScript source (package.json "bun": "./src/index.ts"). Node and browsers use dist/ (bun run build; prepack runs it). The CLI still needs Bun on PATH.
Failure modes
| Symptom | Cause | Fix |
|---|---|---|
| Plots disagree with Python | Port bug or invented host behaviour | Fix TS. Python is the oracle. |
request.security returns na | No foreign/HTF feed | Expected. Do not invent bars. |
mode: "compile" misses a builtin | JS emit surface lag | Use mode: "auto" or interpret |
Importing in a Worker and expecting /run | This is a library | Use pyne-worker |
Editing src/generated/* | Overwritten on regen | bun run generate after PYNE .g4 change |
pynets CLI on Node-only host | bin is src/cli.ts (Bun) | Run under Bun, or call Runtime from Node via dist/ |