Signal Template
Signal templates create a single-instrument strategy from price, indicator, and position-state conditions. They are the default choice when your idea is "enter when this condition happens, exit when that condition happens."
Available Signal Templates
| Template | Behavior |
|---|---|
| Breakout | Enters when price breaks a recent high or low. |
| Mean Reversion | Enters when price stretches away from a reference band and momentum confirms exhaustion. |
| MA Trend | Follows moving-average trend changes. |
| Range Bounce | Looks for reversals near recent support and resistance. |
| MACD Momentum | Enters and exits on MACD momentum flips. |
Choosing a Starting Template
Choose the template whose market assumption matches the idea you want to test. Breakout and MA Trend follow directional movement, while Mean Reversion and Range Bounce expect price to return toward a reference. MACD Momentum reacts to changes in momentum rather than a fixed price level. A template is a starting point, not evidence that its assumption holds for a particular symbol or period.
Before running a backtest, replace the example ticker and notional, review every lookback window, and confirm that long and short behavior is intended. Test entry and exit conditions separately, then inspect trade count, drawdown, fees, and out-of-sample behavior. Add position sizing and risk controls only after the basic signals behave as expected.
Product and Inventory Requirements
The examples below are two-sided strategies: they attempt to open a short from a flat strategy position. Use a supported perpetual/futures ticker for that behavior. Do not copy the short-entry branch into a cash-only spot Paper strategy and expect it to borrow coins.
Spot orders can sell only owned inventory after existing sell reservations. SHORT and SELL are aliases for a sell-direction intent; neither enables borrowing. NoPosition() refers to the strategy position, not the account's available inventory. Broker validates actual sellable inventory when the order is submitted.
For a user-specified spot strategy, agree on long-only behavior if that is what the user wants; do not silently switch to futures or remove the short leg. Setting a leverage number does not change the product. DSL validation success is not proof that a future order has sufficient inventory.
Candle and Tick Cadence
The indicator templates below are candle strategies. Run them with a candle
timeframe such as 1m or 1h; their bare open, high, low, close, and
volume variables are completed candle series.
Do not copy a bare close condition into a tick strategy. Tick strategies
use the scalar price for the current observation. When a tick strategy also
needs candle history, request it explicitly:
ticker = context['ticker']
candles = get_data(ticker, '1m')
entry_signal = (price >= 0.55) & (candles.close[-1] > candles.open[-1])
emit(entry_signal, entry(ticker, 'LONG', Notional(5), when=NoPosition()))
Breakout DSL
ticker = context['ticker']
breakout_high = highest(high, 20).shift(1)
breakout_low = lowest(low, 20).shift(1)
long_entry = close > breakout_high
short_entry = close < breakout_low
long_exit = close < sma(close, 20)
short_exit = close > sma(close, 20)
emit(long_entry, entry(ticker, 'LONG', Notional(500), when=NoPosition()))
emit(short_entry, entry(ticker, 'SHORT', Notional(500), when=NoPosition()))
emit(long_exit, exit_position(ticker, when=HasPosition(side='LONG')))
emit(short_exit, exit_position(ticker, when=HasPosition(side='SHORT')))
Mean Reversion DSL
ticker = context['ticker']
upper, middle, lower = bollinger_bands(close, 20, 2.0)
rsi_val = rsi(close, 14)
long_entry = (close < lower) & (rsi_val < 30)
short_entry = (close > upper) & (rsi_val > 70)
long_exit = close >= middle
short_exit = close <= middle
emit(long_entry, entry(ticker, 'LONG', Notional(500), when=NoPosition()))
emit(short_entry, entry(ticker, 'SHORT', Notional(500), when=NoPosition()))
emit(long_exit, exit_position(ticker, when=HasPosition(side='LONG')))
emit(short_exit, exit_position(ticker, when=HasPosition(side='SHORT')))
MA Trend DSL
ticker = context['ticker']
fast = ema(close, 20)
slow = ema(close, 50)
long_entry = crossover(fast, slow)
short_entry = crossunder(fast, slow)
long_exit = crossunder(fast, slow)
short_exit = crossover(fast, slow)
emit(long_entry, entry(ticker, 'LONG', Notional(500), when=NoPosition()))
emit(short_entry, entry(ticker, 'SHORT', Notional(500), when=NoPosition()))
emit(long_exit, exit_position(ticker, when=HasPosition(side='LONG')))
emit(short_exit, exit_position(ticker, when=HasPosition(side='SHORT')))
Range Bounce DSL
ticker = context['ticker']
support = lowest(low, 20).shift(1)
resistance = highest(high, 20).shift(1)
mid = (support + resistance) / 2
long_entry = close <= support * 1.01
short_entry = close >= resistance * 0.99
long_exit = close >= mid
short_exit = close <= mid
emit(long_entry, entry(ticker, 'LONG', Notional(500), when=NoPosition()))
emit(short_entry, entry(ticker, 'SHORT', Notional(500), when=NoPosition()))
emit(long_exit, exit_position(ticker, when=HasPosition(side='LONG')))
emit(short_exit, exit_position(ticker, when=HasPosition(side='SHORT')))
MACD Momentum DSL
ticker = context['ticker']
macd_line, signal_line, _ = macd(close, 12, 26, 9)
long_entry = crossover(macd_line, signal_line)
short_entry = crossunder(macd_line, signal_line)
long_exit = crossunder(macd_line, signal_line)
short_exit = crossover(macd_line, signal_line)
emit(long_entry, entry(ticker, 'LONG', Notional(500), when=NoPosition()))
emit(short_entry, entry(ticker, 'SHORT', Notional(500), when=NoPosition()))
emit(long_exit, exit_position(ticker, when=HasPosition(side='LONG')))
emit(short_exit, exit_position(ticker, when=HasPosition(side='SHORT')))