Skip to main content

Orders and backtesting

Orders are grouped: one order group is one trade, with its entries, take profits, stop loss and optional trailing stop. The group id names the trade.

Simple orders​

// 100% of equity, take profit 2% above, stop loss 1% below.
strategy.long("breakout", 100, close * 1.02, close * 0.99);
strategy.short("breakdown", 50);
strategy.close("breakout");
strategy.closeAll();

The order builder​

strategy.order("pullback", Side.Long)
.limitEntry(close * 0.99, 0.5) // two entry legs, half each
.limitEntry(close * 0.98, 0.5)
.takeProfit(close * 1.02, 0.5) // two take-profit legs
.takeProfit(close * 1.05, 0.5)
.stopLoss(close * 0.97)
.trailingStop(1.5, close * 1.02) // trail 1.5% once price reaches +2%
.qtyRiskBased(1.0) // size so the stop costs 1% of equity
.submit();
MethodMeaning
marketEntry(weight), limitEntry(price, weight), stopLimitEntry(stop, limit, weight)Entry legs. weight is the leg's share of the group's quantity
takeProfit(price, weight)Exit legs. When all have filled, the position is closed
stopLoss(price)The initial stop
trailingStop(offsetPct, activation)Trail at offsetPct percent from the best price since entry. Starts at the activation price, or immediately if omitted. The stop only tightens
qtyFixed(qty), qtyPercentEquity(pct), qtyRiskBased(riskPct)Position sizing. Without one, the backtest's default size is used
cancelOnTpBeforeFill()Drop unfilled entries if price reaches a take profit first

Change an open trade with strategy.reduce(id, qty), strategy.close(id) or strategy.cancel(id) (cancels pending entries).

Reading the account​

FunctionValue
strategy.positionSize()Signed position size: positive long, negative short, 0 flat
strategy.positionAvgPrice()Average entry price
strategy.equity()Equity marked at the bar close
strategy.netProfit()Realized profit after commission
strategy.openTrades(), strategy.closedTrades()Trade counts

These reflect the backtest. Live, they read 0.

How the backtest fills​

  • Orders submitted on a bar fill from the next bar's open. A script never trades on a price it has not seen.
  • Limit entries and take profits fill at their price when the bar reaches it.
  • If a bar touches both the stop loss and a take profit, the stop loss wins. Without intrabar data the engine assumes the worst case.
  • A trailing stop moves after the bar's exits are checked, so a new stop level applies from the next bar.
  • Commission is charged on entries and exits. Slippage, when configured, is applied against you on market fills and stops; limit orders fill at their price.
  • Pyramiding defaults to 1: a second submit on a group that already holds a position is ignored.

Results include the trade list, the equity curve and TradingView-style statistics (net profit, win rate, profit factor, drawdown, and more), for all trades and split into long and short.