@hoox-sh/pynets 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +661 -0
  3. package/NOTICE +46 -0
  4. package/README.md +327 -0
  5. package/dist/browser.js +44 -0
  6. package/dist/index.d.ts +348 -0
  7. package/dist/index.js +41741 -0
  8. package/package.json +77 -0
  9. package/src/ast/builder.ts +1002 -0
  10. package/src/ast/dump.ts +43 -0
  11. package/src/ast/helper.ts +77 -0
  12. package/src/ast/nodes.ts +570 -0
  13. package/src/ast/unparse.ts +360 -0
  14. package/src/cli/rich.ts +378 -0
  15. package/src/cli.ts +627 -0
  16. package/src/generated/PinescriptLexer.interp +267 -0
  17. package/src/generated/PinescriptLexer.tokens +131 -0
  18. package/src/generated/PinescriptLexer.ts +673 -0
  19. package/src/generated/PinescriptLexerBase.ts +395 -0
  20. package/src/generated/PinescriptParser.interp +267 -0
  21. package/src/generated/PinescriptParser.tokens +131 -0
  22. package/src/generated/PinescriptParser.ts +8863 -0
  23. package/src/generated/PinescriptParserBase.ts +21 -0
  24. package/src/generated/PinescriptParserVisitor.ts +840 -0
  25. package/src/index.ts +55 -0
  26. package/src/parser/LexerBase.ts +395 -0
  27. package/src/parser/ParserBase.ts +21 -0
  28. package/src/parser/error.ts +33 -0
  29. package/src/runtime/array.ts +486 -0
  30. package/src/runtime/color.ts +164 -0
  31. package/src/runtime/drawings.ts +510 -0
  32. package/src/runtime/input.ts +102 -0
  33. package/src/runtime/interpret.ts +3897 -0
  34. package/src/runtime/library.ts +282 -0
  35. package/src/runtime/log.ts +69 -0
  36. package/src/runtime/map.ts +85 -0
  37. package/src/runtime/math.ts +231 -0
  38. package/src/runtime/matrix.ts +1154 -0
  39. package/src/runtime/provider.ts +232 -0
  40. package/src/runtime/request.ts +372 -0
  41. package/src/runtime/series.ts +44 -0
  42. package/src/runtime/str.ts +433 -0
  43. package/src/runtime/strategy.ts +1105 -0
  44. package/src/runtime/ta.ts +2093 -0
  45. package/src/runtime/ticker.ts +81 -0
  46. package/src/runtime/time.ts +439 -0
  47. package/src/runtime/timeframe.ts +85 -0
  48. package/src/runtime/udt.ts +119 -0
package/NOTICE ADDED
@@ -0,0 +1,46 @@
1
+ PyneTS — NOTICE
2
+ ===============
3
+
4
+ Copyright (c) 2026 HOOX · PYNE · jango-blockchained
5
+ https://github.com/hoox-sh/pynets
6
+
7
+ License
8
+ -------
9
+ This project is licensed under the GNU Affero General Public License
10
+ **version 3 or any later version** (SPDX: AGPL-3.0-or-later).
11
+
12
+ Full text: LICENSE
13
+
14
+ “Later version” means a future FSF AGPL version if published — it does
15
+ **not** mean a separate “AGPL 4” product name. There is currently only AGPL v3.
16
+
17
+ Source files should carry:
18
+ SPDX-License-Identifier: AGPL-3.0-or-later
19
+
20
+ package.json: AGPL-3.0-or-later
21
+
22
+ Relationship to PYNE
23
+ --------------------
24
+ PyneTS (`@hoox-sh/pynets`) is the TypeScript / Bun counterpart of
25
+ **PYNE / pynescript**. Python `pynescript.runtime` is the source of
26
+ truth: when semantics disagree, Python wins.
27
+
28
+ The ANTLR4 grammars are **not** vendored here. `bun run generate` reads
29
+ `PinescriptLexer.g4` / `PinescriptParser.g4` from a sibling or parent
30
+ `hoox-sh/pyne` checkout (or `PYNESCRIPT_ROOT` / `PYNETS_GRAMMAR`).
31
+ Do not fork those `.g4` files into this repository.
32
+
33
+ In the PYNE repo this package is consumed only as the `pynets/` git
34
+ submodule.
35
+
36
+ Related
37
+ -------
38
+ PYNE (pynescript): AGPL-3.0-or-later https://github.com/hoox-sh/pyne
39
+ pyne-worker: AGPL-3.0-or-later https://github.com/hoox-sh/pyne-worker
40
+ AXIS: AGPL-3.0-only
41
+ HOOX monorepo: Apache-2.0 (code) / CC-BY-4.0 (docs)
42
+
43
+ Third-party marks
44
+ -----------------
45
+ Pine Script™ and TradingView® are trademarks of TradingView, Inc.
46
+ Cloudflare® is a registered trademark of Cloudflare, Inc.
package/README.md ADDED
@@ -0,0 +1,327 @@
1
+ # PyneTS
2
+
3
+ TypeScript / Bun library for **Pine Script**: parse, unparse, and interpret.
4
+
5
+ <p align="center">
6
+ <img src="docs/assets/cli.gif" alt="PyneTS CLI — help, run Keltner, run strategy" width="720" />
7
+ </p>
8
+
9
+ Same public names as Python [`pynescript`](https://github.com/hoox-sh/pyne): `parse`, `unparse`, `Runtime.run`.
10
+ Python `pynescript.runtime` is the **source of truth**. When semantics disagree, Python wins. This is not a TradingView platform certification.
11
+
12
+ ```ts
13
+ import { parse, unparse, Runtime } from "@hoox-sh/pynets";
14
+
15
+ const src = `//@version=5
16
+ indicator("sma")
17
+ plot(ta.sma(close, 3))
18
+ `;
19
+
20
+ const tree = parse(src);
21
+ unparse(tree);
22
+
23
+ const out = new Runtime("AAPL").run(src, [
24
+ { close: 1 }, { close: 2 }, { close: 3 }, { close: 4 },
25
+ ]);
26
+ // out.plots, out.series, out.count
27
+ ```
28
+
29
+ Install with Bun (published TypeScript source — no bundle needed):
30
+
31
+ ```bash
32
+ bun add @hoox-sh/pynets
33
+ bunx pynets -- help
34
+ ```
35
+
36
+ Node and browsers use the Bun-built ESM in `dist/` (`bun run build`; `npm pack` runs it via `prepack`):
37
+
38
+ ```bash
39
+ # Node 20+
40
+ npm install @hoox-sh/pynets
41
+ ```
42
+
43
+ ```js
44
+ import { parse, Runtime } from "@hoox-sh/pynets";
45
+ ```
46
+
47
+ ```html
48
+ <script type="module">
49
+ import { Runtime } from "https://esm.sh/@hoox-sh/pynets";
50
+ </script>
51
+ ```
52
+
53
+ The CLI still needs Bun on `PATH`. This is not a Cloudflare Worker package.
54
+
55
+ <p align="center">
56
+ <img src="docs/assets/cli-help.png" alt="pynets -- help" width="720" />
57
+ </p>
58
+
59
+ ---
60
+
61
+ ## Where this repo wins
62
+
63
+ 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, the same interpret contract.
64
+
65
+ | | Typical JS Pine runtime | **PyneTS** |
66
+ |---|---|---|
67
+ | Grammar | Hand-rolled or a forked copy | **Shared PYNE `.g4`**, TS ANTLR target — not forked here |
68
+ | AST | Custom / Zod (`Identifier`, `Literal`) | **ASDL names** (`kind`, `lineno`, `col_offset`) |
69
+ | Semantics | “Looks like Pine” | **Python Runtime wins** — every builtin is ported against `pynescript` |
70
+ | `na` | `NaN`, `undefined`, or thrown | **`null`**. `na == na` is true. Non-finite in/out is `na` |
71
+ | Lookback | Off-by-one or OOB crash | `close[1]` is previous; OOB / negative → `na` |
72
+ | Foreign data | Silently reuse the chart | `request.security` **without data is `na`** — we do not invent bars |
73
+ | Strategy | Events only, or a stats demo | **Fills, ledger, `strategy.risk.*`, OCA** |
74
+ | Matrix | Add/multiply if you are lucky | **`inv` / `pinv` / eigen / rank / kron** |
75
+ | Libraries | Unresolved `import` dies | **In-process registry** + soft stubs |
76
+ | Arrays | Push/get | **Near-full `array.*`** including search, percentiles, stdev |
77
+ | Host API | Ad-hoc | **`Runtime.run` / `stream` / `runProvider`** — same envelope as Python |
78
+ | CLI | None or a toy | **`check` / `format` / `run` / `dump` / `info`** — pipes stay JSON |
79
+
80
+ Family map — library vs edge host, same SoT:
81
+
82
+ | | [pynescript](https://github.com/hoox-sh/pyne) | [pyne-worker](https://github.com/hoox-sh/pyne-worker) | **PyneTS** |
83
+ |---|---|---|---|
84
+ | Role | SoT library | Production **Python** Cloudflare Worker | TS / Bun library + CLI |
85
+ | Engine | interpret + Numba compile | Vendors `pynescript.runtime` | interpret only |
86
+ | Grammar | `*.g4` | Same Python engine (not a fork) | **same `.g4`**, TS ANTLR target |
87
+ | How you call it | `Runtime.run` | `POST /run` (`interpret` / `compile` / `auto`) | `Runtime.run` / `stream` / `runProvider` |
88
+ | Extra | LSP, Pro API | R2 OHLCV, 1m cron, alerts, trade-worker | Local TTY (`check` / `format` / `run` / `dump`) |
89
+
90
+ [pyne-worker](https://github.com/hoox-sh/pyne-worker) is the edge evaluate host of the **Python** engine. PyneTS is the TypeScript library you import and the CLI you run on a laptop. They share the PYNE contract; this repo is not a Worker.
91
+
92
+ This repository is the standalone `@hoox-sh/pynets` checkout. PYNE consumes it **only** as the `pynets/` git submodule — never copy sources back into `hoox-sh/pyne`.
93
+
94
+ ---
95
+
96
+ ## Runtime contract
97
+
98
+ These are the rules that make plots match Python. Other ports usually get them wrong.
99
+
100
+ - **`na` is `null`.** A non-finite number in or out becomes `na`.
101
+ - **`na == na` is true.** Any other comparison involving `na` is false.
102
+ - **Series lookback:** `x[0]` current, `x[1]` previous, out of range → `na`.
103
+ - **TA is one sample per bar**, state keyed by call-site (Python incremental kernels).
104
+ - **Foreign / HTF `request.security` without a feed → `na`.** The chart series is never silently reused as another symbol.
105
+ - **v3/v4 bare aliases** (`sma`, `ema`, `rsi`, …) resolve when Python does.
106
+
107
+ ```ts
108
+ const out = new Runtime("TEST").run(
109
+ `indicator("t")
110
+ plot(close[1])
111
+ plot(na == na ? 1 : 0)`,
112
+ [{ close: 10 }, { close: 20 }],
113
+ );
114
+ // plots[0] last bar = 10 (previous close)
115
+ // plots[1] = 1
116
+ ```
117
+
118
+ ---
119
+
120
+ ## What interpret covers
121
+
122
+ Wired through one dispatcher (`src/runtime/interpret.ts`). Not a second engine.
123
+
124
+ **Language** — `var` / `varip` / `:=`, tuples, `if` / `for` / `while` / `switch`, UDFs, `type` / `enum`, `import`, `library()`.
125
+
126
+ **`ta.*`** — SMA/EMA/RMA/WMA/VWMA/HMA/ALMA/DEMA/TEMA/KAMA/SWMA, RSI, ATR, Supertrend, Keltner, BB/BBW, MACD, Stoch, CCI, WPR, DMI/ADX, SAR, MFI, CMO, TSI, COG, stdev/dev/variance, highest/lowest, crossover/crossunder, volume (OBV, PVT, AD, WAD, NVI/PVI, III, WVAD), pivots, barssince, valuewhen, percentiles, and the v3/v4 bare names.
127
+
128
+ **`math.*` / `str.*` / `color.*` / `input.*` / `log.*`** — the Python set, including `nz`, `iff`, `fixnan`, `timestamp`, `weekofyear`, `time_tradingday`.
129
+
130
+ **`array.*`** — new/from, get/set, push/pop/shift/unshift, slice/copy/concat, sort/search (binary + leftmost/rightmost), aggregates (avg/min/max/sum/median/mode/range/stdev/variance/covariance), percentiles, standardize, sort_indices.
131
+
132
+ **`matrix.*`** — shape ops, predicates, `mult` / `inv` / **`pinv`** / `pow` / `kron` / `rank` / **eigenvalues / eigenvectors**.
133
+
134
+ **`strategy.*`** — entry/exit/order, pending limit/stop, commission/slippage/pyramiding, open/closed trade accessors, **`strategy.risk.*`**, **OCA cancel/reduce**.
135
+
136
+ **Drawings / alerts** — `line` / `label` / `box` / `table` events; `alert` / `alertcondition`.
137
+
138
+ ---
139
+
140
+ ## Run scripts
141
+
142
+ ```ts
143
+ import { Runtime } from "@hoox-sh/pynets";
144
+
145
+ const rt = new Runtime("AAPL", {
146
+ timeframe: "5",
147
+ broker: { commission: 0.001, slippage: 0, pyramiding: 0 },
148
+ });
149
+
150
+ const result = rt.run(source, bars);
151
+ // result.plots last values, plot order
152
+ // result.series titled series (plot, strategy fields, …)
153
+ // result.plot_data { title: { data: [{ value, time? }] } }
154
+ // result.events strategy events
155
+ // result.fills fill tape
156
+ // result.drawings line/label/box/table
157
+ // result.logs log.info / warning / error
158
+ // result.error set on parse/runtime failure (does not throw)
159
+ ```
160
+
161
+ Push-driven re-eval:
162
+
163
+ ```ts
164
+ const stream = rt.stream(source);
165
+ stream.on("bar", (out) => { /* one result per push */ });
166
+ stream.push({ close: 1 });
167
+ stream.push({ close: 2 });
168
+ stream.end();
169
+ ```
170
+
171
+ ### Bars you actually have
172
+
173
+ Hosts feed OHLCV. PyneTS will not invent a foreign market.
174
+
175
+ ```ts
176
+ import { MemoryProvider, StaticMapProvider, JsonBarProvider } from "@hoox-sh/pynets";
177
+
178
+ await rt.runProvider(source, new MemoryProvider(bars), { limit: 500 });
179
+
180
+ // In-process symbol map (tests, fixtures, your own cache)
181
+ const map = new StaticMapProvider({
182
+ "AAPL": bars,
183
+ "AAPL:60": htfBars,
184
+ });
185
+
186
+ // Generic JSON GET — inject fetch, no vendor URLs baked in
187
+ const http = new JsonBarProvider({
188
+ url: ({ symbol, timeframe, limit }) => `https://you.example/ohlcv?s=${symbol}&tf=${timeframe}&n=${limit}`,
189
+ fetch: globalThis.fetch,
190
+ });
191
+ ```
192
+
193
+ ### Libraries
194
+
195
+ ```ts
196
+ rt.registerLibrarySource(
197
+ "User",
198
+ "MathLib",
199
+ 1,
200
+ `//@version=5
201
+ library("MathLib")
202
+ export double(x) => x * 2`,
203
+ );
204
+
205
+ rt.run(
206
+ `indicator("t")
207
+ import User/MathLib/1 as ml
208
+ plot(ml.double(close))`,
209
+ bars,
210
+ );
211
+ ```
212
+
213
+ Unresolved remote imports bind a soft stub (known helpers such as `index_2d_to_1d` still work). Register a source when you want real exports.
214
+
215
+ ---
216
+
217
+ ## CLI
218
+
219
+ Rich TTY (PYNE volt palette). Pipes and CI stay plain: `check` prints `ok`, `run` / `info` print JSON.
220
+
221
+ <p align="center">
222
+ <img src="docs/assets/cli-check.png" alt="pynets check sma.pine" width="720" />
223
+ </p>
224
+ <p align="center">
225
+ <img src="docs/assets/cli-run.png" alt="pynets run keltner.pine — three plots with sparklines" width="720" />
226
+ </p>
227
+ <p align="center">
228
+ <img src="docs/assets/cli-strategy.png" alt="pynets run strategy_entry.pine — plot plus entry event" width="720" />
229
+ </p>
230
+ <p align="center">
231
+ <img src="docs/assets/cli-dump.png" alt="pynets dump sma.pine — ASDL AST" width="720" />
232
+ </p>
233
+
234
+ ```bash
235
+ bunx pynets -- help
236
+ bunx pynets -- check script.pine
237
+ bunx pynets -- format script.pine
238
+ bunx pynets -- run script.pine --bars 20
239
+ bunx pynets -- run strat.pine --commission 0.001 --slippage 1 --pyramiding 0
240
+ bunx pynets -- dump script.pine --rich --full
241
+ bunx pynets -- info
242
+ ```
243
+
244
+ Put `--rich` / `--plain` **after** the command so `bun run` does not swallow them. `--plain` wins over leftover `FORCE_COLOR`. Exit codes: `0` ok, `1` syntax/runtime, `2` usage.
245
+
246
+ `run` prints a sparkline + last-value row per plot, a strategy events table when present, and drawings/alerts when present. `--plain` is machine JSON.
247
+
248
+ | Flag | Effect |
249
+ | --- | --- |
250
+ | `--bars N` | Synthetic bar count for `run` (default 20, max 100000) |
251
+ | `--commission N` | Broker commission fraction (`0.001` = 0.1%) |
252
+ | `--slippage N` | Slippage in price units |
253
+ | `--pyramiding N` | Max same-direction adds |
254
+ | `--json` | Machine-readable `run` / `info` |
255
+ | `--full` | Full AST dump (no 80-line cap on `--rich`) |
256
+ | `--plain` | Disable styling |
257
+ | `--rich` | Force panels / sparklines |
258
+
259
+ ---
260
+
261
+ ## Public API
262
+
263
+ ```ts
264
+ import {
265
+ parse, unparse, dump, tokenize, PinescriptSyntaxError,
266
+ Runtime, RuntimeStream,
267
+ PineArray, PineMap, PineMatrix,
268
+ MemoryProvider, StaticMapProvider, JsonBarProvider,
269
+ LibraryRegistry,
270
+ } from "@hoox-sh/pynets";
271
+ ```
272
+
273
+ `src/index.ts` is the stable barrel. Generated ANTLR, parser internals, and CLI helpers are not re-exported.
274
+
275
+ ---
276
+
277
+ ## Development
278
+
279
+ Agent brief: [`AGENTS.md`](AGENTS.md) · contribute: [`CONTRIBUTING.md`](CONTRIBUTING.md) · changes: [`CHANGELOG.md`](CHANGELOG.md)
280
+
281
+ ```bash
282
+ git clone https://github.com/hoox-sh/pynets.git
283
+ cd pynets
284
+ bun install
285
+ bun test
286
+ bun run typecheck
287
+ ```
288
+
289
+ Generated files under `src/generated/` are committed so `bun test` does not require Java. Local development is Bun only — do not add npm/yarn/pnpm lockfiles.
290
+
291
+ ### Grammar (do not fork)
292
+
293
+ `bun run generate` needs the shared PYNE `.g4` files. They are **not** vendored here.
294
+
295
+ Resolution (`scripts/generate-antlr.ts`): `PYNETS_GRAMMAR` → `PYNESCRIPT_ROOT` → parent PYNE checkout → sibling `../pynescript` or `../pyne`.
296
+
297
+ ```bash
298
+ # PYNE cloned next to this repo
299
+ bun run generate
300
+
301
+ # or
302
+ PYNESCRIPT_ROOT=/path/to/pyne bun run generate
303
+ ```
304
+
305
+ Java is required only to regenerate. The ANTLR jar is cached in `.tools/` (gitignored).
306
+
307
+ ### Inside PYNE
308
+
309
+ ```bash
310
+ git clone --recurse-submodules https://github.com/hoox-sh/pyne.git
311
+ cd pyne/pynets
312
+ bun install && bun test
313
+ ```
314
+
315
+ After a plain clone: `git submodule update --init --recursive`.
316
+
317
+ ---
318
+
319
+ ## Non-goals
320
+
321
+ Numba / compile, Worker packaging, ASDL codegen. Interpret is the only backend.
322
+
323
+ ---
324
+
325
+ ## License
326
+
327
+ AGPL-3.0-or-later — same as PYNE. See [LICENSE](LICENSE) and [NOTICE](NOTICE).