# Orders

> Place, modify and cancel simulated orders with strategy.entry, order, exit, close and cancel.

Order functions queue instructions for the broker emulator. They do not fill at
once: the emulator works them from the next bar on (see
[Broker emulator](/docs/scripting/strategies/broker-emulator)). They run in handlers
only and return nothing.

## Overview

| Function | Purpose |
|---|---|
| `strategy.entry(id, direction, qty?, limit:, stop:, ...)` | Open or add to a position; reverses an opposite one; respects `pyramiding`. |
| `strategy.order(id, direction, qty?, limit:, stop:, ...)` | Raw buy or sell: no reversal, no pyramiding limit. |
| `strategy.exit(id, fromEntry?, profit:, loss:, limit:, stop:, trailPoints:, trailOffset:, ...)` | Take-profit, stop-loss and trailing stop for an entry. |
| `strategy.close(id, qty:, qtyPercent:, immediately:)` | Close an entry's trades at market. |
| `strategy.closeAll(immediately:)` | Close the whole position at market. |
| `strategy.cancel(id)` | Cancel the pending orders with this id. |
| `strategy.cancelAll()` | Cancel every pending order. |

`strategy.long` and `strategy.short` are the two directions.

## Order ids {#ids}

Every order has a string id. Ids do three jobs:

- **Identity.** Placing an order again with the id of a pending order *modifies* it
  instead of adding a second one.
- **Linking.** `strategy.exit("TP", "Long")` and `strategy.close("Long")` refer to
  the entry with id `Long`.
- **Reporting.** The id labels the marks on the chart and the Signal column of the
  list of trades, and is `entryId` / `exitId` in
  [trade records](/docs/scripting/strategies/position-and-trades#trades).

Keep ids short and stable: an id built from a changing value creates a new order on
every bar.

## Order lifetime {#lifetime}

| Order | Lifetime |
|---|---|
| Market (no `limit`, no `stop`) | Fills at the next fill opportunity, then is gone. |
| Limit or stop entry | Pending across bars until it fills or is cancelled. |
| Exit | Pending while its entry is open; dropped when the position is flat and no entry is pending. |

## strategy.entry {#entry}

```text
strategy.entry(id: string, direction: Direction, qty: float? = null,
               limit: float? = null, stop: float? = null, ocaName: string? = null,
               ocaType: OcaType? = null, comment: string? = null, alertMessage: string? = null)
```

- Without `limit` and `stop` it is a market order; with `limit` a limit order, with
  `stop` a stop order, with both a stop-limit order.
- Without `qty` the size comes from `defaultQtyType` and `defaultQtyValue`.
- An entry against the current position closes it and opens the new direction with
  `qty`: long 1 and `strategy.entry("S", strategy.short)` with size 1 sells 2.
- Entries in the direction of the position are limited by `pyramiding`.
- `alertMessage` raises an alert when the order fills, with Pine's placeholders
  filled in: `{{ticker}}`, `{{strategy.order.action}}` (`buy` or `sell`),
  `{{strategy.order.contracts}}`, `{{strategy.order.price}}`, `{{strategy.order.id}}`
  and `{{strategy.order.comment}}`. Fills already on the chart when the strategy is
  added are history and raise nothing. The other order calls take it the same way.

```flowscope
script "Breakout entries"

strategy(defaultQtyType: strategy.fixed, defaultQtyValue: 0.1)

data chart = subscribe(data.ohlcv)

on chart.close {
  let hi = ta.highest(chart.high, 20)
  let lo = ta.lowest(chart.low, 20)
  if hi != null && lo != null && strategy.positionSize == 0.0 {
    // Re-placed every bar: the stop orders follow the channel.
    strategy.entry("Up", strategy.long, stop: hi + context.tickSize)
    strategy.entry("Down", strategy.short, stop: lo - context.tickSize)
  }
}
```

## strategy.order {#order}

`strategy.order` buys or sells exactly `qty` and ignores `pyramiding`. An order
against the position reduces it by its size and only reverses it when it is larger.
Use it to scale in and out by hand.

```flowscope
script "Scale out"

strategy(defaultQtyType: strategy.fixed, defaultQtyValue: 1.0)

data chart = subscribe(data.ohlcv)

on chart.close {
  let ema = ta.ema(chart.close, 50)
  if ema != null {
    if strategy.positionSize == 0.0 && ta.crossover(chart.close, ema) {
      strategy.order("Buy", strategy.long, 1.0)
    }
    // Sell half when price stretches 2 % above the average.
    if strategy.positionSize > 0.5 && chart.close > ema * 1.02 {
      strategy.order("Trim", strategy.short, 0.5)
    }
  }
}
```

## strategy.exit {#exit}

```text
strategy.exit(id: string, fromEntry: string? = null, qty: float? = null,
              qtyPercent: float? = null, profit: float? = null, limit: float? = null,
              loss: float? = null, stop: float? = null, trailPrice: float? = null,
              trailPoints: float? = null, trailOffset: float? = null, ocaName: string? = null,
              comment: string? = null, commentProfit: string? = null,
              commentLoss: string? = null, commentTrailing: string? = null,
              alertMessage: string? = null)
```

- `profit` and `loss` are distances in **ticks** from the entry's fill price; `limit`
  and `stop` are absolute prices. Give either form for each leg.
- The trailing stop activates at `trailPrice`, or `trailPoints` ticks in profit, and
  then follows the best price `trailOffset` ticks behind.
- Without `fromEntry` the exit applies to every open entry.
- `qty` or `qtyPercent` (default 100) exits part of the entry.
- The legs form one group: when one fills, the others are cancelled.

```flowscope
script "Bracket"

strategy(defaultQtyType: strategy.fixed, defaultQtyValue: 1.0)

data chart = subscribe(data.ohlcv)

on chart.close {
  if ta.crossover(ta.ema(chart.close, 9), ta.ema(chart.close, 21)) {
    strategy.entry("Long", strategy.long)
    // 200 ticks target, 100 ticks stop.
    strategy.exit("TP/SL", "Long", profit: 200.0, loss: 100.0)
  }
}
```

A trailing stop that starts once the trade is 150 ticks in profit and trails 50
ticks behind:

```flowscope
script "Trailing stop"

strategy(defaultQtyType: strategy.fixed, defaultQtyValue: 1.0)

data chart = subscribe(data.ohlcv)

on chart.close {
  if ta.crossover(chart.close, ta.sma(chart.close, 100)) {
    strategy.entry("Long", strategy.long)
    strategy.exit("Trail", "Long", trailPoints: 150.0, trailOffset: 50.0, loss: 300.0)
  }
}
```

## strategy.close and strategy.closeAll {#close}

`strategy.close("Long")` closes the trades of entry `Long` with a market order at the
next fill opportunity; `qty` or `qtyPercent` closes part of them. With
`immediately: true` the order fills at once, at the current close. `strategy.closeAll`
closes the whole position.

```flowscope
script "Time stop"

strategy(defaultQtyType: strategy.fixed, defaultQtyValue: 1.0)

data chart = subscribe(data.ohlcv)

state barsIn = 0

on chart.close {
  if strategy.positionSize != 0.0 {
    barsIn += 1
  } else {
    barsIn = 0
  }
  if strategy.positionSize == 0.0 && ta.crossover(chart.close, ta.ema(chart.close, 20)) {
    strategy.entry("Long", strategy.long)
  }
  // Out after 10 bars whatever happens.
  if barsIn >= 10 {
    strategy.closeAll(comment: "Time stop")
  }
}
```

## Cancelling {#cancel}

`strategy.cancel("Up")` removes the pending orders with id `Up`;
`strategy.cancelAll()` removes every pending order. Filled orders cannot be
cancelled; close the position instead.

## One-cancels-all groups {#oca}

Entries with the same `ocaName` form a group. With `ocaType: strategy.oca.cancel`, a
fill cancels the other orders of the group; with `strategy.oca.reduce` it reduces
them by the filled size. The breakout example above can use it so that only one of
the two stop entries ever fills:

```flowscope
script "OCA breakout"

strategy(defaultQtyType: strategy.fixed, defaultQtyValue: 1.0)

data chart = subscribe(data.ohlcv)

on chart.close {
  let hi = ta.highest(chart.high, 20)
  let lo = ta.lowest(chart.low, 20)
  if hi != null && lo != null && strategy.positionSize == 0.0 {
    strategy.entry("Up", strategy.long, stop: hi, ocaName: "break", ocaType: strategy.oca.cancel)
    strategy.entry("Down", strategy.short, stop: lo, ocaName: "break", ocaType: strategy.oca.cancel)
  }
}
```
