---
title: Strategy Functions
description: The strategy() declaration and every strategy.* method - orders, brackets, cancellation, and position getters - with full parameter tables.
---

> **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](../strategies/overview.md); this page is the per-parameter reference.

| Function | Description |
| --- | --- |
| [`strategy`](#strategy) | Declare the script as a strategy and configure the simulated broker |
| [`strategy.entry`](#strategy.entry) | Queue an entry order (market, limit, or stop) |
| [`strategy.exit`](#strategy.exit) | Attach protective bracket legs (profit/loss/stop/limit/trailing) to entries |
| [`strategy.close`](#strategy.close) | Close a named entry at market |
| [`strategy.closeAll`](#strategy.closeall) | Close the entire position at market |
| [`strategy.cancel`](#strategy.cancel) | Cancel pending unfilled orders by id |
| [`strategy.cancelAll`](#strategy.cancelall) | Clear the entire pending order queue |
| [Getters](#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](../strategies/slippage-and-costs.md) |
| `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](../strategies/fill-simulation.md) |

**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](../strategies/fill-simulation.md#intrabar-ordering-and-fill-models).

## 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 |

```javascript title="scripts/probes/strategies/trend-brackets.ks"
//@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 `pendingOrders` in the output.
- The position model is netting: one net position, reversals close-then-open atomically at one fill price.
