Docs / Language Syntax

Language Syntax

TDSL is statically typed and supports structs, enums, persistent series buffers, and compiles to high-performance Rust.


Primitive Types

Function / PropertyDescription
intInteger number (32-bit).
doubleDouble-precision float. Default for prices and calculations.
boolBoolean: true or false.
stringText string.
datetimePoint in time, stored as Unix timestamp (f64).
timeframeChart timeframe constant: Timeframe.M1, Timeframe.H1, Timeframe.H4, Timeframe.D1, etc.
colorRGBA color shown as a colour picker in the UI.
enumUser-defined enumeration — shown as a dropdown in the UI.
Variable declarationsTDSL
int    count   = 50;
double price   = 1.23456;
bool   is_long = true;
string label   = "Upper Band";
datetime last_alert = 0.0;
timeframe tf = Timeframe.H4;

System Data

Access market data length and engine-level orchestration variables.

Function / PropertyTypeDescription
candle_count()doubleReturns the total number of bars available in the current history.
Chart.resume_indexintThe index of the first bar that needs calculation (0 on first run, >0 on new ticks).
Using system primitivesTDSL
calculate() {
  // Always loop from the last stable index to the latest candle
  for (int i = Chart.resume_index; i < candle_count(); i++) {
    // ... calculate ...
  }
}

Series Buffers

A series array is a DMA-backed persistent buffer that survives between calculate() calls. Each element corresponds to one bar.

Series declaration and accessTDSL
series double upper[];
series double lower[];

calculate() {
  int len = candle_count();
  upper[] = create_array(len);
  lower[] = create_array(len);

  // Array-style: absolute bar index
  upper[i] = mean + (2.0 * std_dev);

  // Series-style: offset from current bar (0 = latest)
  double prev_upper = upper(1);
  double two_ago    = upper(2);
}
Note
arr(0) reads relative to the most recent bar. arr[i] reads by absolute bar index.

Structs & Returns

TDSL supports two ways to return data from an indicator: Named Structs (recommended for clarity) or Anonymous Tuples.

Option 1: Named Structs

Fields map to names in the display block (e.g. MyStruct.value).

Named Struct StyleTDSL
display {
  outputs: 2
  IndicatorResult.value  { type: "line"; color: "#3b82f6"; name: "Value"; };
  IndicatorResult.signal { type: "line"; color: "#ef4444"; name: "Signal"; };
}

struct IndicatorResult {
  double value;
  double signal;
}

series double val_buf[];
series double sig_buf[];

calculate() {
  int len = candle_count();
  val_buf[] = create_array(len); sig_buf[] = create_array(len);
  
  for (int i = Chart.resume_index; i < len; i++) {
     val_buf[i] = close(0, i) * 1.05;
     sig_buf[i] = close(0, i) * 0.95;
  }
  
  return IndicatorResult { value: val_buf, signal: sig_buf };
}

Option 2: Anonymous Tuples (Buffer Arrays)

Return a simple array of buffers using [ ]. These map to buffer[index] in the display block.

Tuple StyleTDSL
display {
  outputs: 3
  buffer[0] { type: "line"; color: "#10b981"; name: "Upper"; };
  buffer[1] { type: "line"; color: "#f59e0b"; name: "Middle"; };
  buffer[2] { type: "line"; color: "#ef4444"; name: "Lower"; };
}

calculate() {
  int len = candle_count();
  series double up[]; series double mid[]; series double lo[];
  up[] = create_array(len); mid[] = create_array(len); lo[] = create_array(len);
  
  for (int i = Chart.resume_index; i < len; i++) {
     mid[i] = close(0, i);
     up[i]  = mid[i] + 100 * Symbol.Point();
     lo[i]  = mid[i] - 100 * Symbol.Point();
  }

  return [up, mid, lo]; 
}
Caution
Compatibility Note: Anonymous Tuple returns ([ ]) are only supported in standalone Indicators. When building Strategies or sub-indicator proxies, you must return data using Named Structs.

Logic & Control Flow

TDSL supports standard C-style comparison operators and loop control statements for filtering data and managing execution flow.

Comparison Operators

Function / PropertyParametersReturnsDescription
==voidEqual to.
!=voidNot equal to.
>voidGreater than.
<voidLess than.
>=voidGreater than or equal to.
<=voidLess than or equal to.

Control Statements

Loops and ConditionalsTDSL
// Continue and Break in loops
for (int i = 0; i < Position.Count(); i = i + 1) {
  Position.SetIndex(i);
  if (Position.Symbol() == "EURUSD") { continue; } // Skip specific symbol
  if (Position.Magic() != 12345)     { continue; } // Only process my magic
  
  Trade.Close(Position.Ticket());
}

// Complex logic gates
if (Account.Balance() > 1000 && !Position.Exists()) {
  Trade.Buy(Symbol(), 0.1);
} else if (Account.Equity() < 500 || Account.IsConnected() == false) {
  Trade.CloseAll();
}

Enums

Enums appear as dropdown selectors in the parameter panel.

Enum definition and usageTDSL
enum Source { Close = 0, Open = 1, High = 2, Low = 3 }

parameters { Source src = Source.Close; int period = 14; }

calculate() {
  double src_data[];
  if (src == Source.Close) { src_data = close(); }
  if (src == Source.High)  { src_data = high();  }
}

Parameters Block

Parameters with UI OverridesTDSL
parameters {
  string _General_ = "=== General Settings ===";
  int    period    = 14;   // Smoothing Period
  double factor    = 2.0;  // Deviation Factor

  string _Risk_    = "=== Risk Settings ==="; // Risk Management
  double lot_size  = 0.1;  // Fixed Lot Size
  bool   use_sl    = true; // Enable Stop Loss
}

State & Persistence

state { }Script lifetimeSerialised and restored on reload. Use for values that must survive indicator resets.
staticScript lifetimeThread-safe persistent value. Survives tick-to-tick.
global varInit() callModule-scope variable, reset on initialisation.
Persistence formsTDSL
state { datetime lastAlertTime = 0.0; int tradeCount = 0; }
static double lastBar = 0.0;

bool newbar() {
  static datetime last;
  datetime cur = time(0);
  if (last != cur) { last = cur; return true; }
  return false;
}

Display Configuration

Display block with Buffer IndicesTDSL
display {
  separate_window: false;
  outputs: 3
  buffer[0] { type: "line"; color: "#c42626ff"; name: "Upper Band"; }; 
  buffer[1] { type: "line"; color: "#b0aaaaff"; name: "Middle Band"; }; 
  buffer[2] { type: "line"; color: "#50c426ff"; name: "Lower Band"; };                   
  
  fill { buffer_a: 0; buffer_b: 1; color: "rgba(220,38,38,0.05)"; };
}
"line"Continuous line connecting bar values.
"histogram"Vertical bar from zero to the value.
"arrows"Directional arrow glyph at each bar.
"dots"Single dot plotted at each bar.
"candles"Full OHLC candle from four buffers.

Control Flow

Control flowTDSL
if (rsi_val < 30.0) { signal = 1; }
else if (rsi_val > 70.0) { signal = -1; }

for (int i = Chart.resume_index; i < candle_count(); i = i + 1) { 
  result[i] = closes_array[i]; 
}

while (count < max) { count = count + 1; }

double lot = use_fixed ? fixed_lot : Symbol.ToLots(risk_pct, sl_pips);