Skip to content

STS Script AST

STS Script source code is parsed into an internal AST before validation and compilation.

The AST is not the public user-facing language, but it defines how the runtime understands script source.

Top-Level Program

{
  type: "Program",
  body: []
}

The body array contains statements.

Statement Types

Type Purpose
Input Declares an input constant
VarDecl Declares a local variable
Assign Assigns a calculated series
If Conditional branch
For Bounded loop
ExprStmt Function call statement
Event Robot lifecycle event body

Script Declaration

The first statement must be a script(...) expression statement.

script("MA Crossover", kind="robot")
{
  type: "ExprStmt",
  expr: {
    type: "Call",
    name: "script",
    args: [
      { type: "Str", value: "MA Crossover" }
    ],
    named: {
      kind: { type: "Str", value: "robot" }
    }
  }
}

Input

input length = 20
{
  type: "Input",
  name: "length",
  value: { type: "Num", value: 20 }
}

Series Assignment

ma = ta.sma(close, length)
{
  type: "Assign",
  name: "ma",
  expr: {
    type: "Call",
    name: "ta.sma",
    args: [
      { type: "Var", value: "close" },
      { type: "Var", value: "length" }
    ]
  }
}

Event

onBar {
  trade.buy(symbol="BTCUSD", volume=0.01)
}
{
  type: "Event",
  name: "onBar",
  body: {
    type: "Block",
    body: []
  }
}

Expressions

Type Purpose
Num Numeric literal
Str String literal
Var Variable or series reference
History Historical access, for example close[1]
Bin Binary expression
Unary Unary expression
Cond Conditional expression
Call Function call

Validation

Validation checks that:

  • unknown variables are rejected;
  • indicator scripts cannot use robot-only functions;
  • robot scripts can only use allowed trade bridge functions;
  • inputs cannot be reassigned;
  • series history access is used only on series values;
  • plotText is a standalone indicator ExprStmt, allowed inside If but rejected in loops, assignments, nested expressions, and robot events;
  • plotText has exactly one positional price argument and only the documented named options;
  • ta.crossover and ta.crossunder receive exactly two positional named-series references, without history offsets or inline expressions.

The compiler emits plotText at its original per-candle execution point, so conditional branches remain conditional. It does not hoist text-label calls into one-time plot registration. Option types and limits are checked when their values are evaluated. See Chart API.

Extended language contracts

The existing AST shapes also represent the newer APIs; there is no executable JavaScript escape hatch.

  • na is a missing-value literal; na(value) and nz(value, replacement) are calls.
  • barIndex and isClosed are built-in series.
  • History indices must be nonnegative safe integers; negative/fractional/non-finite indices are rejected, including dynamically evaluated indices.
  • For.from and For.to may be expressions. Bounds are captured once per loop entry and validated at runtime; a reversed range is empty.
  • array.* calls accept positional scalar arguments and can be used in expressions or statements, including loops.
  • draw.* calls are indicator statements, including in loops. They are rejected as expression values and in robots.
  • plotShape, barcolor and alertcondition are per-candle indicator statements, allowed in if but not in loops, expressions or robot events.
  • Named options on once-registered plot, hline, fill, bgcolor and color calls must be literals or scalar inputs. Calculate named source/condition series separately.

See the exact signatures and limits in Chart API, Series and Runtime.