[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.

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

NameRole
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 / transpileJS emit (not Numba)
CLI pynetscheck format run dump info

Default mode is interpret. Constructor and per-call extra accept mode: "interpret" | "compile" | "auto".

What this is not

Confused withReality
pyne-workerPython Cloudflare Worker. Vendors pynescript.runtime. POST /run. See pyne-worker.
pyne-agent-workerNL authoring host. Not an evaluate library. See agent.
Python pyne runCompile-only smoke on synthetic bars. PyneTS pynets run calls Runtime.run.
NumbaPython compile backend. PyneTS compile is JS emit (object-mode analog).
AXIS engineAXIS does not load this package.

Internals (repo paths)

Standalone (/home/jango/Git/pynets or the published package):

PathRole
src/index.tsPublic barrel — do not re-export generated ANTLR
src/ast/helper.tsparse / unparse / dump / tokenize
src/ast/nodes.tsHand-written ASDL nodes
src/generated/ANTLR TS — do not hand-edit; bun run generate
src/runtime/interpret.tsRuntime, interpret host
src/runtime/compile/JS emit (transpile / compileScript)
src/cli.tsTTY CLI
test/interpret_*.test.tsFocused interpret tests

PYNE checkout: pynets/ submodule. Grammar SoT stays in PYNE resource/*.g4.

Invariants & edge cases

  1. Python wins. Do not invent TradingView platform behaviour that Python does not implement.
  2. na is null. Non-finite in/out is na. na == na is true. Any other comparison involving na is false.
  3. Lookback: x[0] current, x[1] previous, out of range or negative → na.
  4. TA is one sample per bar, state keyed by call-site (Python incremental kernels).
  5. request.security foreign / HTF without a feed → na. The chart series is never silently reused as another symbol.
  6. Do not fork the grammar. Edit .g4 only in PYNE, then regen here.
  7. Do not edit src/runtime/compile/* and src/runtime/interpret.ts in the same agent turn.
  8. 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

SymptomCauseFix
Plots disagree with PythonPort bug or invented host behaviourFix TS. Python is the oracle.
request.security returns naNo foreign/HTF feedExpected. Do not invent bars.
mode: "compile" misses a builtinJS emit surface lagUse mode: "auto" or interpret
Importing in a Worker and expecting /runThis is a libraryUse pyne-worker
Editing src/generated/*Overwritten on regenbun run generate after PYNE .g4 change
pynets CLI on Node-only hostbin is src/cli.ts (Bun)Run under Bun, or call Runtime from Node via dist/

See also