[pine-worker Isolate Profile]
Comprehensive engineering specification for the pine-worker Pine Script evaluator, covering ANTLR4 parsing, AST evaluation, strategy event emission, and cross-worker trade forwarding.
The pine-worker is the strategy evaluation engine of the Hoox trading platform. Deployed as a compute isolate, it runs TradingView Pine Script strategy scripts against historical or live OHLCV data and emits structured trade events to trade-worker via a V8 Service Binding.
Status: worker design is documented here; the companion
hoox pineCLI group is upcoming and not part of the current CLI release.
1. Declared Wrangler Configurations & Bindings
The pine-worker communicates internally via a Service Binding to trade-worker and reads OHLCV data from an R2 bucket. Its wrangler.jsonc maps out storage, service, and environment hooks:
{
"name": "pine-worker",
"main": "src/index.ts",
"compatibility_date": "2026-06-08",
"compatibility_flags": ["nodejs_compat"],
"placement": { "mode": "smart" },
"observability": {
"enabled": true,
"head_sampling_rate": 0.1,
"logs": { "enabled": true, "head_sampling_rate": 1, "persist": true, "invocation_logs": true }
},
"vars": {
"TRADE_WORKER_NAME": "trade-worker"
},
"services": [
{ "binding": "TRADE_SERVICE", "service": "trade-worker" }
],
"r2_buckets": [
{ "binding": "OHLCV_DATA", "bucket_name": "pine-worker-ohlcv", "preview_bucket_name": "pine-worker-ohlcv-dev" }
]
}
Secrets
| Secret | Purpose |
|---|---|
INTERNAL_KEY_BINDING | Shared internal auth key for cross-worker communication |
Aliases
The worker uses wrangler.jsonc alias mappings to resolve the @jango-blockchained/hoox-shared monorepo package at build time — no npm link or workspace protocol needed at deploy time.
2. Architecture: Parser → AST → Evaluator → Events
The pine-worker processes Pine Script in four stages, following the pynescript reference implementation:
A. Parser (ANTLR4)
An ANTLR4-generated TypeScript parser (PinescriptLexer.g4 / PinescriptParser.g4) tokenizes and parses Pine Script source into an ANTLR parse tree. The grammar supports the full TradingView Pine Script surface including expressions, statements, and type annotations.
# Regenerate parser from grammar
bun run gen:parser
B. AST Builder (Visitor + Zod)
A generated visitor (PinescriptParserVisitor) walks the ANTLR parse tree and builds a Zod-validated typed AST. Every AST node is defined with .strict() Zod schemas, catching malformed or unsupported constructs at the boundary before they reach the evaluator.
C. Evaluator
The evaluator is a composition-based engine that resolves AST nodes into Pine Series values. It handles:
- Expression evaluation — arithmetic, logical, comparison, ternary, subscript, function calls
- Statement execution — variable declarations (with history-based series semantics), if/else, for loops
- Builtin resolution — namespaced builtins (ta., math., strategy.*, etc.) registered in the builtin registry
- Series semantics — each variable maintains per-bar history, with
close[1]-style offset lookups
D. Runtime (Per-Bar Loop)
The Runtime class orchestrates the full pipeline:
- Parse the script via ANTLR
- Build the AST via visitor
- For each OHLCV bar (chronologically): set
open,high,low,close,volume,time, andbar_indexstate - Evaluate the AST against the current bar's state
- Collect strategy events (
strategy.entry,strategy.exit,strategy.close)
import { Runtime } from "./runtime";
const rt = new Runtime({ symbol: "BTCUSDT" });
const result = await rt.run("strategy.entry('long', strategy.long)", ohlcvBars);
E. Trade Forwarding
When forward: true is passed in the request, trade events are forwarded to trade-worker via the TRADE_SERVICE Service Binding. Each event is serialized into a WebhookPayload and sent to trade-worker's /webhook endpoint with INTERNAL_KEY_BINDING authentication.
F. Chart Export
Every /run response includes a per-bar sheet with OHLCV columns plus all plot() / hline() values. The response can be requested in JSON (default) or CSV format — mirroring TradingView's "Export chart data" feature.
3. Internal REST API Specification
A. Execute Strategy
- Endpoint:
/run - Method:
POST - Headers:
X-Internal-Auth-Key: <INTERNAL_KEY_BINDING> - JSON Payload:
{
"script": "indicator('My Strategy')\nplot(close)",
"symbol": "BTCUSDT",
"timeframe": "1d",
"bars": 500,
"forward": false,
"sheet": true,
"format": "json"
}
Payload fields:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
script | string | — | Pine Script source (max 100,000 chars) | |
ohlcv | OHLCVBar[] | — | Explicit bars (max 10,000). If omitted, fetched from DataProvider | |
symbol | string | BTCUSDT | Trading pair | |
timeframe | enum | 1d | Bar size: 1m, 5m, 15m, 1h, 4h, 1d, 1w | |
bars | integer | 500 | Number of bars to fetch (max 10,000) | |
forward | boolean | false | Forward trade events to trade-worker | |
sheet | boolean | true | Include per-bar OHLCV + plot data in response | |
format | enum | json | Response format: json or csv |
- Success Response (200 OK):
{
"events": [
{
"type": "strategy.entry",
"id": "long",
"direction": "long",
"bar_index": 50,
"price": 68425.5
}
],
"bars": 500,
"script_id": "abc123",
"run_id": "def456",
"symbol": "BTCUSDT",
"timeframe": "1d",
"sheet": {
"bars": [
{
"plots": {
"close": 68425.5,
"sma20": 68100.3
},
"time": 1720000000000,
"open": 68200.0,
"high": 68500.0,
"low": 68150.0,
"close": 68425.5,
"volume": 1234.5
}
]
},
"export": {
"columns": ["time", "open", "high", "low", "close", "volume", "close", "sma20"],
"data": [[1720000000000, 68200.0, 68500.0, 68150.0, 68425.5, 1234.5, 68425.5, 68100.3]]
}
}
When format: "csv", the response is a text/csv download with Content-Disposition: attachment.
- Error Response (404) — no data for symbol/timeframe:
{
"error": "No data for BTCUSDT 1d. Run `bun run scripts/download-data.ts --symbol BTCUSDT --tf 1d` first."
}
B. Health Check
-
Endpoint:
/health -
Method:
GET -
Response (200 OK):
{
"status": "ok",
"worker": "pine-worker"
}
4. Security Middleware Stack
Every request passes through a layered middleware pipeline (fail-closed):
- Top-level error boundary — unhandled exceptions return sanitized 500 responses (no stack traces, no internal paths)
- Auth —
requireInternalAuthvalidatesX-Internal-Auth-Keyheader with timing-safe comparison againstINTERNAL_KEY_BINDING - CSRF — Origin vs Host header check on mutations. Service-binding calls (no Origin header) pass through
- Zod validation —
.strict()schema on/runrejects unknown fields, returns sanitized error messages - Security headers —
wrapWithSecurityHeadersapplies CSP, X-Content-Type-Options, etc. on every response - Output sanitization —
createJsonResponsestrips Error instances and stack traces from response bodies
5. DataProvider Architecture
The worker resolves OHLCV data through a layered provider chain:
LiveDataProvider ← always wraps, adds live Binance bars
└─ CompositeDataProvider ← tries R2, then local files
├─ R2DataProvider (production — reads from pine-worker-ohlcv R2 bucket)
└─ LocalFileDataProvider (dev — reads from data/ directory)
- Local dev: Use
bun run download:datato populatedata/{SYMBOL}/{TIMEFRAME}/with compressed JSON Lines files - Production: Upload data to the
pine-worker-ohlcvR2 bucket in the same directory structure
6. Parity Testing
The worker's correctness is verified against the Python reference implementation in pynescript. The parity corpus under pynescript/tests/fixtures/parity/ defines the contract: every .pine script must produce identical event lists when run through both evaluators.
bun test # Full test suite including parity tests
bun test --watch # Watch mode for development
bun test --coverage # Coverage report
7. CLI Scripts
Upcoming: the
hoox pinecommand group is not shipped in the current CLI release. Usebun runscripts insideworkers/pine-workeruntil the group lands. TradingView webhooks (external Pine Script alerts → gateway) are available today and do not requirehoox pine.
Worker-local scripts (from workers/pine-worker):
Download OHLCV Data
bun run download:data --symbol ETHUSDT --tf 1h --days 30
Fetches from Binance public API, stores as compressed JSON Lines: data/{SYMBOL}/{TIMEFRAME}/{YYYY}.jsonl.gz.
Export Chart Data
bun run export:chart ../grid.pine BTCUSDT 5m 100 --csv
Run Backtest
bun run run:backtest ../grid.pine BTCUSDT 5m 864
Bundle Libraries
bun run bundle:libraries
Planned CLI surface (not yet released)
# hoox pine download | backtest | export | bundle — upcoming
Related Workers & Services
- trade-worker — Trade execution engine; receives forwarded events via
TRADE_SERVICEbinding - hoox Gateway — Edge gateway that routes external requests to
pine-worker - pynescript (Python reference) — Reference evaluator for parity testing
- hoox-setup — Monorepo root
Tip
For development, always run bun run download:data first to populate local
OHLCV data. Without it, /run requests that don't include explicit ohlcv
bars will return a 404 with instructions.