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();
| Method | Meaning |
|---|---|
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
| Function | Value |
|---|---|
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.