## Orders
These methods wrap the [Orders](/api/v1/reference/orders/) endpoints one for
one. Prices are paise, quantities are units, and each returns the endpoint's
JSON as a `dict`.

- **Order writes** (place, modify, cancel) need a
  [registered IP](/api/v1/reference/authentication/#register-your-static-ip)
  and are never retried. Reads need no IP, and a short `429` on a read is
  retried once.
- **Every code has a [constant](/sdk/python/#constants)**, such as
  `SahiAPI.ORDER_TYPE_LIMIT`; only MTF product `F` is passed as a string.
- **Examples** use `api`, `instrument_id` and `quote` from
  [Getting started](/sdk/python/). See [Trading terms](/sdk/python/#trading-terms)
  for the vocabulary.

Each segment takes only some products; any other raises
`SahiValidationException`.

| Segment | Products |
|---|---|
| `NSE` | `C` delivery, `I` intraday, `F` MTF |
| `BSE` | `C` delivery, `I` intraday |
| `NFO`, `BFO` | `M` carry-forward, `I` intraday |

Live order updates are on [Live streams](/sdk/python/streams/).

### api.place_order(...) — Place order

**Calls:** [`POST /v1/orders`](/api/v1/reference/orders/#post-v1orders--place-order) · **Scope:** `orders.write`

Sends one order. All arguments are keyword-only.

#### Signature

```python
api.place_order(*, exchange_segment: str, symbol: str, txn_type: str, qty: int, order_type: str, product: str, validity: str, price: int, trigger_price: int | None = None, disclosed_qty: int | None = None, market_protection: float | None = None, variant: str | None = None, timeout: float | None = None) -> dict
```

| Parameter | Type | Required | Notes |
|---|---|---|---|
| `exchange_segment` | str | yes | `NSE`, `NFO`, `BSE` or `BFO`. |
| `symbol` | str | yes | The scrip master's `symbol`, e.g. `RELIANCE`, `NIFTY29DEC26C24500`. Look it up; don't build it. |
| `txn_type` | str | yes | `B` buy, `S` sell. |
| `qty` | int | yes | Units. For F&O, a multiple of `lot_size`. At most the [freeze quantity](/api/v1/reference/orders/#freeze-quantity). |
| `order_type` | str | yes | `LMT`, `MKT`, `SL-LMT` or `SL-MKT`. |
| `product` | str | yes | `C`, `I`, `M` or `F`; see the table above. |
| `validity` | str | yes | `DAY` or `IOC`. |
| `price` | int | yes | Paise. `0` for `MKT` and `SL-MKT`; otherwise a multiple of the tick size. |
| `trigger_price` | int | for SL | Paise. Required for `SL-LMT` and `SL-MKT`. |
| `disclosed_qty` | int | no | Units shown to the market at once. |
| `market_protection` | float | no | `MKT` / `SL-MKT` only. Omit or `-1` for [auto](/api/v1/reference/orders/#market-protection); else `0.01` to `100` percent. |
| `variant` | str | no | `AMO` for an after-market order; default `REGULAR`. |
| `timeout` | float | no | Seconds, overriding the client default. |

#### Returns

`{"order_ids": [...]}`, always a list.

#### Raises

- [`SahiValidationException`](/sdk/python/errors/#sahivalidationexception): a field breaks a rule, e.g. unknown symbol, qty over freeze, a `REGULAR` order while the market is closed.
- [`SahiIpNotAllowedException`](/sdk/python/errors/#sahiipnotallowedexception): not sent from a registered IP.
- [`SahiRateLimitException`](/sdk/python/errors/#sahiratelimitexception): over 10/s, 250/min or 10,000/day, shared by place, modify and cancel.
- [`SahiTimeoutException`](/sdk/python/errors/#sahitimeoutexception): no reply; the order may still have been placed. See [Find the order after a timeout](#find-the-order-after-a-timeout).

#### Notes

- **Accepted is not placed.** Tick size and price band are checked after the
  order id is returned; a failing order then shows `status` `Rejected` with a
  `rejection_reason`. Read the status before relying on an order.
- **Market orders read back as limits.** `MKT` and `SL-MKT` are converted once
  to protected `LMT` and `SL-LMT`, and the order book shows the converted type
  and price.
- **After-market orders.** Send `variant=SahiAPI.VARIANT_AMO` only while the
  market is closed; it goes out at the next open. See
  [Market hours](/sdk/python/#market-hours).

#### Example

```python
result = api.place_order(
    exchange_segment=SahiAPI.EXCHANGE_SEGMENT_NSE,
    symbol="RELIANCE",
    txn_type=SahiAPI.TXN_TYPE_BUY,
    qty=1,
    order_type=SahiAPI.ORDER_TYPE_LIMIT,
    product=SahiAPI.PRODUCT_DELIVERY,
    validity=SahiAPI.VALIDITY_DAY,
    price=quote["dpr_lower"],  # paise
)
order_id = result["order_ids"][0]
```

#### Example — a stop-loss buy

Triggers if the price rises to `trigger_price`, then sends a limit at `price`.

```python
tick = round(float(api.get_instrument_by_id(instrument_id)["tick_size"]) * 100)  # rupees to paise
api.place_order(
    exchange_segment=SahiAPI.EXCHANGE_SEGMENT_NSE,
    symbol="RELIANCE",
    txn_type=SahiAPI.TXN_TYPE_BUY,
    qty=1,
    order_type=SahiAPI.ORDER_TYPE_SL_LIMIT,
    product=SahiAPI.PRODUCT_DELIVERY,
    validity=SahiAPI.VALIDITY_DAY,
    trigger_price=quote["dpr_upper"] - 10 * tick,
    price=quote["dpr_upper"],
)
```

#### Find the order after a timeout

There is no client order id, so match the order book on what you sent. Treat
more than one match as a case to resolve by hand.

```python
import time

sent_at = int(time.time() * 1000)
# ... place_order raised SahiTimeoutException ...
time.sleep(1)
matches = [
    o for o in api.get_order_list()["orders"]
    if o["symbol"] == "RELIANCE" and o["qty"] == 1 and o["created_at"] >= sent_at - 5000
]
print(matches)
```

### api.modify_order(...) — Modify order

**Calls:** [`PUT /v1/orders/{order_id}`](/api/v1/reference/orders/#put-v1ordersorder_id--modify-order) · **Scope:** `orders.write`

Changes an `Open` or `OpenPartial` order. Pass only the fields you change.

#### Signature

```python
api.modify_order(order_id: str, *, qty: int | None = None, price: int | None = None, order_type: str | None = None, validity: str | None = None, trigger_price: int | None = None, disclosed_qty: int | None = None, market_protection: float | None = None, timeout: float | None = None) -> dict
```

| Parameter | Type | Required | Notes |
|---|---|---|---|
| `order_id` | str | yes | From `place_order` or the order book. |
| `qty` | int | no | New total quantity, in units. |
| `price` | int | no | New limit price, in paise. |
| `order_type` | str | no | New order type. |
| `validity` | str | no | `DAY` or `IOC`. |
| `trigger_price` | int | no | Paise, for stop orders. |
| `disclosed_qty` | int | no | Units. |
| `market_protection` | float | no | Only with a change to `MKT` or `SL-MKT`. |
| `timeout` | float | no | Seconds. |

#### Returns

`{"order_id": "..."}`.

#### Raises

- [`SahiConfigurationException`](/sdk/python/errors/#sahiconfigurationexception): no field to change, raised before sending.
- [`SahiInvalidOrderStateException`](/sdk/python/errors/#sahiinvalidorderstateexception): the order is no longer open.
- [`SahiOrderNotFoundException`](/sdk/python/errors/#sahiordernotfoundexception): not on today's book.
- Validation, IP, rate-limit and timeout errors as for `place_order`.

#### Example

```python
api.modify_order(order_id, price=quote["dpr_lower"] + 10)  # paise
```

### api.cancel_order(...) — Cancel order

**Calls:** [`DELETE /v1/orders/{order_id}`](/api/v1/reference/orders/#delete-v1ordersorder_id--cancel-order) · **Scope:** `orders.write`

Cancels an `Open` or `OpenPartial` order. Returns `None`.

#### Signature

```python
api.cancel_order(order_id: str, *, timeout: float | None = None) -> None
```

| Parameter | Type | Required | Notes |
|---|---|---|---|
| `order_id` | str | yes | The order to cancel. |
| `timeout` | float | no | Seconds. |

#### Raises

- [`SahiInvalidOrderStateException`](/sdk/python/errors/#sahiinvalidorderstateexception): already completed, cancelled or rejected.
- [`SahiOrderNotFoundException`](/sdk/python/errors/#sahiordernotfoundexception): not on today's book.
- IP, rate-limit and timeout errors as for `place_order`.

#### Example

```python
api.cancel_order(order_id)
```

#### Example — cancel every open order

```python
for o in api.get_order_list()["orders"]:
    if o["status"] in (SahiAPI.ORDER_STATUS_OPEN, SahiAPI.ORDER_STATUS_OPEN_PARTIAL):
        api.cancel_order(o["order_id"])
```

### api.get_order_list(...) — Order book

**Calls:** [`GET /v1/orders`](/api/v1/reference/orders/#get-v1orders--order-book-today) · **Scope:** `orders.read`

Every order on the account today, in any status.

#### Signature

```python
api.get_order_list(*, timeout: float | None = None) -> dict
```

#### Returns

`{"orders": [...]}`; fields are on [the endpoint](/api/v1/reference/orders/#get-v1orders--order-book-today).

#### Raises

- [`SahiRateLimitException`](/sdk/python/errors/#sahiratelimitexception): over 5/s, 250/min or 10,000/day, shared by the three order reads.

#### Example

```python
for o in api.get_order_list()["orders"]:
    print(o["order_id"], o["symbol"], o["status"])
```

### api.get_order_detail(...) — Order details

**Calls:** [`GET /v1/orders/{order_id}`](/api/v1/reference/orders/#get-v1ordersorder_id--order-details) · **Scope:** `orders.read`

One order, with the same fields as an order-book entry. Right after placing,
wait a second before reading it.

#### Signature

```python
api.get_order_detail(order_id: str, *, timeout: float | None = None) -> dict
```

#### Raises

- [`SahiOrderNotFoundException`](/sdk/python/errors/#sahiordernotfoundexception): not on today's book (yet).
- [`SahiValidationException`](/sdk/python/errors/#sahivalidationexception): not a valid order id.
- Rate limit as for `get_order_list`.

#### Example

```python
order = api.get_order_detail(order_id)
print(order["status"], order["filled_qty"], order["rejection_reason"])
```

### api.get_trade_list_for_order(...) — Trades for an order

**Calls:** [`GET /v1/orders/{order_id}/trades`](/api/v1/reference/orders/#get-v1ordersorder_idtrades--trades-for-an-order) · **Scope:** `orders.read`

The fills behind one order; empty if it has not traded.

#### Signature

```python
api.get_trade_list_for_order(order_id: str, *, timeout: float | None = None) -> dict
```

#### Returns

`{"trades": [...]}`.

#### Raises

- Rate limit as for `get_order_list`.

#### Example

```python
for t in api.get_trade_list_for_order(order_id)["trades"]:
    print(t["qty"], "at", t["price"] / 100, "INR")
```

