SUP · Docs

Strategy script (SupScript)

SupScript is Sup's sandboxed language for backtesting trading strategies on historical candles. It has no eval, network, file access, or transaction authority.

#Language reference

SupScript — strategy scripting language

A tiny, SAFE scripting language for backtesting trading rules on real candles.
It is interpreted (no eval, no host access): every expression is evaluated as a
SERIES across the bars (Pine-style), then a long/short backtest is run over the
entry/exit signals. You write the script and call the runStrategyScript tool; it
returns a backtest card (metrics + equity curve).

WRITING A SCRIPT
- One statement per line. Blank lines are fine.
- Comments start with // or #.

STATEMENTS
- let NAME = EXPR      Define a reusable named series/value (reference it later).
- long when EXPR       Open a LONG when EXPR is true and currently flat.
- short when EXPR      Open a SHORT when flat. (You may use long and short in one script.)
- exit when EXPR       Close the open position when EXPR is true.
- stop N%              Stop-loss N percent from entry (e.g. stop 8%). N is constant.
- target N%            Take-profit N percent from entry (e.g. target 15%). N is constant.
- trail N%             Trailing stop: exit if price retraces N% from the best price
                       reached since entry (e.g. trail 5%). Works for long and short.
- size N%              Capital per trade as a percent of equity (default 100). e.g. size 50%.
- plot(EXPR, "name")   Chart an indicator series under the equity curve (e.g.
                       plot(rsi(close,14), "RSI")) — handy to see what drove the trades.
You need at least one 'long when' or 'short when'. exit/stop/target/trail/size/plot
are optional (a position always closes on the final bar). Multiple 'long when' lines are OR-ed.

PRICE SERIES (built in)
  close open high low volume   and the averages   hl2  hlc3  ohlc4

OPERATORS
  + - * /            arithmetic
  > < >= <= == !=    comparisons (produce true/false)
  and  or  not       logical
  ( )                grouping
Booleans are real values; you can combine conditions: close > sma(close,50) and rsi(close,14) < 40.

PAST VALUES (offset)
  EXPR[n]  = the value n bars ago. n is a constant integer.
  Examples: close[1] (previous close), rsi(close,14)[1], macd_hist(close,12,26,9)[1].

FUNCTIONS  (length / period arguments must be CONSTANT numbers)
  Moving averages:
    sma(src, len)              Simple moving average.
    ema(src, len)              Exponential moving average.
    wma(src, len)              Weighted MA (recent bars heavier).
    hma(src, len)              Hull MA (fast + smooth, low lag).
    vwma(src, len)             Volume-weighted MA.
    linreg(src, len)           Linear-regression value (LSMA endpoint).
  Oscillators / momentum:
    rsi(src, len)              Relative Strength Index (0-100).
    roc(src, len)              Rate of change, percent, over len bars.
    cci(src, len)              Commodity Channel Index (use hlc3 for the classic).
    wpr(len)                   Williams %R (-100..0; uses high/low/close).
    mfi(len)                   Money Flow Index (0-100; a volume-weighted RSI).
    stoch_k(len)               Stochastic %K (0-100).
    stoch_d(len, smooth)       Stochastic %D = sma(%K, smooth).
    macd(src, fast, slow)      MACD line = ema(src,fast) - ema(src,slow).
    macd_signal(src, fast, slow, sig)   Signal line = ema(macd, sig).
    macd_hist(src, fast, slow, sig)     Histogram = macd - signal.
  Trend / volatility:
    atr(len)                   Average True Range (uses high/low/close).
    adx(len)                   Average Directional Index — trend STRENGTH (0-100).
    stdev(src, len)            Rolling standard deviation.
    dev(src, len)              Mean absolute deviation.
    bb_basis(src, len)         Bollinger basis = sma(src, len).
    bb_upper(src, len, mult)   basis + mult * stdev.
    bb_lower(src, len, mult)   basis - mult * stdev.
  Volume:
    obv()                      On-Balance Volume (cumulative signed volume).
    vwap()                     Cumulative VWAP (typical price x volume).
  Range / stats:
    highest(src, len)          Highest value over the last len bars.
    lowest(src, len)           Lowest value over the last len bars.
    sum(src, len)              Rolling sum over len bars.
    cum(src)                   Running (cumulative) sum from the first bar.
    correlation(a, b, len)     Pearson correlation of two series (-1..1).
    change(src)                src - src[1].   change(src, n) = src - src[n].
  Conditions:
    crossover(a, b)            true on the bar a crosses ABOVE b.
    crossunder(a, b)           true on the bar a crosses BELOW b.
    cross(a, b)                true on the bar a crosses b in EITHER direction.
    rising(src, len)           true if src rose on EACH of the last len bars.
    falling(src, len)          true if src fell on EACH of the last len bars.
    iff(cond, a, b)            pick a where cond is true, else b (a conditional value).
  Math / utility:
    abs(x)  sign(x)  sqrt(x)  pow(a, b)  log(x)  exp(x)
    floor(x)  ceil(x)  round(x)  max(a, b)  min(a, b)
    na(x)                      true (1) where x has no value yet (NaN warm-up).
    nz(x)  /  nz(x, repl)      replace NaN with 0 (or repl) — fill warm-up gaps.

HOW THE BACKTEST RUNS
- Warm-up bars (until the longest indicator is ready) are skipped; signals there are ignored.
- Each closed trade pays a 0.1% fee per side; position size is 100% of equity unless you set 'size'.
- A position closes on the first of: exit-signal, stop hit, target hit, trailing-stop hit, or the last bar.
- It reports total return vs buy & hold, est. APY, max drawdown, win rate, profit factor,
  Sharpe and an equity curve. Needs at least ~30 candles.

EXAMPLES

1) RSI mean-reversion (long the dips):
   let r = rsi(close, 14)
   long when r < 30
   exit when r > 55
   stop 8%
   target 15%

2) EMA trend cross:
   let fast = ema(close, 20)
   let slow = ema(close, 50)
   long when crossover(fast, slow)
   exit when crossunder(fast, slow)
   stop 10%

3) Bollinger reversion with momentum filter, both directions:
   let mom = macd_hist(close, 12, 26, 9)
   long when close < bb_lower(close, 20, 2) and mom > mom[1]
   short when close > bb_upper(close, 20, 2) and mom < mom[1]
   exit when crossover(rsi(close, 14), 50)
   stop 6%
   target 12%

4) Trend-follow with a trailing stop, half size, and a plotted filter:
   let trend = ema(close, 100)
   long when close > trend and crossover(ema(close, 10), ema(close, 30))
   trail 8%
   size 50%
   plot(trend, "EMA100")

5) ADX trend-strength filter — only take cross signals when the trend is real:
   let strength = adx(14)
   long when crossover(ema(close, 10), ema(close, 30)) and strength > 25
   exit when crossunder(ema(close, 10), ema(close, 30))
   trail 6%
   plot(strength, "ADX")

6) VWAP + Williams %R reversion:
   long when close < vwap() and wpr(14) < -80
   exit when close > vwap() or wpr(14) > -20
   stop 5%
   target 8%

7) Regime switch with iff — fast MA in strong trends, slow MA when choppy:
   let regime = iff(adx(14) > 25, ema(close, 20), ema(close, 50))
   long when crossover(close, regime)
   exit when crossunder(close, regime)
   stop 7%

8) Volume-confirmed breakout — break out only when volume expands and MFI agrees:
   long when crossover(close, highest(high, 20)[1]) and volume > sma(volume, 20) and mfi(14) > 50
   exit when close < ema(close, 20)
   trail 10%

TIPS
- Encode only what the language supports. If you need a concept it lacks, approximate it.
- Keep entry conditions specific (combine a trend filter + a trigger) for fewer, better trades.
- Always frame results as research / education, not financial advice.