Syntax Guide

PineTS syntax rules for writing indicators in TradingGoose

PineTS uses JavaScript/TypeScript syntax that mirrors Pine Script's runtime behavior. If you know Pine Script from TradingView, the transition is straightforward — the key differences are in variable declarations and standard JS syntax conventions.

Variable Declarations

PineTS distinguishes between let and var to match Pine Script's execution model. This is the most important concept to understand.

let — Recalculated Every Bar

Variables declared with let (or const for immutable values) are re-evaluated on every bar, just like standard Pine Script variables:

// Recalculated on every bar
const sma20 = ta.sma(close, 20);
let direction = close > open ? 1 : -1;

var — Persistent State Across Bars

Variables declared with var are initialized only once (on the first bar) and retain their value across subsequent bars — matching Pine Script's var keyword:

// Initialized once, persists across bars
var cumulativeVolume = 0;
cumulativeVolume = cumulativeVolume + volume;

In PineTS, var does not behave like standard JavaScript var. It adopts Pine Script's semantics: the variable is set once and persists. Use let if you need a value that resets every bar.

Side-by-Side Comparison

BehaviorPine ScriptPineTS
Recalculated each barfloat x = closelet x = close or const x = close
Persistent across barsvar float x = 0.0var x = 0.0
Reassignmentx := x + 1x = x + 1

History Access

Access previous bar values using bracket notation, identical to Pine Script:

const prevClose = close[1];     // 1 bar ago
const tenBarsAgo = close[10];   // 10 bars ago
const momentum = close - close[10];

Loops

Standard JavaScript loop syntax:

// Pine Script: for i = 0 to 9
let sum = 0;
for (let i = 0; i < 10; i++) {
  sum += close[i];
}
let i = 0;
let sum = 0;
while (i < 10) {
  sum += close[i];
  i++;
}

Control Flow

// If/else
if (close > open) {
  direction = 1;
} else {
  direction = -1;
}

// Ternary
const color = close > open ? '#00FF00' : '#FF0000';

// Switch
switch (maType) {
  case 'ema': return ta.ema(close, length);
  case 'sma': return ta.sma(close, length);
  default: return ta.rma(close, length);
}

Functions

Define reusable functions using standard JavaScript syntax:

// Pine Script: f_ma(source, length) => ta.sma(source, length)
function f_ma(source, length) {
  return ta.sma(source, length);
}

const ma = f_ma(close, 20);
plot(ma, 'Custom MA');

Tuples (Multiple Return Values)

Some functions like ta.macd() and ta.bb() return multiple values. Use array destructuring:

// Pine Script: [macdLine, signalLine, hist] = ta.macd(close, 12, 26, 9)
const [macdLine, signalLine, hist] = ta.macd(close, 12, 26, 9);

// Pine Script: [middle, upper, lower] = ta.bb(close, 20, 2)
const [middle, upper, lower] = ta.bb(close, 20, 2);

Special Values

ValueDescription
naNot available — equivalent to null/undefined in Pine Script
nz(value)Replace na with zero (or a specified default)
colorColor namespace for chart colors
const prev = close[1];
const change = na(prev) ? 0 : close - prev;  // Handle na values
const safeValue = nz(someCalculation, 0);     // Default to 0 if na

Complete Example: Parabolic SAR

This example demonstrates var for persistent state, if/else logic, history access, and custom functions:

indicator('Custom SAR', { overlay: true });

const start = input.float(0.02, 'Start');
const increment = input.float(0.02, 'Increment');
const maximum = input.float(0.2, 'Maximum');

function pine_sar(start, inc, max) {
  var result = na;
  var maxMin = na;
  var acceleration = na;
  var isBelow = false;

  let isFirstTrendBar = false;

  if (bar_index == 1) {
    if (close > close[1]) {
      isBelow = true;
      maxMin = high;
      result = low[1];
    } else {
      isBelow = false;
      maxMin = low;
      result = high[1];
    }
    isFirstTrendBar = true;
    acceleration = start;
  }

  // ... calculation logic ...
  return result;
}

const sar = pine_sar(start, increment, maximum);
plot(sar, 'SAR', { style: plot.style_cross });