Skip to content

trading_agent.terminal.formatter

Formats money, numbers, durations and times the way the web page does.

Money uses Indian digit grouping and the rupee sign, and times are India clock times.

Typical usage example:

formatter = Formatter() formatter.money(123456.7) # '₹1,23,456.70' formatter.elapsed_text(137) # '2m 17s'

Formatter

Turns numbers and moments into short text for the terminal.

grouped

grouped(value, decimals=2)

Writes a number with Indian digit grouping.

Parameters:

Name Type Description Default
value float

The number.

required
decimals int

How many digits to keep after the point.

2

Returns:

Type Description
str

Such as "1,23,456.70" for 123456.7, with a leading "-" when negative.

Source code in src/trading_agent/terminal/formatter.py
def grouped(self, value: float, decimals: int = 2) -> str:
    """Writes a number with Indian digit grouping.

    Args:
        value (float): The number.
        decimals (int): How many digits to keep after the point.

    Returns:
        str: Such as "1,23,456.70" for 123456.7, with a leading "-" when negative.
    """
    sign = ''
    if value < 0:
        sign = '-'
        value = -value
    fixed = f'{value:.{decimals}f}'
    whole = fixed
    fraction = ''
    if decimals > 0:
        whole, fraction = fixed.split('.')
        fraction = '.' + fraction
    if len(whole) > 3:
        head = whole[:-3]
        tail = whole[-3:]
        groups = []
        while len(head) > 2:
            groups.insert(0, head[-2:])
            head = head[:-2]
        if head:
            groups.insert(0, head)
        whole = ','.join(groups) + ',' + tail
    return f'{sign}{whole}{fraction}'

money

money(amount)

Formats an amount of money.

Parameters:

Name Type Description Default
amount float | None

The amount in rupees, or None.

required

Returns:

Type Description
str

Such as "₹1,23,456.70", or "—" when missing.

Source code in src/trading_agent/terminal/formatter.py
def money(self, amount: float | None) -> str:
    """Formats an amount of money.

    Args:
        amount (float | None): The amount in rupees, or None.

    Returns:
        str: Such as "₹1,23,456.70", or "—" when missing.
    """
    if amount is None:
        return _MISSING
    if amount < 0:
        return f'-₹{self.grouped(-amount)}'
    return f'₹{self.grouped(amount)}'

signed_money

signed_money(amount)

Formats a profit or loss with its sign.

Parameters:

Name Type Description Default
amount float | None

The amount in rupees, or None.

required

Returns:

Type Description
str

Such as "+₹1,250.00" or "−₹300.00", or "—" when missing.

Source code in src/trading_agent/terminal/formatter.py
def signed_money(self, amount: float | None) -> str:
    """Formats a profit or loss with its sign.

    Args:
        amount (float | None): The amount in rupees, or None.

    Returns:
        str: Such as "+₹1,250.00" or "−₹300.00", or "—" when missing.
    """
    if amount is None:
        return _MISSING
    if amount > 0:
        return f'+₹{self.grouped(amount)}'
    if amount < 0:
        return f'{_MINUS}₹{self.grouped(-amount)}'
    return f'₹{self.grouped(0)}'

price_text

price_text(value)

Formats a price.

Parameters:

Name Type Description Default
value float | None

The price, or None.

required

Returns:

Type Description
str

Such as "2,945.50", or "—" when missing.

Source code in src/trading_agent/terminal/formatter.py
def price_text(self, value: float | None) -> str:
    """Formats a price.

    Args:
        value (float | None): The price, or None.

    Returns:
        str: Such as "2,945.50", or "—" when missing.
    """
    if value is None:
        return _MISSING
    return self.grouped(value)

number

number(value)

Formats a whole number from an event payload.

Parameters:

Name Type Description Default
value object

The value, which may be missing or not a number.

required

Returns:

Type Description
str

Such as "12,345", or "?" when the value is not a number.

Source code in src/trading_agent/terminal/formatter.py
def number(self, value: object) -> str:
    """Formats a whole number from an event payload.

    Args:
        value (object): The value, which may be missing or not a number.

    Returns:
        str: Such as "12,345", or "?" when the value is not a number.
    """
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        return '?'
    if isinstance(value, float) and not value.is_integer():
        return self.grouped(value, 1)
    return self.grouped(value, 0)

moment

moment(iso_text)

Reads an ISO timestamp from the gateway.

Parameters:

Name Type Description Default
iso_text str

Such as "2026-10-19T04:30:00+00:00".

required

Returns:

Type Description
datetime | None

The moment in India time, or None when the text is not a timestamp.

Source code in src/trading_agent/terminal/formatter.py
def moment(self, iso_text: str) -> datetime.datetime | None:
    """Reads an ISO timestamp from the gateway.

    Args:
        iso_text (str): Such as "2026-10-19T04:30:00+00:00".

    Returns:
        datetime.datetime | None: The moment in India time, or None when the text is not a timestamp.
    """
    try:
        moment = datetime.datetime.fromisoformat(iso_text)
    except ValueError:
        return None
    if moment.tzinfo is None:
        moment = moment.replace(tzinfo=datetime.UTC)
    return moment.astimezone(_INDIA)

time

time(iso_text)

Formats a moment as an India clock time.

Parameters:

Name Type Description Default
iso_text str

An ISO timestamp.

required

Returns:

Type Description
str

Such as "10:04:31", or the text itself when it is not a timestamp.

Source code in src/trading_agent/terminal/formatter.py
def time(self, iso_text: str) -> str:
    """Formats a moment as an India clock time.

    Args:
        iso_text (str): An ISO timestamp.

    Returns:
        str: Such as "10:04:31", or the text itself when it is not a timestamp.
    """
    moment = self.moment(iso_text)
    if moment is None:
        return iso_text
    return moment.strftime('%H:%M:%S')

day_time

day_time(iso_text)

Formats a moment as a day and an India clock time.

Parameters:

Name Type Description Default
iso_text str

An ISO timestamp.

required

Returns:

Type Description
str

Such as "19 Oct, 10:04", or the text itself when it is not a timestamp.

Source code in src/trading_agent/terminal/formatter.py
def day_time(self, iso_text: str) -> str:
    """Formats a moment as a day and an India clock time.

    Args:
        iso_text (str): An ISO timestamp.

    Returns:
        str: Such as "19 Oct, 10:04", or the text itself when it is not a timestamp.
    """
    moment = self.moment(iso_text)
    if moment is None:
        return iso_text
    return f'{moment.day} {moment.strftime("%b, %H:%M")}'

file_size

file_size(size_bytes)

Formats a file size.

Parameters:

Name Type Description Default
size_bytes int

The size in bytes.

required

Returns:

Type Description
str

Such as "340 KB" or "2.4 MB".

Source code in src/trading_agent/terminal/formatter.py
def file_size(self, size_bytes: int) -> str:
    """Formats a file size.

    Args:
        size_bytes (int): The size in bytes.

    Returns:
        str: Such as "340 KB" or "2.4 MB".
    """
    if size_bytes < 1024 * 1024:
        return f'{max(1, round(size_bytes / 1024))} KB'
    return f'{size_bytes / (1024 * 1024):.1f} MB'

token_count

token_count(tokens)

Formats a token count.

Parameters:

Name Type Description Default
tokens float

The count.

required

Returns:

Type Description
str

Such as "850", "12.3k" or "1M".

Source code in src/trading_agent/terminal/formatter.py
def token_count(self, tokens: float) -> str:
    """Formats a token count.

    Args:
        tokens (float): The count.

    Returns:
        str: Such as "850", "12.3k" or "1M".
    """
    if tokens < 1000:
        return str(round(tokens))
    if tokens < 1000000:
        return f'{self._one_decimal(tokens / 1000)}k'
    return f'{self._one_decimal(tokens / 1000000)}M'

share

share(part, whole)

Formats a part of a whole as a percentage.

Parameters:

Name Type Description Default
part float

The part.

required
whole float

The whole.

required

Returns:

Type Description
str

Such as "34.2%", or "—" when the whole is not positive.

Source code in src/trading_agent/terminal/formatter.py
def share(self, part: float, whole: float) -> str:
    """Formats a part of a whole as a percentage.

    Args:
        part (float): The part.
        whole (float): The whole.

    Returns:
        str: Such as "34.2%", or "—" when the whole is not positive.
    """
    if whole <= 0:
        return _MISSING
    return f'{100 * part / whole:.1f}%'

elapsed_text

elapsed_text(seconds)

Formats a duration the way Claude Code shows it.

Parameters:

Name Type Description Default
seconds int

The duration in seconds.

required

Returns:

Type Description
str

Such as "12s" or "2m 17s".

Source code in src/trading_agent/terminal/formatter.py
def elapsed_text(self, seconds: int) -> str:
    """Formats a duration the way Claude Code shows it.

    Args:
        seconds (int): The duration in seconds.

    Returns:
        str: Such as "12s" or "2m 17s".
    """
    if seconds < 60:
        return f'{seconds}s'
    return f'{seconds // 60}m {seconds % 60}s'