Skip to content

trading_agent.trading.desk_order_book

The record of which desk placed which order, in a small SQLite database shared by every desk.

A desk may change or cancel only the orders it placed itself, and this record is how the order tools know which those are. Each order is kept under its parent_id, the handle UBI's order engine gives every order, and also under its broker order_id once a broker has accepted it. A dry run reaches no broker and gets no id from UBI, so it is kept under a made-up id that starts with "dry-", which lets a desk practise changing and cancelling it.

Typical usage example:

book = DeskOrderBook(Path('workspace/shared/desk_orders.db')) record = book.find('main', parent_id='...', order_id=None)

OPEN module-attribute

OPEN = 'open'

CANCELLED module-attribute

CANCELLED = 'cancelled'

OrderRecord dataclass

OrderRecord(record_id, desk, kind, parent_id, order_id, instrument_id, exchange, segment, symbol, transaction_type, quantity, product, price, dry_run, state, placed_at)

One order a desk placed.

Attributes:

Name Type Description
record_id str

The key of the record: the parent_id, the order_id, or a made-up "dry-" id for a dry run.

desk str

The desk that placed it.

kind str

"order" for a plain order, "bracket" for a bracket order, or "close" for a closing order.

parent_id str | None

The handle UBI's order engine gave it, or the made-up id for a dry run, or None.

order_id str | None

The broker's id, or None until a broker has accepted it.

instrument_id str

UBI's id for the instrument.

exchange str

The exchange, such as nse.

segment str

UBI's segment, such as nse_equities.

symbol str

The symbol, or the underlying's for a future or option.

transaction_type str

"buy" or "sell".

quantity int

How many units.

product str

"cnc", "mis" or "nrml".

price float

The price the order was valued at.

dry_run bool

Whether it was a dry run that reached no broker.

state str

"open", or "cancelled" once a desk cancelled it.

placed_at str

When it was placed, as ISO text.

DeskOrderBook

DeskOrderBook(path)

The table of orders placed by the desks, and the questions the order tools ask of it.

Opens the database, creating it and its table if needed.

Parameters:

Name Type Description Default
path Path

The database file.

required
Source code in src/trading_agent/trading/desk_order_book.py
def __init__(self, path: Path):
    """Opens the database, creating it and its table if needed.

    Args:
        path (Path): The database file.
    """
    path.parent.mkdir(parents=True, exist_ok=True)
    self._connection = sqlite3.connect(str(path), check_same_thread=False)
    self._lock = threading.Lock()
    with self._lock, self._connection:
        self._connection.execute(_SCHEMA)

add

add(record)

Stores a newly placed order.

Parameters:

Name Type Description Default
record OrderRecord

The order.

required
Source code in src/trading_agent/trading/desk_order_book.py
def add(self, record: OrderRecord) -> None:
    """Stores a newly placed order.

    Args:
        record (OrderRecord): The order.
    """
    with self._lock, self._connection:
        self._connection.execute(
            f'INSERT OR REPLACE INTO desk_orders ({_COLUMNS}) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
            (
                record.record_id,
                record.desk,
                record.kind,
                record.parent_id,
                record.order_id,
                record.instrument_id,
                record.exchange,
                record.segment,
                record.symbol,
                record.transaction_type,
                record.quantity,
                record.product,
                record.price,
                int(record.dry_run),
                record.state,
                record.placed_at,
            ),
        )

find

find(desk, parent_id, order_id)

Finds one of a desk's orders by its parent_id or its order_id.

Parameters:

Name Type Description Default
desk str

The desk asking; another desk's order is never found.

required
parent_id str | None

The engine's handle, or None.

required
order_id str | None

The broker's id, or None.

required

Returns:

Type Description
OrderRecord | None

The order, or None when this desk placed no such order.

Source code in src/trading_agent/trading/desk_order_book.py
def find(
    self,
    desk: str,
    parent_id: str | None,
    order_id: str | None,
) -> OrderRecord | None:
    """Finds one of a desk's orders by its parent_id or its order_id.

    Args:
        desk (str): The desk asking; another desk's order is never found.
        parent_id (str | None): The engine's handle, or None.
        order_id (str | None): The broker's id, or None.

    Returns:
        OrderRecord | None: The order, or None when this desk placed no such order.
    """
    with self._lock:
        row = self._connection.execute(
            f'SELECT {_COLUMNS} FROM desk_orders WHERE desk = ? AND ((parent_id IS NOT NULL AND parent_id = ?) OR (order_id IS NOT NULL AND order_id = ?))',
            (desk, parent_id, order_id),
        ).fetchone()
    if row is None:
        return None
    return self._record(row)

open_orders

open_orders(desk)

A desk's orders that it has not cancelled.

Parameters:

Name Type Description Default
desk str

The desk.

required

Returns:

Type Description
list[OrderRecord]

The orders, oldest first.

Source code in src/trading_agent/trading/desk_order_book.py
def open_orders(self, desk: str) -> list[OrderRecord]:
    """A desk's orders that it has not cancelled.

    Args:
        desk (str): The desk.

    Returns:
        list[OrderRecord]: The orders, oldest first.
    """
    with self._lock:
        rows = self._connection.execute(
            f'SELECT {_COLUMNS} FROM desk_orders WHERE desk = ? AND state = ? ORDER BY placed_at',
            (desk, OPEN),
        ).fetchall()
    records = []
    for row in rows:
        records.append(self._record(row))
    return records

change

change(record_id, quantity, price)

Records a new quantity and price after an order was modified.

Parameters:

Name Type Description Default
record_id str

The order's record id.

required
quantity int

Its new quantity.

required
price float

Its new valuation price.

required
Source code in src/trading_agent/trading/desk_order_book.py
def change(self, record_id: str, quantity: int, price: float) -> None:
    """Records a new quantity and price after an order was modified.

    Args:
        record_id (str): The order's record id.
        quantity (int): Its new quantity.
        price (float): Its new valuation price.
    """
    with self._lock, self._connection:
        self._connection.execute(
            'UPDATE desk_orders SET quantity = ?, price = ? WHERE record_id = ?',
            (quantity, price, record_id),
        )

mark_cancelled

mark_cancelled(record_id)

Records that an order was cancelled.

Parameters:

Name Type Description Default
record_id str

The order's record id.

required
Source code in src/trading_agent/trading/desk_order_book.py
def mark_cancelled(self, record_id: str) -> None:
    """Records that an order was cancelled.

    Args:
        record_id (str): The order's record id.
    """
    with self._lock, self._connection:
        self._connection.execute(
            'UPDATE desk_orders SET state = ? WHERE record_id = ?',
            (CANCELLED, record_id),
        )

close

close()

Closes the database.

Source code in src/trading_agent/trading/desk_order_book.py
def close(self) -> None:
    """Closes the database."""
    with self._lock:
        self._connection.close()

now_text staticmethod

now_text()

The current time in UTC as ISO text, for placed_at.

Returns:

Type Description
str

The time.

Source code in src/trading_agent/trading/desk_order_book.py
@staticmethod
def now_text() -> str:
    """The current time in UTC as ISO text, for placed_at.

    Returns:
        str: The time.
    """
    return datetime.datetime.now(datetime.UTC).isoformat()