Skip to content

Strategy Development Guide

Strategies extend the Strategy class to add position tracking, order execution, and backtesting support.

Strategy vs Script

FeatureScriptStrategy
Base classextends Scriptextends Strategy
Position trackingNothis.position.isLong, etc.
Order executionNothis.strategy.entry(), etc.
BacktestingNoYes (via Backtest button)
PlottingAll plot typesAll plot types
Built-in functionsAllAll (inherits from Script)

Basic Structure

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

export default class MyStrategy extends Strategy {
  fastLen = input.number('Fast EMA', 9, { min: 1, max: 100 });
  slowLen = input.number('Slow EMA', 21, { min: 1, max: 200 });

  calculate() {
    const fast = this.ema('close', this.fastLen);
    const slow = this.ema('close', this.slowLen);

    plot('Fast', fast, { color: color.cyan, width: 2, overlay: true });
    plot('Slow', slow, { color: color.orange, width: 2, overlay: true });

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

      if (this.crossOver(fast, slow, pf, ps)) {
        this.strategy.entry('Buy', 'long');
      }
      if (this.crossUnder(fast, slow, pf, ps)) {
        this.strategy.close('Exit');
      }
    }
  }
}

Position Object

Access current position state via this.position:

PropertyTypeDescription
isLongbooleanCurrently in a long position
isShortbooleanCurrently in a short position
isFlatbooleanNo open position
sizenumberPosition size (quantity)
entryPricenumberAverage entry price
entryBarnumberBar index where position was opened
typescript
// Only enter if not already in a position
if (buyCondition && this.position.isFlat) {
  this.strategy.entry('Buy', 'long');
}

Order Methods

strategy.entry(signal, direction, options?)

Open a new position or add to an existing one.

typescript
this.strategy.entry('Buy Signal', 'long', { qty: 1 });
this.strategy.entry('Short Signal', 'short', { qty: 2 });
  • If you're long and call entry('x', 'short'), the long position is closed first (reversal)
  • signal is a label for the trade
  • direction must be 'long' or 'short'

strategy.exit(signal, from?, options?)

Close or reduce an existing position.

typescript
this.strategy.exit('Take Profit', 'long');
this.strategy.exit('Stop Loss');  // exits any direction

strategy.close(comment?)

Close the entire position immediately.

typescript
this.strategy.close('End of day exit');

strategy.cancel(signal) / strategy.cancelAll()

Cancel pending orders (for future use).

Complete Strategy Examples

EMA Crossover Strategy

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

export default class EMACrossStrategy extends Strategy {
  fastLen = input.number('Fast', 9, { min: 1, max: 100 });
  slowLen = input.number('Slow', 21, { min: 1, max: 200 });

  calculate() {
    const fast = this.ema('close', this.fastLen);
    const slow = this.ema('close', this.slowLen);
    plot('Fast', fast, { color: color.cyan, width: 2, overlay: true });
    plot('Slow', slow, { color: color.orange, width: 2, overlay: true });

    if (this.bar > 0) {
      const pf = this.getPlot('Fast', 1);
      const ps = this.getPlot('Slow', 1);
      if (this.crossOver(fast, slow, pf, ps)) {
        this.strategy.entry('Buy', 'long');
        plotShape('Buy', true, { shape: 'triangleup', location: 'belowbar', color: color.green });
      }
      if (this.crossUnder(fast, slow, pf, ps)) {
        this.strategy.close('Sell');
        plotShape('Sell', true, { shape: 'triangledown', location: 'abovebar', color: color.red });
      }
    }
  }
}

RSI Mean Reversion

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

export default class RSIMeanReversion extends Strategy {
  length = input.number('RSI Period', 14, { min: 2, max: 100 });
  oversold = input.number('Oversold', 30, { min: 0, max: 50 });
  overbought = input.number('Overbought', 70, { min: 50, max: 100 });

  calculate() {
    const rsi = this.rsi('close', this.length);
    plot('RSI', rsi, { color: color.purple, width: 2 });
    hline('OB', this.overbought, { color: color.red, style: 'dashed' });
    hline('OS', this.oversold, { color: color.green, style: 'dashed' });

    if (rsi < this.oversold && this.position.isFlat) {
      this.strategy.entry('RSI Buy', 'long');
      plotShape('Buy', true, { shape: 'triangleup', location: 'belowbar', color: color.green });
    }
    if (rsi > this.overbought && this.position.isLong) {
      this.strategy.close('RSI Sell');
      plotShape('Sell', true, { shape: 'triangledown', location: 'abovebar', color: color.red });
    }
  }
}

SuperTrend Trend Following

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

export default class SuperTrendStrategy extends Strategy {
  period = input.number('ATR Period', 10, { min: 1, max: 100 });
  factor = input.number('Factor', 3.0, { min: 0.5, max: 10, step: 0.5 });

  calculate() {
    const st = this.supertrend(this.period, this.factor);
    plotColor('ST', st.value, [color.green, color.red],
      st.direction === 1 ? 0 : 1, { width: 2 });

    // Track direction changes
    this.setState('dir', st.direction);
    const prevDir = this.bar > 0 ? this.getState('dir') : st.direction;

    if (st.direction === 1 && prevDir === -1) {
      this.strategy.entry('ST Buy', 'long');
      plotShape('Buy', true, { shape: 'triangleup', location: 'belowbar', color: color.green });
    }
    if (st.direction === -1 && prevDir === 1) {
      this.strategy.close('ST Sell');
      plotShape('Sell', true, { shape: 'triangledown', location: 'abovebar', color: color.red });
    }
  }
}

Backtesting

After writing a strategy:

  1. Click Run to compile and execute
  2. Click the Backtest button in the toolbar
  3. Review results: trade count, win rate, profit factor, Sharpe ratio, equity curve

Tips

  • Check position before entry: Use this.position.isFlat to avoid duplicate entries
  • Use signal labels: They help identify trades in backtest results
  • Add visual signals: Use plotShape() to mark entry/exit points on the chart
  • Test on multiple instruments: Different markets may behave differently
  • Keep it simple: Start with one entry condition and one exit condition, then add complexity

ChartLabs Documentation