Example Strategies

Examples: Spot Strategies

Three complete spot strategies you can paste and run, from a two-line trend follower to bracketed exits, each one an executed example from this documentation's probe suite.

Three complete, runnable spot strategies. Each one is small enough to read in a minute, ships as an executed example in this documentation's probe suite, and makes a good starting skeleton for your own script. Paste any of them into the editor and press Run.

Moving average cross

The smallest useful strategy: go long when the fast EMA crosses above the slow one, flatten when it crosses back under. One entry rule, one exit rule, nothing else.

//@version=2
strategy(title="MA Cross Strategy", position="onchart", axis=true, initialCapital=10000, qtyType="percentOfEquity", qtyValue=50, commissionPercent=0.05, slippageBps=2)

timeseries bars = ohlcv(symbol=currentSymbol, exchange=currentExchange)
timeseries fast = ema(source=bars.close, period=9)
timeseries slow = ema(source=bars.close, period=21)

if (crossover(fast, slow)) {
  strategy.entry("L", "long")
}
if (crossunder(fast, slow)) {
  strategy.closeAll()
}

plotLine(value=fast, width=1, colors=["#4f8cff"], label=["Fast EMA"], desc=["9-period EMA of close"])
plotLine(value=slow, width=1, colors=["#f59e0b"], label=["Slow EMA"], desc=["21-period EMA of close"])

What to notice: percentOfEquity sizing keeps position size proportional as equity compounds, and commissionPercent plus slippageBps make the backtest pay realistic costs on every fill.

RSI reversion with a protective stop

Buys oversold dips and adds a protective stop under every entry, so a dip that keeps dipping gets cut instead of riding to the bottom.

//@version=2
strategy(title="RSI Reversion", position="onchart", axis=true, initialCapital=10000, qtyType="percentOfEquity", qtyValue=25, commissionPercent=0.05, slippageBps=2)

timeseries bars = ohlcv(symbol=currentSymbol, exchange=currentExchange)
timeseries r = rsi(source=bars.close, period=14)
timeseries oversold = 30
timeseries recovered = 55
var lastClose = bars.close

if (crossover(r, oversold)) {
  strategy.entry("Dip", "long")
}
if (strategy.positionSize() > 0) {
  strategy.exit("Protect", fromEntry="Dip", stop=lastClose * 0.96)
}
if (crossover(r, recovered)) {
  strategy.closeAll()
}

plotLine(value=bars.close, width=1, colors=["#94a3b8"], label=["Close"], desc=["Close price"])

What to notice: strategy.exit with fromEntry scopes the stop to the named entry, and the stop follows lastClose at placement time. The first strategy tutorial builds this script up line by line.

Trend entries with bracket exits

A crossover entry bracketed by both a stop and a take-profit limit. Whichever side the market touches first closes the trade and cancels the other side.

//@version=2
strategy(title="Trend with Brackets", position="onchart", axis=true, initialCapital=10000, qtyType="fixed", qtyValue=1, pyramiding=1, fillModel="pathHeuristic")

timeseries bars = ohlcv(symbol=currentSymbol, exchange=currentExchange)
timeseries fast = sma(source=bars.close, period=5)
timeseries slow = sma(source=bars.close, period=20)
var lastClose = bars.close

if (crossover(fast, slow)) {
  strategy.entry("Trend", "long")
}
if (strategy.positionSize() > 0) {
  strategy.exit("Protect", fromEntry="Trend", stop=lastClose * 0.97, limit=lastClose * 1.05)
}

plotLine(value=fast, width=1, colors=["#4f8cff"], label=["Fast SMA"], desc=["5-period SMA of close"])
plotLine(value=slow, width=1, colors=["#8b5cf6"], label=["Slow SMA"], desc=["20-period SMA of close"])

What to notice: the stop and limit placed through one strategy.exit call form an OCA pair. How contested bars resolve (both sides touched in one bar) is exactly what the fill simulation page explains.