Since engine 3.0.61; verified against engine 3.0.61. Every example on this page is an executed probe against that build.
Overview
Functions for declaring a backtestable strategy and placing simulated orders against the broker emulator. Concepts, fill semantics, and result interpretation live in the Strategies section; this page is the per-parameter reference.
| Function | Description |
|---|---|
strategy | Declare the script as a strategy and configure the simulated broker |
strategy.entry | Queue an entry order (market, limit, or stop) |
strategy.exit | Attach protective bracket legs (profit/loss/stop/limit/trailing) to entries |
strategy.close | Close a named entry at market |
strategy.closeAll | Close the entire position at market |
strategy.cancel | Cancel pending unfilled orders by id |
strategy.cancelAll | Clear the entire pending order queue |
| Getters | positionSize, equity, netProfit, and friends |
A script contains either define() or strategy(), never both. Calling any strategy.* method without a strategy() declaration is a compile-time error (strategy methods require a strategy() declaration).
strategy
strategy(title, position?, axis?, customTitle?, format?, maxBarsBack?, initialCapital?, currency?, commissionPercent?, slippageBps?, slippageModel?, qtyType?, qtyValue?, pyramiding?, fillModel?): declares the strategy and its broker configuration. Accepts everything define() accepts plus the broker parameters. Literal-only arguments, validated like define(); any broker parameter may also be wired to an input() so users can adjust it from script settings.
| Parameter | Type | Default | Description |
|---|---|---|---|
title | string | required | Display name, surfaced on the chart legend and the Strategy Tester |
position | 'onchart' | 'offchart' | 'onchart' | Strategies default onchart so trade markers land on the price series |
initialCapital | number | 10000 | Starting equity; must be positive |
currency | string | "USD" | Display label for money-denominated stats |
commissionPercent | number | 0 | Charged per fill as a percent of fill notional |
slippageBps | number | 0 | Adverse basis points on market, stop, and trailing fills. Limit fills are exempt (a limit price is a bound) |
slippageModel | 'fixed' | 'bookEstimate' | 'fixed' | 'bookEstimate' prices market-crossing fills from recorded order-book depth where available, falling back to slippageBps with a counted disclosure. See Slippage and Costs |
qtyType | 'fixed' | 'percentOfEquity' | 'cash' | 'percentOfEquity' | Default sizing for entries without an explicit qty |
qtyValue | number | 100 | Units for 'fixed'; percent for 'percentOfEquity' ((qtyValue/100 * equityAtFill) / fillPrice); account currency for 'cash' (qtyValue / fillPrice) |
pyramiding | number | 1 | Maximum stacked same-direction entries; excess entries are rejected and counted |
fillModel | 'pessimistic' | 'pathHeuristic' | 'pessimistic' | Intrabar ordering assumption when a bar could fill two levels and no finer data covers it. See Fill Simulation |
Returns: void.
strategy.entry
strategy.entry(id, direction, qty=na, limit=na, stop=na, ocaName=na, comment=na): queues an entry. Plain calls are market orders for the next bar open; limit/stop create resting orders that fill when touched. Re-issuing an id replaces the pending unfilled order with that id.
| Parameter | Type | Description |
|---|---|---|
id | string | Your key for this entry; exits target it via fromEntry, and strategy.close(id) closes it |
direction | 'long' | 'short' | Order direction. An entry opposite the current position is a reversal: it closes the position fully at the same fill, then opens the new one |
qty | number | Optional explicit quantity; overrides the declaration's qtyType sizing. Fractional quantities are legal |
limit | number | Optional limit price: fills when the bar trades through it, at the better of open and limit, with no slippage |
stop | number | Optional stop price: fills on touch, slippage-adjusted (stops cross the market) |
ocaName | string | Optional one-cancels-all group shared with other entries and exits: when any grouped order fills, the rest cancel |
comment | string | Optional free text carried on the trade |
Returns: void. Rejected when the pyramiding cap is reached, sizing resolves non-positive, the bar has NaN OHLC, or the bar is not confirmed; rejections are counted in stats.rejectedOrders, never thrown.
strategy.exit
strategy.exit(id, fromEntry=na, qty=na, qtyPercent=na, profit=na, limit=na, loss=na, stop=na, trailPoints=na, trailOffset=na, ocaName=na, comment=na): attaches protective bracket legs to open entries. At least one of profit, limit, loss, stop, or a trailing pair is required. Legs within one exit id are inherently one-cancels-all: a full fill cancels the siblings, a partial fill keeps the bracket armed for the remainder.
| Parameter | Type | Description |
|---|---|---|
id | string | Key for this exit order; re-issuing replaces the pending version |
fromEntry | string | Target entry id. Omitted: protects all open entries |
qty / qtyPercent | number | Total contracts (or percent of targeted quantity) to exit, allocated FIFO across targeted trades |
profit / loss | number | Take-profit / stop distance in ticks from entry; must be finite and positive |
limit / stop | number | Absolute take-profit / stop prices; must be finite and positive. Ticks and absolute together on the same leg is a diagnostic |
trailPoints | number | Favorable excursion (price units) that activates the trailing stop |
trailOffset | number | Trailing distance once active; the stop ratchets monotonically with new favorable extremes |
ocaName | string | Optional one-cancels-all group shared with entries and exits |
comment | string | Optional free text |
Returns: void. Pre-arming before the entry fills is allowed; once armed, the exit auto-cancels if its trades are closed by another order. Take-profit limit legs fill without slippage; stop and trailing legs are slippage-adjusted. When both a stop and a profit level fall inside one bar, resolution follows fill simulation.
strategy.close
strategy.close(id, comment=na): market-closes the trades opened by entry id at the next bar open.
strategy.closeAll
strategy.closeAll(comment=na): market-closes the entire position at the next bar open. Exit reason is closeAll.
strategy.cancel
strategy.cancel(id): removes all pending unfilled orders with that id across entry and exit namespaces. Unknown ids are silent no-ops.
strategy.cancelAll
strategy.cancelAll(): clears the entire pending queue, including a pending closeAll.
Getters
All zero-argument, valid on any bar, reflecting state as of the current bar:
| Getter | Returns |
|---|---|
strategy.positionSize() | Signed open quantity (negative for shorts, 0 when flat) |
strategy.positionAvgPrice() | Average entry price of the open position |
strategy.equity() | Cash plus open position marked at the current close, minus fees paid |
strategy.openProfit() | Unrealized PnL of the open position |
strategy.netProfit() | Realized net profit so far |
strategy.closedTradeCount() | Closed trades so far |
strategy.winTradeCount() / strategy.lossTradeCount() | Winning / losing closed trades so far |
strategy.maxDrawdown() | Largest equity decline so far |
//@version=2
strategy(title="Trend with Brackets", 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"])Order lifecycle notes
- Orders placed during bar N join the queue for bar N+1; the processing sequence each bar is protective exits, then signal exits, then entries, each in insertion order.
- All order methods are recorded as rejected (not thrown) on NaN-OHLC bars and non-confirmed bars.
- On the last bar, unfilled orders remain visible under
pendingOrdersin the output. - The position model is netting: one net position, reversals close-then-open atomically at one fill price.