[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 pine CLI 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

SecretPurpose
INTERNAL_KEY_BINDINGShared 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:

  1. Parse the script via ANTLR
  2. Build the AST via visitor
  3. For each OHLCV bar (chronologically): set open, high, low, close, volume, time, and bar_index state
  4. Evaluate the AST against the current bar's state
  5. 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:

FieldTypeRequiredDefaultDescription
scriptstringPine Script source (max 100,000 chars)
ohlcvOHLCVBar[]Explicit bars (max 10,000). If omitted, fetched from DataProvider
symbolstringBTCUSDTTrading pair
timeframeenum1dBar size: 1m, 5m, 15m, 1h, 4h, 1d, 1w
barsinteger500Number of bars to fetch (max 10,000)
forwardbooleanfalseForward trade events to trade-worker
sheetbooleantrueInclude per-bar OHLCV + plot data in response
formatenumjsonResponse 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):

  1. Top-level error boundary — unhandled exceptions return sanitized 500 responses (no stack traces, no internal paths)
  2. AuthrequireInternalAuth validates X-Internal-Auth-Key header with timing-safe comparison against INTERNAL_KEY_BINDING
  3. CSRF — Origin vs Host header check on mutations. Service-binding calls (no Origin header) pass through
  4. Zod validation.strict() schema on /run rejects unknown fields, returns sanitized error messages
  5. Security headerswrapWithSecurityHeaders applies CSP, X-Content-Type-Options, etc. on every response
  6. Output sanitizationcreateJsonResponse strips 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:data to populate data/{SYMBOL}/{TIMEFRAME}/ with compressed JSON Lines files
  • Production: Upload data to the pine-worker-ohlcv R2 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 pine command group is not shipped in the current CLI release. Use bun run scripts inside workers/pine-worker until the group lands. TradingView webhooks (external Pine Script alerts → gateway) are available today and do not require hoox 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


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.