Docs / Indicators

Indicators

Indicators process price history and render visual overlays on the chart. TDSL supports three distinct modes — write from scratch, wrap a native engine, or load an external script.


Three Modes Overview

Mode A
Custom Standard
Write all the math. Full control over every calculation step.
Mode B
Native Fetch
Wraps one of the 30 built-in native engine indicators.
Mode C
Custom Fetch
Loads and wraps another .tbc script from your library.
Mode D
Hybrid Extension
Fetch a base indicator and layer custom secondary math on top.

Mode A — Custom Standard

Write all indicator math directly in TDSL. Use series double[] buffers, populate them in calculate(), and return a typed struct.

Tip
Start your loop at Chart.resume_index - 1 (or period - 1 on first run) for incremental performance.
BollingerBands.tbc — Custom StandardTDSL
about { author: "CoreXTrader"; version: "2.0.0"; }

parameters { int period = 20; double multiplier = 2.0; }

struct BollingerSignal { double upper; double middle; double lower; double buy_signal; double sell_signal; }

display {
  separate_window: false; outputs: 5
  BollingerSignal.upper  { type: "line";  color: "#c42626ff"; name: "Upper"; width: 1; };
  BollingerSignal.middle { type: "line";  color: "#b0aaaaff"; name: "Middle"; width: 0.5; };
  BollingerSignal.lower  { type: "line";  color: "#50c426ff"; name: "Lower"; width: 1; };
  BollingerSignal.sell_signal { type: "arrow"; color: "#c42626ff"; arrow_code: 234; };
  BollingerSignal.buy_signal  { type: "arrow"; color: "#50c426ff"; arrow_code: 233; };
  fill { buffer_a: 2; buffer_b: 0; color: "rgba(19,75,228,0.15)"; };
}

series double upper[]; series double middle[]; series double lower[];
series double buy_sig[]; series double sell_sig[];

calculate() {
  double closes[] = close();
  int len   = candle_count();
  int start = Chart.resume_index > 0 ? Chart.resume_index - 1 : period - 1;

  upper[] = create_array(len); middle[] = create_array(len); lower[] = create_array(len);
  buy_sig[] = create_array(len); sell_sig[] = create_array(len);

  for (int i = start; i < len; i = i + 1) {
    double sum = 0.0;
    for (int j = 0; j < period; j = j + 1) { sum = sum + closes[i - j]; }
    double mean = sum / period;
    middle[i] = mean;
    double sq = 0.0;
    for (int j = 0; j < period; j = j + 1) { double d = closes[i-j] - mean; sq = sq + (d*d); }
    double std_dev = Math.Sqrt(sq / period);
    upper[i] = mean + (multiplier * std_dev);
    lower[i] = mean - (multiplier * std_dev);
    if (i > 0) {
      if (closes[i-1] < lower[i-1] && closes[i] > lower[i]) { buy_sig[i]  = lower[i]; }
      if (closes[i-1] > upper[i-1] && closes[i] < upper[i]) { sell_sig[i] = upper[i]; }
    }
  }

  return BollingerSignal {
        upper: upper,
        middle: middle,
        lower: lower,
        sell_signal: sell_sig,
        buy_signal: buy_sig,
      };
}

Mode B — Native Fetch

Wrap a native engine. Use Native.Source, Native.Init, Native.Parameter, and Native.Bind in Init(), then fetch buffers in the proxy .calculate() block.

BollingerNative.tbc — Native FetchTDSL
struct BollingerSignal { double upper; double middle; double lower; }

parameters { int period = 20; double std_dev = 2.0; }

Init() {
  Native.Source(i.Bollinger); // or indi.Bollinger
  Native.Init(Symbol(), Timeframe);
  Native.Parameter(period, std_dev, Price.Close);
  Native.Bind(NativeBands);
}

NativeBands.calculate() {
  int len = candle_count();
  series double mid_buf[]; series double up_buf[]; series double lo_buf[];
  mid_buf[] = create_array(len); up_buf[] = create_array(len); lo_buf[] = create_array(len);
  // Buffer indices: 0=Middle, 1=Upper, 2=Lower
  Native.Fetch(0, mid_buf); Native.Fetch(1, up_buf); Native.Fetch(2, lo_buf);
  return BollingerSignal { upper: up_buf, middle: mid_buf, lower: lo_buf };
}

Mode C — Custom Fetch

Load any .tbc indicator script and access its output buffers via Custom.Fetch.

Wrapping an external indicatorTDSL
parameters { int Bands_period = 20; double multiplier = 2.0; }

display {
  outputs: 2
  Bands.upper { type: "line"; color: "#dc2626"; name: "Upper Band"; };
  Bands.lower { type: "line"; color: "#16a34a"; name: "Lower Band"; };
}

struct BollingerSignal { double upper; double lower; }

Init() {
  Custom.Source("Bands Arrow.tbc");
  Custom.Init(Symbol(), Timeframe.H1);
  Custom.Parameter(Bands_period, multiplier);
  Custom.Bind(Bands);
}

Bands.calculate() {
  int len = candle_count();
  series double up[]; series double lo[];
  up[] = create_array(len); lo[] = create_array(len);
  Custom.Fetch(0, up);  // buffer 0 → upper band
  Custom.Fetch(1, lo);  // buffer 1 → lower band
  return BollingerSignal { upper: up, lower: lo };
}

Mode D — Hybrid Extension

Fetch data from native engines or external scripts, then perform custom secondary calculations (e.g. Volatility Bands derived from a Native EMA).

HybridIndi.tbcTDSL
struct Signal { double value; double vol_adjusted; }
parameters { int period = 50; double mult = 2.0; }

Init() {
  // Fetch native EMA
  Native.Source(i.EMA); Native.Init(Symbol(), Timeframe);
  Native.Parameter(period, Price.Close);
  Native.Bind(BaseEMA);

  // Fetch custom volatility script
  Custom.Source("HV.tbc"); Custom.Init(Symbol(), Timeframe);
  Custom.Bind(BaseEMA);
}

BaseEMA.calculate() {
  int len = candle_count();
  series double ema[]; series double hv[]; series double result[];
  ema[] = create_array(len); hv[] = create_array(len); result[] = create_array(len);

  // Fetch from BOTH sources
  Native.Fetch(0, ema);
  Custom.Fetch(0, hv);

  // Custom secondary math: Adjust EMA by Historical Volatility
  for (int i = Chart.resume_index; i < len; i++) {
    result[i] = ema[i] * (1.0 + hv[i] * mult);
  }
  return Signal { value: ema, vol_adjusted: result };
}

Native Buffer Index Map

i.Bollinger0 Middle · 1 Upper · 2 Lower
i.MACD0 MACD Line · 1 Signal · 2 Histogram
i.RSI0 Value (0–100)
i.Stochastic0 %K · 1 %D
i.ATR0 Value
i.Ichimoku0 Tenkan · 1 Kijun · 2 Span A · 3 Span B · 4 Chikou
i.SAR0 Value
i.Supertrend0 Value · 1 Direction (+1 up / −1 down)
i.Pivot0 Pivot · 1 R1 · 2 S1 · 3 R2 · 4 S2 · 5 R3 · 6 S3
i.MA0 Value