Since engine 3.0.61; verified against engine 3.0.61. Every example on this page is an executed probe against that build.
The strategy() declaration
strategy() accepts everything define() accepts (title, position, axis, customTitle, format, maxBarsBack) plus the broker parameters below. All are optional except title. Arguments are literal-only and validated like define(); any strategy param may also be wired to a normal input() so users can adjust it from the script settings, with the declaration acting as the default.
strategy(title="MA Cross",
initialCapital=10000, // starting equity, > 0
currency="USD", // display label
commissionPercent=0.0, // per fill, percent of notional
slippageBps=0.0, // adverse, per market-crossing fill
slippageModel="fixed", // "fixed" | "bookEstimate"
qtyType="percentOfEquity", // "fixed" | "percentOfEquity" | "cash"
qtyValue=100, // meaning depends on qtyType
pyramiding=1, // max stacked same-direction entries
fillModel="pessimistic") // "pessimistic" | "pathHeuristic"
| Parameter | Default | Meaning |
|---|---|---|
initialCapital | 10000 | Starting account equity. Must be positive. |
currency | "USD" | Display label for money-denominated stats. |
commissionPercent | 0 | Charged on every fill as a percent of fill notional. |
slippageBps | 0 | Adverse basis points applied to market, stop, and trailing fills. Limit fills are exempt: a limit price is a bound and can fill better but never worse. |
slippageModel | "fixed" | "bookEstimate" prices market-crossing fills from recorded order-book depth where available. See Slippage and costs. |
qtyType / qtyValue | "percentOfEquity" / 100 | Default order sizing. "fixed": qtyValue units per entry. "percentOfEquity": (qtyValue / 100 * equityAtFill) / fillPrice. "cash": qtyValue / fillPrice. |
pyramiding | 1 | Maximum stacked same-direction entries. Excess entries are rejected and counted, never silently dropped. |
fillModel | "pessimistic" | Intrabar ordering assumption when a bar could fill two levels. See Fill simulation. |
Strategy scripts default to position="onchart" so trade markers land on the price series.
Order API
strategy.entry(id, direction, qty=na, limit=na, stop=na, ocaName=na, comment=na)
strategy.close(id, comment=na) // close the named entry (market, next open)
strategy.closeAll(comment=na)
strategy.cancel(id) // cancel pending unfilled orders with this id
strategy.cancelAll()
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)
directionis"long"or"short".idis your string key; re-issuing an id replaces the pending unfilled order with that id.- A plain
strategy.entryis a market order for the next bar open. Addinglimitorstopcreates a resting order that fills when touched. strategy.exitattaches bracket legs to an entry id:profitandlossin ticks,limitandstopas absolute prices. At least one leg is required.exitwithoutfromEntryprotects all open entries. Stop, limit, and trail legs within one exit id are inherently one-cancels-all.trailPointsactivates a trailing stop once the trade's favorable excursion reaches that many price units;trailOffsetsets the trailing distance. The trail ratchets monotonically with new favorable extremes.ocaNamejoins any orders (entries and exits) into a one-cancels-all group: when one fills, the rest cancel immediately.- Getters, valid on any bar:
strategy.positionSize()(signed),strategy.positionAvgPrice(),strategy.equity(),strategy.openProfit(),strategy.netProfit(),strategy.closedTradeCount(),strategy.winTradeCount(),strategy.lossTradeCount(),strategy.maxDrawdown().
//@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"])Position model
The broker nets to one position. A strategy.entry in the opposite direction is a reversal: it closes the existing position fully at the same fill, then opens the new one at the requested quantity. pyramiding caps same-direction stacking; rejected entries are counted in the output rather than thrown.
Sizing details worth knowing:
- Explicit
qtyon an order always wins over the declaration'sqtyType. - Sized-at-fill quantities (
percentOfEquity,cash) resolve from the slippage-adjusted fill price, and fractional quantities are legal (the broker does not round lots). - A computed size is rejected and counted when equity at fill is not positive or the quantity is not finite and positive.
Order methods are recorded as rejected (not thrown) when the current bar has NaN OHLC values or is not confirmed. On the last bar, unfilled orders remain visible under pending orders in the output.