Skip to content

Advanced Indicator Techniques

Advanced patterns for building sophisticated indicators in CodeLab.

Multi-Plot Indicators

Plot 3 or more lines with different visual properties.

typescript
// ADX with +DI and -DI (simplified)
const adxVal = this.adx(14);
const emaFast = this.ema('close', 9);
const emaSlow = this.ema('close', 21);
const emaTrend = this.ema('close', 50);

plot('Fast', emaFast, { color: color.cyan, width: 2, overlay: true });
plot('Slow', emaSlow, { color: color.orange, width: 1, overlay: true });
plot('Trend', emaTrend, { color: color.purple, width: 1, overlay: true });

Dynamic Per-Bar Coloring

2-Color Pattern (Bullish/Bearish)

typescript
const val = this.ema('close', 20);
const prev = this.bar > 0 ? this.getPlot('EMA', 1) : val;
plotColor('EMA', val,
  [color.green, color.red],
  val > prev ? 0 : 1,
  { width: 2 }
);

4-Color Histogram (MACD Style)

Position + direction creates 4 visual states:

typescript
const m = this.macd('close', 12, 26, 9);
const hist = m.histogram;
const prevHist = this.bar > 0
  ? this.getPlot('MACD', 1) - this.getPlot('Signal', 1)
  : 0;

let histColor;
if (hist >= 0) {
  histColor = hist > prevHist ? '#16a34a' : '#86efac';  // strong/weak bullish
} else {
  histColor = hist < prevHist ? '#dc2626' : '#fca5a5';  // strong/weak bearish
}
plotHistogram('Histogram', hist, { color: histColor });

Gradient Coloring (Multiple Levels)

typescript
const rsiVal = this.rsi('close', 14);
const colors = ['#16a34a', '#86efac', '#6b7280', '#fca5a5', '#dc2626'];
const idx = rsiVal > 80 ? 4 : rsiVal > 60 ? 3 : rsiVal > 40 ? 2 : rsiVal > 20 ? 1 : 0;
plotColor('RSI', rsiVal, colors, idx, { width: 2 });

Signal Markers

Mark specific conditions with shapes on the chart.

typescript
// Buy/sell arrow signals
const fast = this.ema('close', 9);
const slow = this.ema('close', 21);
plot('Fast', fast); plot('Slow', slow);

if (this.bar > 0) {
  const pf = this.getPlot('Fast', 1);
  const ps = this.getPlot('Slow', 1);

  if (this.crossOver(fast, slow, pf, ps)) {
    plotShape('Buy', true, {
      shape: 'triangleup',
      location: 'belowbar',
      color: color.green,
      size: 'small',
      text: 'BUY'
    });
  }
  if (this.crossUnder(fast, slow, pf, ps)) {
    plotShape('Sell', true, {
      shape: 'triangledown',
      location: 'abovebar',
      color: color.red,
      size: 'small',
      text: 'SELL'
    });
  }
}

Complex State Management

Tracking Trend Direction

typescript
calculate() {
  const st = this.supertrend(10, 3);

  // Store current direction in state
  this.setState('direction', st.direction);

  // Access previous direction
  if (this.bar > 0) {
    const prevDir = this.getState('direction');
    if (st.direction === 1 && prevDir === -1) {
      this.log('Trend flipped BULLISH at', this.close);
    }
  }
}

Counting Consecutive Events

typescript
calculate() {
  const up = this.close > this.open;

  if (this.isFirstBar) {
    this.setState('streak', up ? 1 : -1);
  } else {
    const prev = this.getState('streak');
    if (up) {
      this.setState('streak', prev > 0 ? prev + 1 : 1);
    } else {
      this.setState('streak', prev < 0 ? prev - 1 : -1);
    }
  }

  const streak = this.getState('streak');
  plotHistogram('Streak', streak, {
    color: streak > 0 ? color.green : color.red
  });
}

Combining Multiple Indicators

Build composite indicators that combine trend, momentum, and volume signals.

typescript
import { Script, input, plotHistogram, plot, hline, color } from '@chartlabs/script-sdk';

export default class CompositeSignal extends Script {
  adxLen = input.number('ADX Period', 14, { min: 1, max: 50 });
  rsiLen = input.number('RSI Period', 14, { min: 1, max: 50 });

  calculate() {
    // Trend filter
    const adxVal = this.adx(this.adxLen);
    const trending = adxVal > 25;

    // Momentum
    const rsiVal = this.rsi('close', this.rsiLen);
    const bullMomentum = rsiVal > 50;

    // Volume
    const mfiVal = this.mfi(14);
    const volumeConfirm = mfiVal > 50;

    // Composite score
    let score = 0;
    if (trending) score += bullMomentum ? 1 : -1;
    if (volumeConfirm) score += 1;
    else score -= 1;

    plotHistogram('Signal', score, {
      color: score > 0 ? color.green : score < 0 ? color.red : color.gray
    });
    plot('ADX', adxVal, { color: color.purple });
    hline('Trend Threshold', 25, { color: color.gray, style: 'dashed' });
  }
}

Squeeze Momentum Pattern

Detect when Bollinger Bands are inside Keltner Channel (squeeze), then plot momentum direction.

typescript
import { Script, input, plotColor, color } from '@chartlabs/script-sdk';

export default class SqueezeMomentum extends Script {
  bbLen = input.number('BB Length', 20, { min: 2, max: 200 });
  bbMult = input.number('BB Mult', 2.0, { min: 0.5, max: 5, step: 0.5 });
  kcMult = input.number('KC Mult', 1.5, { min: 0.5, max: 5, step: 0.5 });

  calculate() {
    const bb = this.bbands('close', this.bbLen, this.bbMult);

    // Keltner Channel
    const kcMid = this.ema('close', this.bbLen);
    const atrVal = this.atr(this.bbLen);
    const kcUpper = kcMid + atrVal * this.kcMult;
    const kcLower = kcMid - atrVal * this.kcMult;

    // Squeeze detection
    const squeeze = bb.lower > kcLower && bb.upper < kcUpper;

    // Momentum using linear regression
    const momentum = this.linreg('close', this.bbLen) - this.sma('close', this.bbLen);

    // 4 states: squeeze on/off x momentum up/down
    plotColor('Squeeze', momentum,
      [color.green, color.red, color.cyan, color.magenta],
      squeeze
        ? (momentum > 0 ? 2 : 3)   // squeeze: cyan/magenta
        : (momentum > 0 ? 0 : 1),  // no squeeze: green/red
      { width: 3 }
    );
  }
}

Background and Bar Coloring

Highlight Zones

typescript
const rsiVal = this.rsi('close', 14);

// Color background in extreme zones
if (rsiVal > 80) bgcolor('#ef444415');  // very light red
if (rsiVal < 20) bgcolor('#22c55e15');  // very light green

Color Bars by Trend

typescript
const st = this.supertrend(10, 3);
barcolor(st.direction === 1 ? color.green : color.red);

ChartLabs Documentation