Placing and reading orders¶
Every instrument that can be traded carries the members on this page. Five of them send orders to UBI, which passes them on to a broker, six read this instrument's own rows out of the day's order book and trade book, and four read the order engine's parents, which are the synthetic orders and held limit orders UBI is working. An index cannot be traded, so EquityIndex and the other index classes have none of these members.
These are real orders
The members with a places orders badge send orders through UBI to real brokers, with real money. UBI does not check the market's hours, and a broker that accepts an order can still see it filled within milliseconds. Pass dry_run=True to place_order, modify_order or cancel_order first: UBI then builds the exact request it would send to the broker and returns it without sending anything.
The table below lists the fifteen members this page documents.
| Kind | Member | Description |
|---|---|---|
| places orders | place_order |
Places one order in this instrument through UBI. |
| places orders | modify_order |
Changes one pending order through UBI. |
| places orders | cancel_order |
Cancels one pending order through UBI. |
| places orders | cancel_open_orders |
Cancels every order in this instrument that is still waiting, whether at a broker or held in UBI's order engine. |
| places orders | cancel_parent |
Cancels one of the order engine's parents, with every leg it still has resting at a broker. |
| property | orders |
Every one of today's orders in this instrument, whatever its status. |
| property | open_orders |
Today's orders in this instrument that can still be changed. |
| property | completed_orders |
Today's orders in this instrument that filled in full. |
| property | rejected_orders |
Today's orders in this instrument that a broker or the exchange refused. |
| property | cancelled_orders |
Today's orders in this instrument that were cancelled. |
| property | trades |
Today's trades in this instrument. |
| property | parents |
This instrument's synthetic orders and held orders that the order engine has not finished. |
| method | parent |
Reads one of the order engine's parents, whether or not it has finished. |
| method | parent_orders |
Today's broker orders that one parent placed. |
| method | parent_trades |
Today's trades in the broker orders that one parent placed. |
Placing an order through a named price, such as "buy at the best bid", has its own page, Price wrappers. Changing a position without saying which side you are on is on Positions, and the fifty-four order types UBI builds out of ordinary orders are on Synthetic orders. All of them end in place_order.
Glossary of plain strings¶
The library passes the order vocabulary to UBI as plain lower-case strings, with no constants and no enums, because UBI already checks every value and answers HTTP 400 with a clear message when one is wrong. UBI ignores case, so "buy" and "BUY" are the same. The table below lists the values these members accept and return; Vocabulary has the full list for the whole library.
| Parameter | Values | Meaning |
|---|---|---|
transaction_type |
buy, sell |
The side of the order. |
order_type |
market |
Fill at whatever price the market offers. Takes no price. |
limit |
Fill at the price given or better. Needs a price. | |
sl |
A stop-loss limit: waits for the trigger price, then rests a limit. Needs a price and a trigger price. | |
sl-m |
A stop-loss market: waits for the trigger price, then sends a market order. Needs a trigger price and takes no price. | |
product |
cnc |
Delivery. A buy puts shares in the demat account. |
mis |
Intraday. The broker closes the position before the session ends. | |
nrml |
Carry forward, for futures and options held overnight. | |
validity |
day, ioc |
Good for the day, or immediate-or-cancel. UBI uses day when none is given. |
status (returned) |
PENDING, OPEN, COMPLETE, CANCELLED, REJECTED, EXPIRED |
UBI's own upper-case status of an order. |
outcome (returned) |
accepted, rejected, unknown, partial, armed |
What happened to the request. partial means some of the orders of a type that sends several at once were accepted and some were not. armed means the order engine is holding the order, waiting for a price or a time. |
UBI ties the price fields to the order type, and the library does not check this before sending. The table below shows the rule, which you will otherwise meet as a BadRequestError.
order_type |
price |
trigger_price |
|---|---|---|
market |
must be absent | must be absent |
limit |
required | must be absent |
sl |
required | required |
sl-m |
must be absent | required |
A price_reference stands in for price, and a quantity_reference stands in for quantity. Both are described under place_order.
Nothing is checked before sending¶
The library sends the price and the quantity to UBI exactly as you give them. It does not round a price to the tick size, it does not check that a quantity is a whole number of lots, and it does not check that the market is open. UBI and the broker behind it hold those rules, and their refusal is the most accurate message you can get. The consequence is that the error you see comes from UBI, as one of the exceptions on the Errors page.
Quantities are always in units, never in lots. An MCX gold future has a lot of 100, so one lot is quantity=100, and quantity=1 is refused with HTTP 400.
How an order travels¶
The sequence below follows one order that carries a price_reference, from your code to the broker and back. Every order takes this path through UBI's order engine, which has placed every order since UBI removed its direct placement mode on 2026-09-27.
sequenceDiagram
autonumber
participant P as Your program
participant I as TradeableInstrument
participant C as Shared client
participant A as UBI API worker
participant E as UBI order engine
participant B as Broker
P->>I: place_order with a price_reference
I->>C: the body
C->>A: POST /api/orders/place
A->>A: check the body and resolve the instrument
A->>E: intent on the Redis stream
E->>E: read the quote, work the price out, round it to the tick
E->>B: the broker's own order request
B-->>E: order id
E-->>A: answer on the intent's list
A-->>C: 200 with order_id, intent_id and parent_id
C-->>I: answer
I-->>P: the answer as a dict
A plain day limit order with a price of its own stops at step 6: the engine holds it, answers at once with HTTP 202 and an outcome of armed, and sends it only when the book reaches its price. Order engine explains that, and UBI's page on the order engine describes the engine itself.
place_order¶
places orders place_order(transaction_type, order_type, quantity, product, price=None, trigger_price=None, validity=None, disclosed_quantity=None, after_market=False, tag=None, dry_run=False, price_reference=None, quantity_reference=None, synthetic=None)POST /api/orders/place
This method places one order in this instrument. You never name a broker: UBI chooses one from the brokers that carry the instrument and can take the order, and the answer says which it chose. Every optional field left as None is left out of the request entirely, rather than sent as zero, because UBI treats a missing price and a zero price differently.
An answer with an outcome of accepted means the broker took the order, not that the order survived. The exchange can still refuse it a moment later, which is what happens to an ordinary order sent while the market is closed, so read its real fate from orders. To queue an order for the next session, pass after_market=True.
The last three parameters describe something for UBI to work out instead of stating it. A price_reference names a price, such as "the second best offer", which UBI reads from the live quote and rounds to the tick when it sends the order. A quantity_reference names a quantity, such as "the whole position", which UBI reads from the account's positions. A synthetic object turns the order into one of UBI's fifty-four synthetic order types.
A plain limit order with a price of its own, day validity and no synthetic object is held by UBI's order engine rather than sent, until the other side of the book reaches its price. The answer then has an outcome of armed, a parent_id and no order_id, and the order is found in parents rather than in orders. Pass synthetic={"type": "simple"} to send a limit order at once, which an instrument with no live quote needs, because its held order would never be sent.
A plain market order that is not after-market is not sent as a market order either. The engine runs it as a marketable_limit, a limit two ticks past the other side's best price that follows that price until it fills and is cancelled after 30 seconds, and refuses it with HTTP 409 when nobody is on the other side of the book or the quote is missing or stale. synthetic={"type": "simple"} sends a real market order. Order engine explains it.
Parameters¶
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
transaction_type |
str |
yes | buy or sell. UBI overrides it for a quantity_reference that reduces or closes a position. |
|
order_type |
str |
yes | market, limit, sl or sl-m. |
|
quantity |
int or None |
yes | The quantity in units, not lots, or None when a quantity_reference supplies it. It has no default, so you have to write None on purpose. |
|
product |
str |
yes | cnc, mis or nrml. |
|
price |
float or None |
no | None |
The limit price in rupees. Leave it out for market and sl-m, or when a price_reference supplies it. |
trigger_price |
float or None |
no | None |
The trigger price in rupees, for sl and sl-m. |
validity |
str or None |
no | None |
day or ioc. UBI uses day when it is None. |
disclosed_quantity |
int or None |
no | None |
The part of the order to show on the exchange. None shows all of it. |
after_market |
bool |
no | False |
True sends an after-market order, which the broker queues for the next session. |
tag |
str or None |
no | None |
A label of up to twenty letters and digits. |
dry_run |
bool |
no | False |
True has UBI build the broker's request and return it without sending it. |
price_reference |
dict or None |
no | None |
A price for UBI to work out, such as {"kind": "offer_level", "level": 2}. The seven kinds are on Price wrappers. |
quantity_reference |
dict or None |
no | None |
A quantity for UBI to work out, such as {"kind": "liquidate_position", "product": "intraday"}. The kinds are on Positions. |
synthetic |
dict or None |
no | None |
A synthetic order type and its settings, such as {"type": "bracket", "stop_price": 990, "stop_limit_price": 988, "target_price": 1010}. The classes on Synthetic orders build it for you. |
Example¶
The first example below is a dry run of a plain limit buy of one RELIANCE share at 1000 rupees. The second asks UBI to price the order at the best offer instead of stating a price. Both outputs were captured from a local UBI on Saturday 2026-09-26, with the market closed, in two separate runs, the day before UBI began holding plain limit orders; the plain limit order's dry run may answer differently today. They are reformatted across lines, and the broker account identifier in actid and uid is replaced with XX000000.
from tradingmachine.assets import equities
reliance = equities.Equity("nse", "RELIANCE")
answer = reliance.place_order(
"buy",
"limit",
1,
"cnc",
price=1000,
dry_run=True,
)
print(answer)
answer = reliance.place_order(
"buy",
"limit",
1,
"cnc",
price_reference={
"kind": "offer_level",
"level": 1,
},
dry_run=True,
)
print(answer)
{'broker': 'shoonya',
'dry_run': True,
'instrument_id': '3f92570a-9924-5bf5-9f9d-e006cd9f4202',
'intent_id': '520360eee8e9494ab580e96e093d715c',
'request': {'form': {'actid': 'XX000000',
'amo': 'NO',
'dscqty': '0',
'exch': 'NSE',
'ordersource': 'API',
'prc': '1000',
'prctyp': 'LMT',
'prd': 'C',
'qty': '1',
'ret': 'DAY',
'trantype': 'B',
'trgprc': '0',
'tsym': 'RELIANCE-EQ',
'uid': 'XX000000'},
'method': 'POST',
'url': 'https://api.shoonya.com/NorenWClientAPI/PlaceOrder'},
'skipped': [],
'tag': None,
'timing_ms': {'preparation': 1.594}}
{'broker': 'stoxkart',
'dry_run': True,
'instrument_id': '3f92570a-9924-5bf5-9f9d-e006cd9f4202',
'intent_id': '584e0a7f6cb84dc18fe0e64da9f4db69',
'request': {'json': {'action': 'BUY',
'algo_id': '99999',
'disclose_quantity': '0',
'exchange': 'NSE',
'order_type': 'LIMIT',
'price': '1226.0',
'product_type': 'DELIVERY',
'quantity': '1',
'stop_loss_price': '0',
'token': '2885',
'trailing_stop_loss': '0',
'trigger_price': '0',
'validity': 'DAY'},
'method': 'POST',
'url': 'https://openapi.stoxkart.com/orders/normal'},
'skipped': [],
'tag': None,
'timing_ms': {'preparation': 1.98}}
The outputs show three things worth knowing:
- UBI chose a different broker for each request,
shoonyaand thenstoxkart, because its selector takes turns among the brokers that can take the order. - The lower-case
"buy","limit"and"cnc"reached each broker in that broker's own spelling:trantype: B,prctyp: LMTandprd: Cfor Shoonya, andDELIVERYfor Stoxkart. - The price reference was resolved to
1226.0, which was the one level on the offer side of the book in the quote captured the same afternoon.
Returns¶
A dict, which is UBI's answer unchanged. The table below lists its keys; which of them appear depends on whether the order was sent, was a dry run, or is held inside UBI's order engine.
| Key | Type | Description |
|---|---|---|
broker |
str or None |
The broker UBI chose. It is None for a held limit order or a synthetic order that is waiting for a price or a time. |
instrument_id |
str |
The instrument the order was for. |
order_id |
str or None |
The broker's id for the order, which modify_order and cancel_order take. It is None unless the outcome is accepted. |
outcome |
str |
accepted, rejected or unknown; partial for a type that sends several orders when only some were accepted, which UBI answers with HTTP 207 and the library returns rather than raises; or armed for an order the engine is holding. Absent on a dry run. |
status_message |
str or None |
Why the outcome is not accepted. |
broker_response |
dict, str or None |
The broker's own answer. |
dry_run |
bool |
True, on a dry run only. |
request |
dict |
On a dry run only: the method, the URL and the body the broker would have received. |
skipped |
list |
Each broker UBI passed over before the one it chose, with its reason. |
tag |
str or None |
The tag the order carried. |
timing_ms |
dict |
How long UBI spent preparing the order, and how long the broker took. |
intent_id |
str |
The id of the order's intent in UBI's order engine, on every answer. Account.intent reads the answer again by it. |
parent_id |
str |
Present for an order the engine recorded as a parent, including a held limit order. Keep it: it is the only handle on an order that has not reached a broker yet. |
legs |
list |
Present for the types that send several orders at once, such as freeze_slicer and ladder, one entry per order with its plan path, instrument_id, outcome, order_id and status_message. |
Raises¶
| Exception | When |
|---|---|
BadRequestError |
A field is invalid, the price fields do not fit the order type, or a synthetic order's own settings are wrong. |
LossLockoutError |
The day's loss is past UBI's daily loss limit. |
NotFoundError |
No broker has a mapping for this instrument today. |
ConflictError |
A quantity_reference asked to reduce or close a position that is not held, a market order run as a marketable limit found nobody on the other side of the book or no fresh quote, a reduce-only order would not reduce the position, or the engine read the order too late or had already started it before a restart. |
OrderRejectedError |
The broker refused the order. Its answer is in the exception's detail, not in its message. |
RateLimitError |
The broker's daily order cap has no room for this order. |
ServiceUnavailableError |
No broker could take the order, the order engine is not running, or a price_reference could not be resolved, for example because the book is empty. |
OrderOutcomeUnknownError |
The order was sent but its outcome is unknown. Read orders, or Account.intent with the intent_id in the exception's detail, before sending it again, or you may place it twice. |
UnifiedBrokerInterfaceError |
Any other failure reported by, or on the way to, UBI. |
Each of these is described, with what to do next, on the Errors page.
Under the hood
The method builds a JSON body from its arguments and sends it with the shared client's post. The six fields that are always present come first, and each optional field is added only when it is not None. For the price-reference example above, the body was:
{
"instrument_id": "3f92570a-9924-5bf5-9f9d-e006cd9f4202",
"transaction_type": "buy",
"order_type": "limit",
"product": "cnc",
"after_market": false,
"dry_run": true,
"quantity": 1,
"price_reference": {"kind": "offer_level", "level": 1}
}
Nothing else is sent: one call is one request. UBI's route is documented under Place an order.
modify_order¶
places orders modify_order(order_id=None, quantity=None, price=None, trigger_price=None, order_type=None, validity=None, disclosed_quantity=None, broker=None, dry_run=False, parent_id=None, part=None)PUT /api/orders/modify
This method changes one order that is still waiting in the market. Give at least one field to change; every field left as None keeps the value the order already has. UBI finds the order by its id in the brokers' order books, so the method does not check that the order belongs to the instrument you called it on.
UBI's order books are copies that its own collectors refresh every few seconds, so an order placed a moment ago is not in them yet, and changing it raises NotFoundError. In a live test on 2026-09-20 an order took 2.0 seconds to appear. Wait until the order shows up in orders before you change it.
An order that is a leg of one of UBI's synthetic orders is handed to the order engine, which lets the order type carry on from the change: a trailing stop trails from the trigger you set, and a chaser steps on from the price you set. Only such a leg's price, trigger_price and quantity can change, and anything else raises ConflictError.
An order the engine is still holding, such as a plain limit order waiting for the book to reach its price, has no broker order id yet. Name it by parent_id instead of order_id. Only its price and quantity can change, nothing is sent to a broker, and the order is later sent at the new terms.
Parameters¶
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
order_id |
str or None |
one of the two | None |
The id the broker gave the order, as place_order returned it. |
quantity |
int or None |
no | None |
The new total quantity in units, counting what has already filled. |
price |
float or None |
no | None |
The new limit price in rupees. |
trigger_price |
float or None |
no | None |
The new trigger price in rupees. |
order_type |
str or None |
no | None |
The new order type: market, limit, sl or sl-m. |
validity |
str or None |
no | None |
The new validity: day or ioc. |
disclosed_quantity |
int or None |
no | None |
The new quantity to show on the exchange. |
broker |
str or None |
no | None |
The broker holding the order. It is needed only after a ConflictError that says two brokers share the id. |
dry_run |
bool |
no | False |
True has UBI build the broker's request and return it without sending it. |
parent_id |
str or None |
one of the two | None |
The parent_id of an order the engine is still holding, or of the plan that holds part, as place_order returned it. |
part |
str or None |
no | None |
With parent_id, the path of a part of a plan order that has not been sent, such as root.each_fill.children.0 for a bracket's stop. Its price, trigger_price and quantity can change, and it keeps them until its turn comes. |
Example¶
The first example below changes a held limit order by its parent_id. The second sends a limit order to the broker at once, with the simple type, waits for it to appear and then lowers its price. No output was captured for either, because both would change a real order.
import time
answer = reliance.place_order(
"buy",
"limit",
1,
"cnc",
price=1000,
after_market=True,
synthetic={
"type": "simple",
},
)
order_id = answer["order_id"]
for attempt in range(30):
frame = reliance.open_orders
if frame is not None and order_id in set(frame["order_id"]):
break
time.sleep(2)
reliance.modify_order(order_id, price=995, broker=answer["broker"])
Returns¶
A dict with broker, order_id, instrument_id, status_before_modify, outcome, status_message, broker_response and timing_ms, plus parent_id and synthetic_type for a leg of a synthetic order. On a dry run it holds dry_run and the request UBI would have sent instead. A held order answers with parent_id, synthetic_type, held set to True, the new price and quantity, and an outcome of accepted.
Raises¶
| Exception | When |
|---|---|
BadRequestError |
No field was given to change, or a field is invalid or is one this broker cannot change. |
NotFoundError |
No broker's order book holds this order id, which is also what a very new order gives, or the engine holds no parent with this parent_id. |
ConflictError |
The order is already complete, cancelled, rejected or expired; two brokers hold the same id and the exception's detail lists them under brokers; a leg of a synthetic order was asked to change a field other than its price, trigger price or quantity; or a held order has already been sent, when the detail names its broker and order_id. |
OrderRejectedError |
The broker refused the change. |
ServiceUnavailableError |
The broker's order rate budget was full, so the change was not sent. It is worth retrying a moment later. |
OrderOutcomeUnknownError |
The change was sent but its outcome is unknown. |
UnifiedBrokerInterfaceError |
Any other failure reported by, or on the way to, UBI. |
Under the hood
The body holds dry_run, plus order_id or parent_id and each field that is not None, and it is sent with the shared client's put. UBI's route is documented under Modify an order.
cancel_order¶
places orders cancel_order(order_id, broker=None, dry_run=False)DELETE /api/orders/cancel
This method cancels one order that is still waiting in the market. Like modify_order, it finds the order by id across every broker's order book, does not check which instrument it belongs to, and cannot see an order placed in the last few seconds.
An order that is a leg of one of UBI's synthetic orders is cancelled through the order engine, so the order type knows about it, but the synthetic order itself carries on. cancel_parent stops a synthetic order, and it is also how an order the engine is still holding is cancelled, because such an order has no broker order id. Since 2026-10-05 a leg cancelled this way stays cancelled: a bracket's stop is not placed again, and the leg's unfilled quantity comes off what its part trades, so a later fill of the entry is protected for the smaller quantity only.
Parameters¶
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
order_id |
str |
yes | The id the broker gave the order. | |
broker |
str or None |
no | None |
The broker holding the order, needed only when two brokers share the id. |
dry_run |
bool |
no | False |
True has UBI build the broker's request and return it without sending it. |
Example¶
The example below cancels an order, naming the broker from the answer that placed it.
Returns¶
A dict with broker, order_id, status_before_cancel, outcome, status_message, broker_response and timing_ms, plus parent_id and synthetic_type for a leg of a synthetic order, or, on a dry run, dry_run and the request UBI would have sent.
Raises¶
| Exception | When |
|---|---|
BadRequestError |
The order id, the broker or the dry run flag is malformed. |
NotFoundError |
No broker's order book holds this order id. |
ConflictError |
The order is already complete, cancelled, rejected or expired, or two brokers hold the same id. |
OrderRejectedError |
The broker refused the cancellation. |
ServiceUnavailableError |
The broker's order rate budget was full, so the cancellation was not sent. |
OrderOutcomeUnknownError |
The cancellation was sent but its outcome is unknown. |
UnifiedBrokerInterfaceError |
Any other failure reported by, or on the way to, UBI. |
Under the hood
The body holds order_id, dry_run and, when given, broker, and it is sent with the shared client's delete. UBI's route is documented under Cancel an order.
cancel_open_orders¶
places orders cancel_open_orders()GET /api/orders/parents and /api/orders/details, then DELETE /api/orders/cancel with a parent_id per parent and one DELETE /api/orders/cancel for the rest
This method cancels every order in this instrument that is still waiting, whether it rests at a broker or is held in UBI's order engine. The numbered steps below are what it does.
- It reads this instrument's open
parentsand cancels each withcancel_parent. The parents go first, because a synthetic order left running could place a new order after its old ones had been cancelled. - It reads
open_ordersand leaves out every order whoseengine_parent_idis a parent the engine took a cancel for, because the engine has already dealt with it. An order whose parent's cancel failed is kept, so it is still cancelled. - It cancels every remaining order in one request, naming the broker from each order's row, using the list form of UBI's cancel route.
Every parent and order is attempted even when an earlier one fails, and a failure is reported in the returned frame rather than raised, so one order that can no longer be cancelled does not leave the rest open. A parent whose cancel a broker refused for one leg is reported as not cancelled, because that leg may still be live.
It has no dry_run argument. To see what it would cancel, read parents and open_orders yourself first.
Parameters¶
The method takes no parameters.
Example¶
The output below is built from the code rather than captured, because running the method cancels real orders. It shows a held limit order cancelled through its parent, one broker order cancelled, and one that had filled a moment before; the ids are invented, and the error text is UBI's HTTP 409 message for an order that is already finished.
Returns¶
A pandas.DataFrame with one row per parent and per order, or None when nothing in this instrument is waiting.
| Column | Type | Description |
|---|---|---|
parent_id |
str or None |
The parent cancelled, or None for an order cancelled on its own. |
order_id |
str or None |
The broker's id for the order, or None for a parent. |
broker |
str or None |
The broker holding the order, or None for a parent. |
cancelled |
bool |
Whether the cancellation was accepted. |
error |
str or None |
Why it was not: the exception's class name and message for a parent, or the HTTP status and UBI's message for an order. None when it was. |
Raises¶
| Exception | When |
|---|---|
BrokerError |
No broker's order book could be read. |
ServiceUnavailableError |
UBI's order book document is missing or too old to serve, or UBI's parents could not be read. |
UnifiedBrokerInterfaceError |
The order book or the parents could not be read for any other reason, or UBI refused the list of cancels as a whole. A failure to cancel one order or parent is reported in the frame instead. |
Reading the order book¶
UBI serves the whole account's order book and trade book, across every broker, and has no route for one instrument. So each property below reads the whole book, one request per access, and keeps the rows whose instrument_id matches this instrument. The book is not merged across brokers: one order at one broker is one row, and the same instrument traded at two brokers gives a row from each. A row whose instrument_id UBI could not work out is invisible here, because there is no other field that names the instrument reliably.
The table below shows which statuses each property keeps. An order still waiting in the market is PENDING at some brokers and OPEN at others, which is why open_orders takes both.
| Property | Statuses kept |
|---|---|
orders |
all six |
open_orders |
PENDING, OPEN |
completed_orders |
COMPLETE |
rejected_orders |
REJECTED |
cancelled_orders |
CANCELLED |
A status with no property of its own, such as EXPIRED, is found by filtering the status column of orders. An order UBI's order engine is still holding has not reached a broker, so it is in none of these frames; it is in parents. Every property returns None, not an empty frame, when no row matches, and each access sends a new request, so bind the frame to a variable when you need it twice.
orders¶
property ordersGET /api/orders/details
This property gives every one of today's orders in this instrument, whatever its status.
Example¶
The output below was captured from a local UBI on 2026-09-26. The account had placed no RELIANCE order that day, so the property returned None.
Returns¶
A pandas.DataFrame with UBI's order fields, or None when this instrument has no orders today. The table lists the columns the library's docstring names; UBI's order book page lists every field.
| Column | Type | Description |
|---|---|---|
broker |
str |
The broker holding the order. |
order_id |
str |
The broker's id for the order. |
status |
str |
PENDING, OPEN, COMPLETE, CANCELLED, REJECTED or EXPIRED. |
status_message |
str or None |
Why an order was rejected, in the words of whoever refused it. |
transaction_type |
str |
BUY or SELL. |
product |
str |
CNC, MIS or NRML. |
order_type |
str |
MARKET, LIMIT, SL or SL-M. |
quantity |
number | The order's quantity in units. |
filled_quantity |
number | How much has filled. |
price |
number | The limit price. |
trigger_price |
number | The trigger price. |
average_price |
number | The average fill price. |
order_timestamp |
str |
When the order was placed. |
engine_parent_id |
str or None |
The order engine parent that placed the order, or None for an order placed elsewhere. |
leg_role |
str or None |
The order's role in that parent, such as entry, stop, target or slice. |
synthetic_type |
str or None |
The parent's order type, such as bracket or virtual_limit. |
intent_id |
str or None |
The intent the parent was placed for, as the place answer named it. |
A column that is null in every row comes back from pandas as NaN rather than None.
Raises¶
| Exception | When |
|---|---|
BrokerError |
No broker's order book could be read. |
ServiceUnavailableError |
UBI's order book document is missing or too old to serve. This means UBI's own background writer stopped, not that a broker is down. |
UnifiedBrokerInterfaceError |
Any other failure reported by, or on the way to, UBI. |
open_orders¶
property open_ordersGET /api/orders/details
This property gives today's orders in this instrument that are still waiting in the market, which are the only ones modify_order and cancel_order will accept. It returns a frame shaped like orders, or None, and raises the same exceptions.
completed_orders¶
property completed_ordersGET /api/orders/details
This property gives today's orders in this instrument that filled in full. It returns a frame shaped like orders, or None, and raises the same exceptions.
rejected_orders¶
property rejected_ordersGET /api/orders/details
This property gives today's orders in this instrument that a broker or the exchange refused. The status_message column holds the reason, which is the first place to look after an accepted order that never filled. It returns a frame shaped like orders, or None, and raises the same exceptions.
cancelled_orders¶
property cancelled_ordersGET /api/orders/details
This property gives today's orders in this instrument that were cancelled. It returns a frame shaped like orders, or None, and raises the same exceptions.
trades¶
property tradesGET /api/orders/trades
This property gives today's trades in this instrument. One order can fill in several trades, and each trade names the order it came from, so trades is where to look for the prices an order actually filled at.
Returns¶
A pandas.DataFrame with UBI's trade fields, or None when this instrument has no trades today. The columns the library's docstring names are listed below; UBI's trade book page lists every field.
| Column | Type | Description |
|---|---|---|
broker |
str |
The broker the trade happened at. |
trade_id |
str |
The id of the trade. |
order_id |
str |
The order the trade filled. |
transaction_type |
str |
BUY or SELL. |
product |
str |
CNC, MIS or NRML. |
quantity |
number | The quantity traded. |
price |
number | The price it traded at. |
value |
number | The quantity times the price. |
trade_timestamp |
str |
When it traded. |
engine_parent_id, leg_role, synthetic_type, intent_id |
str or None |
The order engine parent the trade's order belongs to, as for an order, or None for an order placed elsewhere. |
Raises¶
| Exception | When |
|---|---|
BrokerError |
No broker's trade book could be read. |
ServiceUnavailableError |
UBI's trade book document is missing or too old to serve. |
UnifiedBrokerInterfaceError |
Any other failure reported by, or on the way to, UBI. |
Reading the order engine's parents¶
A parent is one order the order engine was asked for, such as a bracket, a trailing stop or a held limit order, and its legs are the broker orders it placed. Every answer from the engine for such an order carries a parent_id, which the members below take. The classes on Synthetic orders keep their own parent_id and call these members for you.
cancel_parent¶
places orders cancel_parent(parent_id, part=None, dry_run=False)DELETE /api/orders/cancel
This method cancels one parent, with every leg it still has resting at a broker, so the parent places, moves and cancels nothing more. It is how a synthetic order is stopped and how a held limit order is cancelled. A position the parent has already opened is not closed.
When a broker refuses the cancel of one leg, or its outcome is unknown, UBI answers HTTP 207, which the library returns rather than raises, and the parent's state is cancelling rather than cancelled. The parent no longer acts, and becomes cancelled on its own once the broker reports that leg finished. Read cancelled_legs to see which leg may still be live, and call the method again to retry it.
Parameters¶
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
parent_id |
str |
yes | The parent_id that place_order answered with. |
|
part |
str or None |
no | None |
The path of one part of a plan order to cancel, such as root.each_fill.children.0, as the parent's parameters.parts lists it. The rest of the plan carries on. None cancels the whole parent. |
dry_run |
bool |
no | False |
True has UBI say what would be cancelled, without cancelling anything. |
Example¶
The example below places a held limit order and cancels it again. No output was captured for it, because it places and cancels a real order.
Returns¶
A dict with parent_id, synthetic_type, state, intent_id and cancelled_legs, which holds one entry per leg with its leg_id, broker, order_id, outcome and status_message. A part answers instead with parent_id, synthetic_type, part, its state, outcome, status_message, intent_id and orders, where each order's cancel_accepted says whether its broker accepted the cancel.
Raises¶
| Exception | When |
|---|---|
BadRequestError |
The parent id is malformed. |
NotFoundError |
The order engine holds no parent with this id, or the plan has no part at this path. |
ConflictError |
The parent or part has already finished, the part is kept whole and has not started, or the parent is not a plan and was given a part. |
ServiceUnavailableError |
The order engine is not running. |
OrderOutcomeUnknownError |
The engine did not answer in time. |
UnifiedBrokerInterfaceError |
Any other failure reported by, or on the way to, UBI. |
parents¶
property parentsGET /api/orders/parents
This property gives this instrument's parents that the order engine has not finished. It is the only way to see a parent that has placed nothing yet, such as a held limit order or an armed trigger. UBI lists every open parent in the account, so the property reads them all and keeps this instrument's; Account.parents gives the whole list.
Returns¶
A pandas.DataFrame with one row per parent, or None when no parent in this instrument is open. The table lists its main columns.
| Column | Type | Description |
|---|---|---|
parent_order_id |
str |
The parent's id, which is the parent_id the other members take. |
synthetic_type |
str |
plan for every type but simple, since UBI runs every other type as a plan of its preset; the type asked for is under parameters as routed_from. |
state |
str |
received, working or cancelling; a parent placed before 2026-10-03 can also show protecting. The finished states, completed, cancelled, rejected and failed, do not appear here. |
instrument_id |
str |
This instrument. |
body |
dict |
The order body the parent was placed with. |
parameters |
dict |
The type's settings, including the engine's own working values. |
legs |
list |
One entry per broker order the parent placed. |
Raises¶
| Exception | When |
|---|---|
ServiceUnavailableError |
UBI's parents could not be read. |
UnifiedBrokerInterfaceError |
Any other failure reported by, or on the way to, UBI. |
parent¶
method parent(parent_id)GET /api/orders/parents?parent_id=...
This method reads one parent, whether or not it has finished. UBI finds it by id alone, so the method does not check that it belongs to this instrument. It returns a dict with the same fields as a row of parents, and raises NotFoundError when the engine holds no parent with this id.
parent_orders¶
method parent_orders(parent_id)GET /api/orders/details?parent_id=...
This method gives today's broker orders that one parent placed, using the order book's parent_id filter. It returns a frame shaped like orders, whose leg_role column says what each order was to the parent, or None when the parent has placed nothing the order book shows yet. It raises the same exceptions as orders.
parent_trades¶
method parent_trades(parent_id)GET /api/orders/trades?parent_id=...
This method gives today's trades in the broker orders that one parent placed. It returns a frame shaped like trades, or None when none of the parent's orders has traded, and raises the same exceptions as trades.