Skip to content

trading_agent.terminal.screens.desks_screen

The Desks page: every desk's state, profit and models, with pause, resume, flatten and a way into its chat.

It copies the web page's DesksPage.tsx. Enter on a desk opens its chat. Flatten runs the desk's own flatten_desk tool through the gateway, so it goes through the risk engine and the journal, and it asks for a reason first.

Typical usage example:

app.push_screen(DesksScreen('general'))

DesksScreen

DesksScreen(desk_name)

Bases: PageScreen

The Desks page.

Creates the page.

Parameters:

Name Type Description Default
desk_name str

The desk the chat shows.

required
Source code in src/trading_agent/terminal/screens/desks_screen.py
def __init__(self, desk_name: str):
    """Creates the page.

    Args:
        desk_name (str): The desk the chat shows.
    """
    super().__init__(desk_name)
    self._formatter = formatter.Formatter()
    self._desks: list[dict[str, Any]] = []

compose_page

compose_page()

Builds the summary line and the desks table.

Yields:

Type Description
Widget

The summary and the table.

Source code in src/trading_agent/terminal/screens/desks_screen.py
def compose_page(self):
    """Builds the summary line and the desks table.

    Yields:
        Widget: The summary and the table.
    """
    yield widgets.Static('', id='desks-summary', classes='page-summary')
    yield widgets.DataTable(id='desks', cursor_type='row')
    yield widgets.Static('', id='desks-detail', classes='page-detail')

on_mount

on_mount()

Sets up the table's columns, then reads the data.

Source code in src/trading_agent/terminal/screens/desks_screen.py
def on_mount(self) -> None:
    """Sets up the table's columns, then reads the data."""
    self.table('desks').add_columns(
        'Desk',
        'State',
        'Waiting',
        'Today',
        'Model order',
        'Session',
    )
    super().on_mount()

refresh_page async

refresh_page()

Reads the desks and the account.

Source code in src/trading_agent/terminal/screens/desks_screen.py
@work(exclusive=True, group='page')
async def refresh_page(self) -> None:
    """Reads the desks and the account."""
    gateway = self.app.gateway
    try:
        document = await gateway.desks()
        account = await gateway.account()
    except gateway_client.GatewayError as error:
        self.problem(error.message)
        return
    self._desks = document.get('desks', [])
    positions = len(account.get('positions') or [])
    self.query_one('#desks-summary', widgets.Static).update(
        Content.from_markup(
            'Balance [b]$balance[/b]   Today $today   This week $week   Open positions [b]$positions[/b]   [dim]$mode[/dim]',
            balance=self._formatter.money(account.get('total_balance')),
            today=self._formatter.signed_money(account.get('day_pnl')),
            week=self._formatter.signed_money(account.get('week_pnl')),
            positions=str(positions),
            mode='LIVE ORDERS'
            if document.get('mode') == 'live'
            else 'DRY RUN',
        )
    )
    table = self.table('desks')
    cursor = table.cursor_row
    table.clear()
    halts = account.get('halts') or []
    desk_pnl = account.get('desk_pnl') or {}
    for desk in self._desks:
        name = desk.get('name', '')
        state = str(desk.get('state', ''))
        if desk.get('paused'):
            state += ', paused'
        for halt in halts:
            if halt.get('scope') == name:
                state += ', halted'
        first_models = []
        for line in (desk.get('models') or [])[:2]:
            first_models.append(str(line))
        table.add_row(
            name,
            state,
            str(desk.get('queued', 0)),
            self._formatter.signed_money(desk_pnl.get(name, 0.0)),
            '; '.join(first_models),
            f'{desk.get("session_id") or "—"} ({desk.get("exchanges", 0)})',
            key=name,
        )
    if cursor is not None and cursor < table.row_count:
        table.move_cursor(row=cursor)

on_data_table_row_selected

on_data_table_row_selected(event)

Opens the chat with the desk chosen with Enter.

Parameters:

Name Type Description Default
event RowSelected

The choice.

required
Source code in src/trading_agent/terminal/screens/desks_screen.py
def on_data_table_row_selected(
    self, event: widgets.DataTable.RowSelected
) -> None:
    """Opens the chat with the desk chosen with Enter.

    Args:
        event (widgets.DataTable.RowSelected): The choice.
    """
    event.stop()
    self._open_chat(event.row_key.value)

action_pause_or_resume

action_pause_or_resume()

Pauses the highlighted desk, or resumes it when paused.

Source code in src/trading_agent/terminal/screens/desks_screen.py
def action_pause_or_resume(self) -> None:
    """Pauses the highlighted desk, or resumes it when paused."""
    name = self.selected_key('desks')
    if name is not None:
        self._pause_or_resume(name)

action_flatten

action_flatten()

Asks for a reason, then flattens the highlighted desk.

Source code in src/trading_agent/terminal/screens/desks_screen.py
def action_flatten(self) -> None:
    """Asks for a reason, then flattens the highlighted desk."""
    name = self.selected_key('desks')
    if name is None:
        return

    def flatten(reason: str | None) -> None:
        """Flattens once a reason is given.

        Args:
            reason (str | None): The reason, or None when cancelled.
        """
        if reason is not None:
            self._flatten(name, reason)

    self.app.push_screen(
        confirm_dialog.ConfirmDialog(
            f'Flatten {name}',
            f"Cancel {name}'s open orders and close its positions, through the risk engine. Other desks and your own holdings are not touched.",
            'Flatten',
        ),
        flatten,
    )