YeScript Documentation

Complete syntax and runtime guide for Tradeiz YeScript — declarations, built-ins, plotting, strategy execution, bytecode internals, and server-run behavior.

Types: indicator · strategy · library Runtime: browser VM · server-run File: .yes · bytecode YESC v2

Overview

YeScript is Tradeiz's chart-native DSL. Source compiles into bytecode and executes per bar in a sandboxed VM. The same script model is used for browser backtest and server-run execution.

  • First line is exactly one declaration: indicator(...), strategy(...), or library(...).
  • Execution is bar-by-bar. Built-in series and host context are injected for each bar.
  • Trade intents and plot commands are generated by VM output, then rendered/processed by host runtimes.
  • Source DSL is English-only; locale UI does not change script keywords.
strategy("EMA + RSI", initial_capital=10000, commission=0.001)
var fast = ta.ema(close, 12)
var slow = ta.ema(close, 26)
var r = ta.rsi(close, 14)
if ta.crossOver(fast, slow) and r < 65
  trade.open_long("ema_long", 1)
if ta.crossUnder(fast, slow)
  trade.close_all()

Script structure

Every .yes script starts with exactly one declaration on the first effective line.

DeclarationDescription
indicator("Name")Indicator script. Default pane behavior comes from host routing and indicator options.
indicator("Name", overlay=true)Indicator overlaying price context.
strategy("Name", initial_capital=..., commission=..., default_qty=...)Strategy script that can emit trade intents and backtest metrics.
library("Name")Reusable function package for import-oriented workflows.

Comments

Lexer supports single-line and block comments.

// slash comment
# hash comment
var x = 1 // inline
/* multi-line comment
   still ignored by compiler */

Data types

TypeExamplesNotes
number42, 3.14, -0.5Primary numeric type for series/math.
string"BTCUSDT", "#2196F3"Text, identifiers, colors, labels.
booltrue, falseControl and trigger conditions.
nanaMissing value marker, propagates through many calculations.
array[1, 2, 3]Runtime array object for arr.*.
mapmap.new()Runtime map object for map.*.

Built-in series/vars

NameDescription
open, high, low, close, volumeCurrent bar OHLCV fields from host data.
bar_indexZero-based current bar index.
timeCurrent bar timestamp (seconds, UTC context).

History reference

Series can be referenced with bracket offsets.

close[0]   // current close
close[1]   // previous bar close
high[5]    // high from five bars ago
volume[2]  // volume from two bars ago

Out-of-range history returns na.

Assignment (var/const/state)

FormBehavior
var x = exprMutable variable in script scope.
const x = exprImmutable after declaration.
state x = exprInitialized once; persistent across bars.
x = exprAssignment-style declaration/update when allowed by analyzer rules.

Operators

  • Arithmetic: +, -, *, /, %, unary -.
  • Comparison: >, >=, <, <=, ==, !=.
  • Logical: and, or, not.
  • Ternary: condition ? a : b.
var regime = close > ta.ema(close, 200) ? "bull" : "bear"
var trigger = ta.crossOver(close, ta.sma(close, 20)) and not na(close[1])

Control flow

Indentation-based blocks are used throughout.

if close > open
  log.info("bull bar")
else if close < open
  log.info("bear bar")
else
  log.info("doji")

for i = 0 to 10 by 1
  if i == 5
    continue

var total = 0
for p in [close, close[1], close[2]]
  total = total + p

Functions

User functions are declared with fn and can return values.

fn spread(srcHigh, srcLow)
  return srcHigh - srcLow

var s = spread(high, low)

return is valid inside function scope and supports expression returns.

Import/Library

Library declaration and import syntax supported by parser/analyzer:

library("shared_stats")
fn zscore(src, len)
  var m = ta.sma(src, len)
  return (src - m) / ta.stdev(len)
use "shared_stats"
import (zscore, signal) from "shared_stats"

For production workflows, keep library code reusable and side-effect free.

input.*

Input descriptors are captured per script and can be overridden by host-provided values.

FunctionSignatureReturn
input.intinput.int(defval, title)integer
input.floatinput.float(defval, title)number
input.boolinput.bool(defval, title)boolean
input.stringinput.string(defval, title)string
input.sourceinput.source(defval, title)string
input.timeframeinput.timeframe(defval, title)string
input.colorinput.color(defval, title)string
input.symbolinput.symbol(defval, title)string

log.*

FunctionDescription
log.info(msg, ...)Informational log entry for current bar.
log.warn(msg, ...)Warning log entry for current bar.
log.error(msg, ...)Error log entry for current bar.

math.*

Function/constSignature
math.absmath.abs(x)
math.max, math.minmath.max(a, b), math.min(a, b)
math.round, math.floor, math.ceilsingle-number transforms
math.sqrt, math.pow, math.log, math.expcore numeric transforms
math.sin, math.cos, math.tantrigonometric
math.asin, math.acos, math.ataninverse trigonometric
math.log10, math.log2, math.sign, math.randommisc numeric helpers
math.avg(...), math.sum(...)variadic aggregations
math.to_degrees, math.to_radiansangle conversion
math.PI, math.Enumeric constants

str.*

FunctionSignature
str.lengthstr.length(s)
str.containsstr.contains(s, sub)
str.to_upper, str.to_lowercase conversion
str.replacestr.replace(s, old, next) (global replacement)
str.substringstr.substring(s, start, end?)
str.starts_with, str.ends_withprefix/suffix checks
str.to_stringstr.to_string(value)
str.formatstr.format("x={0}", x)

arr.*

FunctionSignatureNotes
arr.newarr.new(size, fill)create array
arr.lengtharr.length(a)canonical length name
arr.get, arr.setarr.get(a, idx), arr.set(a, idx, val)random access
arr.push, arr.pop, arr.shift, arr.unshiftqueue/stack opsmutating
arr.includesarr.includes(a, value)membership check
arr.sum, arr.avg, arr.max, arr.minnumeric aggregationnon-numeric ignored in numeric reducers
arr.sort, arr.reverse, arr.slice, arr.joinstructural transformssort/reverse return copied arrays

map.*

FunctionSignature
map.newmap.new()
map.get, map.set, map.haskey/value read-write checks
map.keys, map.values, map.sizeintrospection helpers
map.remove, map.cleardeletion helpers

sym.*

PropertyDescription
sym.tickerHost symbol/ticker (default fallback: BTCUSDT).
sym.exchangeHost exchange id/name.
sym.kindHost market kind.
sym.descriptionDescription field (currently empty placeholder if host does not inject).

tf.*

Property/functionDescription
tf.periodCurrent timeframe period string from host context.
tf.multiplierCurrent timeframe multiplier from host context.
tf.data(tf, expr)Pass-through placeholder hook for multi-timeframe extension.

time.*

PropertyRange/description
time.hour, time.minute, time.secondUTC components of current bar datetime.
time.dayofweek, time.dayofmonth, time.month, time.yearUTC calendar breakdown.
time.is_monday, time.is_friday, time.is_weekendBoolean day selectors.

color.*

Color helpers include constructors and constants:

color.new("#2196F3", 90)
color.rgb(33, 150, 243, 200)
color.red color.green color.blue color.orange color.purple color.yellow
color.white color.black color.gray color.aqua color.lime color.fuchsia
color.silver color.teal color.navy color.maroon color.olive

ta.* (full table, 47 functions)

This table reflects VM/runtime built-ins plus codegen TA opcode mappings. Canonical cross names are ta.crossOver / ta.crossUnder; lowercase aliases ta.crossover / ta.crossunder are also accepted.

#FunctionTypical signatureReturn
1ta.smata.sma(length) or ta.sma(close, length)number
2ta.emata.ema(length) or ta.ema(close, length)number
3ta.rsita.rsi(length) or ta.rsi(close, length)number
4ta.atrta.atr(length)number
5ta.wmata.wma(length) or ta.wma(close, length)number
6ta.highestta.highest(length) or ta.highest(close, length)number
7ta.lowestta.lowest(length) or ta.lowest(close, length)number
8ta.changeta.change() or ta.change(length)number
9ta.crossOverta.crossOver(a, b)bool
10ta.crossUnderta.crossUnder(a, b)bool
11ta.vwmata.vwma(length)number
12ta.rmata.rma(length)number
13ta.hmata.hma(length)number
14ta.swmata.swma()number
15ta.almata.alma(length, offset?, sigma?)number
16ta.demata.dema(length)number
17ta.temata.tema(length)number
18ta.macdta.macd(fast?, slow?, signal?)tuple
19ta.stochta.stoch(k?, d?, smooth?)tuple
20ta.ccita.cci(length?)number
21ta.mfita.mfi(length?)number
22ta.rocta.roc(length?)number
23ta.momta.mom(length?)number
24ta.willrta.willr(length?)number
25ta.obvta.obv()number
26ta.bbta.bb(length?, mult?)tuple
27ta.kcta.kc(length?, mult?, atr_len?)tuple
28ta.supertrendta.supertrend(factor?, atr_len?)tuple
29ta.stdevta.stdev(length)number
30ta.varianceta.variance(length)number
31ta.trta.tr()number
32ta.dmita.dmi(length?, adx_len?)tuple
33ta.sarta.sar(start?, inc?, max?)number
34ta.pivot_highta.pivot_high(left, right)number
35ta.pivot_lowta.pivot_low(left, right)number
36ta.cumta.cum()number
37ta.risingta.rising(length)bool
38ta.fallingta.falling(length)bool
39ta.bars_sinceta.bars_since(cond)number
40ta.pct_rankta.pct_rank(length)number
41ta.linregta.linreg(length, offset?)number
42ta.valuewhenta.valuewhen(cond, source, n?)number
43ta.highestbarsta.highestbars(length)number
44ta.lowestbarsta.lowestbars(length)number
45ta.medianta.median(length)number
46ta.percentileta.percentile(length, pct?)number
47ta.correlationta.correlation(length)number

trade.*

Available only in strategy() scripts.

Paper Trading: trade.open_long and trade.open_short add quantity to the same merged account position as your manual trades on that symbol (same leverage and margin mode).

Function/propertySignatureDescription
trade.open_longtrade.open_long(id, qty)emit open-long intent
trade.open_shorttrade.open_short(id, qty)emit open-short intent
trade.close_longtrade.close_long(id)emit close-long intent
trade.close_shorttrade.close_short(id)emit close-short intent
trade.exittrade.exit(id)emit exit intent
trade.close_alltrade.close_all()flatten all positions
trade.canceltrade.cancel(id)cancel single pending order
trade.cancel_alltrade.cancel_all()cancel all pending orders
trade.limittrade.limit(id, qty, price)emit limit-order intent
trade.stoptrade.stop(id, qty, price)emit stop-order intent
trade.position_sizepropertycurrent position size
trade.avg_pricepropertyaverage entry price
trade.equitypropertycurrent equity snapshot
trade.open_profitpropertyunrealized PnL
trade.sidepropertylong, short, or flat side label

Close functions — backtest vs Paper Trading

In chart/backtest mode, only the strategy's simulated position exists. trade.close_long, trade.close_short, trade.exit, trade.close_all, and close_position close that strategy position only—the semantics are clear.

In server-run Paper Trading, futures positions are merged per user, symbol, leverage, and margin mode into one ti_positions row. There is no source field—strategy fills and manual fills share the same account record.

When the strategy closes, it closes the merged net position, not just the slice the strategy opened. If you manually opened the same symbol on the same side, the strategy close can reduce or flatten your manual position too.

This is intentional product behavior, not a bug. See also: Paper Trading.

Paper Trading

Existing trade.* APIs and legacy buy/sell/close_position statements still compile unchanged—no paper-trading-specific syntax was added. By default, server runs emit signals only; trade intents reach the run owner's Paper Trading account only when you explicitly enable simulated orders for that run at creation time.

  • Server runs default to signal-only mode: alerts and trade signals are emitted, but trade intents are not sent to Paper Trading. Browser/chart backtests simulate fills locally and never place Paper Trading orders.
  • To place simulated orders, check Allow simulated orders for this run when creating the server run (off by default). If you enable it, you must already hold the yescript.paper_trading plan feature; creation is rejected otherwise.
  • An intent is executed only when both conditions hold: the run has paper_trading_enabled=true (your explicit consent for this run) and the run owner still has yescript.paper_trading entitlement. Either missing leads to rejection.
  • The paper-trading consent flag is set at run creation and cannot be changed afterward. Stop the run and create a new one to toggle it. Existing runs created before this field existed are treated as not authorized (signal-only).

Closes operate on the account merged net position for that symbol and side (full explanation under trade.* Close functions above). Manual positions in the same direction are included. This is intentional product behavior, not a defect.

  • Only market open/close intents are executed. trade.limit, trade.stop, trade.cancel, trade.cancel_all, and related pending intents are rejected (strategy_pending_intent_not_supported) and the VM simulated position does not advance for them.
  • Successful fills surface filled_quantity in run signals/UI. Rejected intents return a reason code (see table below).
  • The VM maintains its own simulated position for strategy logic (trade.position_size, etc.). Manual trading or partial fills can make VM state differ from the Paper Trading account.
  • Executed orders are tagged source=strategy with source_ref set to the run id (client_order_id prefix ysr_{runId}_…).
  • Per bar: up to 16 trade intents (MAX_STRATEGY_INTENTS_PER_BAR default; extras get strategy_intent_limit_exceeded). Per user: up to 120 strategy orders per rolling minute (strategy_order_rate_limited).

Common rejection reason codes

Codes returned to the worker/run UI when an intent is not executed:

CodeDescription
strategy_pending_intent_not_supportedLimit, stop, or cancel intents are not supported for server-run Paper Trading.
strategy_intent_not_executableIntent could not be mapped to a market open/close action.
strategy_position_not_foundClose intent but no matching VM position, or no matching Paper Trading position on the account.
strategy_intent_limit_exceededMore than 16 trade intents on the same bar.
paper_trading_not_enabled_for_runThis server run was not created with simulated-order consent (paper_trading_enabled=false).
feature_not_in_planRun owner lacks yescript.paper_trading entitlement.
strategy_order_rate_limitedMore than 120 strategy orders for this user in the current minute.
strategy_order_rate_limit_unavailableRate-limit store unavailable; retry later.
entitlement_unavailableCould not verify entitlements.
paper_order_unavailablePaper Trading service unreachable.
strategy_run_not_activeServer run is not in starting/running/idle state.
strategy_market_not_supportedPaper Trading routing applies to futures server runs only.
paper_order_not_filledMarket order submitted but received no fill.
paper_order_rejectedPaper Trading rejected the order (4xx upstream).

Plot/drawing

FunctionSignatureNotes
plotplot(value, label?, color?, pane?)line series
plotHistogramplotHistogram(value, label?, color?, pane?)histogram series
hlinehline(price, label?, color?, pane?)horizontal line
bgcolorbgcolor(color, label?, opacity?)background tint
markmark(value, style?, location?, color?, size?, text?)shape marker (canonical; not plotshape)
tinttint(color)bar tint
arrowarrow(value, colorUp?, colorDown?)directional arrow
candlecandle(open, high, low, close, color?)custom candle draw command
fillfill(plot1, plot2, color?, opacity?)area fill between named plots

alert

Statement form:

alert("Price crossed above resistance")

buy/sell/close_position

Legacy strategy statements remain available and compile to trade opcodes.

buy(0.01)
buy("BTCUSDT", 0.01)
sell(0.01)
close_position("BTCUSDT")

close_position follows the same close semantics as trade.close_long and trade.close_all. In backtest it closes the strategy position only. In Paper Trading it closes the merged account net position, which can include manual positions on the same symbol and side—see Close functions under trade.*.

Runtime/bytecode

Compile and execution pipeline:

source (.yes)
  -> lexer -> parser -> analyzer -> codegen
  -> bytecode (magic: YESC, version: 2)
  -> VM.executeBar()
  -> { plotCommands, tradeIntents, alertIntents, logEntries }
Opcode groupExamples
Stack/varsPUSH_CONST, LOAD_VAR, STORE_STATE
Arithmetic/logicalADD, DIV, EQ, AND
Data accessGET_OPEN, GET_TIME, GET_SERIES_AT
TACALL_SMA, CALL_RSI, CALL_CROSS_OVER, CALL_BUILTIN
DrawingDRAW_PLOT, DRAW_MARK, DRAW_FILL
Trade/alertTRADE_BUY, TRADE_CLOSE, ALERT_FIRE

Limitations

Known constraints and doc-vs-VM differences (source-of-truth: compiler/vm runtime):

  • DSL keywords are English-only from 2026-05-17; legacy locale pragma is tolerated, not language-switching syntax.
  • Canonical names are mark, arr.length, map.set, ta.crossOver/ta.crossUnder (plus lowercase aliases).
  • ta.cross_over and ta.cross_under are not canonical namespaced VM functions.
  • Older docs mention plotshape, map.put, arr.size, and object drawing namespaces (line.*/box.*/tag.*/grid.*) as fully available; runtime support differs and should be verified against current VM/compiler implementation.
  • tf.data is currently a pass-through placeholder in VM builtins.
  • Tuple-return TA functions (for example ta.macd, ta.bb) require host-compatible handling; no native tuple destructuring syntax is documented in current parser grammar.

Changelog

Changelog

Version history highlights for syntax/runtime milestones. Release labels use YYYYMMDD.N style to align with API/platform docs.

YeScript syntax and runtime releases use calendar versions in the form YYYYMMDD.N — date stamp plus a same-day increment. Breaking language or bytecode changes bump the date or reset N; additive APIs and runtime improvements ship as regular increments on the release date.

  • majorBreaking DSL keywords, bytecode format, or incompatible runtime semantics.
  • minorNew built-ins, community workflows, or materially expanded script capabilities.
  • patchServer-run, subscription, or documentation-only adjustments without language changes.

20260602.1 · Server-run grants unification

minor
  • Server-run access moved to unified grant ledger flow for script-level runtime control.
  • Run authorization path decoupled from older invite-only subscription tables.

20260531.1 · Server-run subscriber decoupling

patch
  • Run-subscription state separated from creator invite grants for clearer lifecycle handling.
  • POST/DELETE server-run operations aligned to dedicated runtime subscription records.

20260527.1 · Community publishing and library workflow

minor
  • Phase-1 community schema and publication metadata shipped for strategies/indicators/libraries.
  • Library import path integrated into YeScript workspace flow.
  • Community sorting and script type constraints hardened at data layer.

20260519.1 · Plot pane routing upgrade

minor
  • plot / plotHistogram / hline gained optional fourth argument pane ("main" / "sub" / "auto").
  • Per-plot pane classification replaced global single-subpane routing, fixing mixed overlay+oscillator scripts.

20260517.1 · English-only DSL baseline

major
  • Source-language keywords collapsed to English-only; legacy @locale pragma remains tolerated for old scripts.
  • ta.atr compatibility tightened to Pine-style signature ta.atr(length).

20260516.2 · Bytecode v2 and runtime parity pass

major
  • Bytecode upgraded to YESC v2: options/functions sections serialized and validated.
  • Source-aware TA dispatch added via encoded source id for selected TA calls.
  • VM/input/runtime correctness pass: descriptor recording, per-bar state reuse, and safety hardening.