Python SDK
Orders
Place, modify and cancel orders, and read the order book and trades from Python.
These methods wrap the 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
and are never retried. Reads need no IP, and a short
429on a read is retried once. - Every code has a constant, such as
SahiAPI.ORDER_TYPE_LIMIT; only MTF productFis passed as a string. - Examples use
api,instrument_idandquotefrom Getting started. See 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.
Place order#
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
Calls POST /v1/orders · Scope: orders.write
Sends one order. All arguments are keyword-only.
NSE, NFO, BSE or BFO.symbol, e.g. RELIANCE, NIFTY29DEC26C24500. Look it up; don't build it.B buy, S sell.lot_size. At most the freeze quantity.LMT, MKT, SL-LMT or SL-MKT.C, I, M or F; see the table above.DAY or IOC.0 for MKT and SL-MKT; otherwise a multiple of the tick size.SL-LMT and SL-MKT.AMO for an after-market order; default REGULAR.Returns#
{"order_ids": [...]}, always a list.
Raises#
SahiValidationException: a field breaks a rule, e.g. unknown symbol, qty over freeze, aREGULARorder while the market is closed.SahiIpNotAllowedException: not sent from a registered IP.SahiRateLimitException: over 10/s, 250/min or 10,000/day, shared by place, modify and cancel.SahiTimeoutException: no reply; the order may still have been placed. See 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
statusRejectedwith arejection_reason. Read the status before relying on an order. - Market orders read back as limits.
MKTandSL-MKTare converted once to protectedLMTandSL-LMT, and the order book shows the converted type and price. - After-market orders. Send
variant=SahiAPI.VARIANT_AMOonly while the market is closed; it goes out at the next open. See Market hours.
Example — a stop-loss buy#
Triggers if the price rises to trigger_price, then sends a limit at price.
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.
Modify order#
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
Calls PUT /v1/orders/{order_id} · Scope: orders.write
Changes an Open or OpenPartial order. Pass only the fields you change.
place_order or the order book.DAY or IOC.MKT or SL-MKT.Returns#
{"order_id": "..."}.
Raises#
SahiConfigurationException: no field to change, raised before sending.SahiInvalidOrderStateException: the order is no longer open.SahiOrderNotFoundException: not on today's book.- Validation, IP, rate-limit and timeout errors as for
place_order.
Cancel order#
api.cancel_order(order_id: str, *, timeout: float | None = None) -> None
Calls DELETE /v1/orders/{order_id} · Scope: orders.write
Cancels an Open or OpenPartial order. Returns None.
Raises#
SahiInvalidOrderStateException: already completed, cancelled or rejected.SahiOrderNotFoundException: not on today's book.- IP, rate-limit and timeout errors as for
place_order.
Order book#
api.get_order_list(*, timeout: float | None = None) -> dict
Calls GET /v1/orders · Scope: orders.read
Every order on the account today, in any status.
Returns#
{"orders": [...]}; fields are on the endpoint.
Raises#
SahiRateLimitException: over 5/s, 250/min or 10,000/day, shared by the three order reads.
Order details#
api.get_order_detail(order_id: str, *, timeout: float | None = None) -> dict
Calls GET /v1/orders/{order_id} · Scope: orders.read
One order, with the same fields as an order-book entry. Right after placing, wait a second before reading it.
Raises#
SahiOrderNotFoundException: not on today's book (yet).SahiValidationException: not a valid order id.- Rate limit as for
get_order_list.
Trades for an order#
api.get_trade_list_for_order(order_id: str, *, timeout: float | None = None) -> dict
Calls GET /v1/orders/{order_id}/trades · Scope: orders.read
The fills behind one order; empty if it has not traded.
Returns#
{"trades": [...]}.
Raises#
- Rate limit as for
get_order_list.