Skip to content

tradingmachine.orders.plan_parts.peg_pricing

The peg pricing rule of a plan: a limit kept at a named place in the book and moved there as the book moves.

The reference is own_touch, the best price on the order's own side, so a buy sits on the bid; mid, halfway between the bid and the offer; or opposite_touch, the other side's best price, where the order fills at once. A positive offset_ticks moves the order away from filling and a negative one towards it. Every move passes UBI's repricing throttle, and a move that changes nothing is not sent. When the book gives no price as the order is sent, because nobody is on the side the reference reads, no live quote has arrived or the quote is marked stale, on_empty_book decides what happens: wait, UBI's default, keeps the order waiting for a tick that does, and refuse ends it refused, which a plan with nothing else placed answers with HTTP 409 and sends nothing.

Typical usage example:

pricing = peg_pricing.PegPricing(reference="own_touch", offset_ticks=1) document = pricing.document()

PegPricing

PegPricing(*, reference=None, offset_ticks=None, follows=None, within_body_price=False, on_empty_book=None)

Bases: PlanPart

A pricing rule that keeps a limit at its reference in the book.

Attributes:

Name Type Description
reference

The str place in the book, own_touch, mid or opposite_touch, or None for UBI's default of own_touch.

offset_ticks

The int number of ticks away from the reference, positive away from filling and negative towards it, or None for UBI's default of 0.

follows

A bool that is False to price the order at its reference once when it is sent and leave it there, or None for UBI's default of True.

within_body_price

A bool that is True to treat the template's limit price as the worst price the order takes.

on_empty_book

The str wait or refuse, what to do when the book gives no price as the order is sent, or None for UBI's default of wait.

Initialises the rule with its reference and settings.

Parameters:

Name Type Description Default
reference str | None

The str place in the book, own_touch for the order's own side, mid for halfway between the bid and the offer, or opposite_touch for the other side, or None for UBI's default of own_touch.

None
offset_ticks int | None

The int number of ticks away from the reference, positive away from filling and negative towards it, or None for UBI's default of 0.

None
follows bool | None

A bool that is False to price the order at its reference once and leave it there, True to move it whenever the reference moves, or None for UBI's default of True.

None
within_body_price bool

A bool that is True to treat the template's limit price as the worst price the order takes, resting at that price when the book shows no reference. UBI refuses that price with HTTP 400 when it is not a whole number of ticks.

False
on_empty_book str | None

The str wait to keep the order waiting for a tick that carries its reference when the book gives no price as it is sent, or refuse to end it refused, which a plan with nothing else placed answers with HTTP 409, or None for UBI's default of wait.

None
Source code in src/tradingmachine/orders/plan_parts/peg_pricing.py
def __init__(
    self,
    *,
    reference: str | None = None,
    offset_ticks: int | None = None,
    follows: bool | None = None,
    within_body_price: bool = False,
    on_empty_book: str | None = None,
):
    """Initialises the rule with its reference and settings.

    Args:
        reference: The str place in the book, `own_touch` for the order's own side, `mid` for halfway between the bid and the offer, or `opposite_touch` for the other side, or None for UBI's default of `own_touch`.
        offset_ticks: The int number of ticks away from the reference, positive away from filling and negative towards it, or None for UBI's default of 0.
        follows: A bool that is False to price the order at its reference once and leave it there, True to move it whenever the reference moves, or None for UBI's default of True.
        within_body_price: A bool that is True to treat the template's limit price as the worst price the order takes, resting at that price when the book shows no reference. UBI refuses that price with HTTP 400 when it is not a whole number of ticks.
        on_empty_book: The str `wait` to keep the order waiting for a tick that carries its reference when the book gives no price as it is sent, or `refuse` to end it refused, which a plan with nothing else placed answers with HTTP 409, or None for UBI's default of `wait`.

    Raises:
        Nothing.
    """
    self.reference = reference
    self.offset_ticks = offset_ticks
    self.follows = follows
    self.within_body_price = within_body_price
    self.on_empty_book = on_empty_book

document

document()

Builds the peg pricing object UBI reads, holding every setting that is not None.

Returns:

Type Description
dict

A dict with the single key peg, whose value holds reference, offset_ticks, follows and on_empty_book when they are set and within_body_price when it is True.

Examples:

Print a peg that sits on the order's own side of the book with UBI's defaults:

from tradingmachine.orders.plan_parts import peg_pricing

pricing = peg_pricing.PegPricing()
print(pricing.document())

Print a peg to the midpoint, one tick further from filling:

from tradingmachine.orders.plan_parts import peg_pricing

pricing = peg_pricing.PegPricing(reference="mid", offset_ticks=1)
print(pricing.document())

Print a peg priced once at the own touch and kept within the template's limit price:

from tradingmachine.orders.plan_parts import peg_pricing

pricing = peg_pricing.PegPricing(
    reference="own_touch",
    follows=False,
    within_body_price=True,
)
print(pricing.document())

Print a peg two ticks through the other side's best price that is refused, rather than left waiting, when nobody is on that side, which is the pricing of a marketable_limit order:

from tradingmachine.orders.plan_parts import peg_pricing

pricing = peg_pricing.PegPricing(
    reference="opposite_touch",
    offset_ticks=-2,
    on_empty_book="refuse",
)
print(pricing.document())
Source code in src/tradingmachine/orders/plan_parts/peg_pricing.py
def document(self) -> dict:
    """Builds the `peg` pricing object UBI reads, holding every setting that is not None.

    Returns:
        A dict with the single key `peg`, whose value holds `reference`, `offset_ticks`, `follows` and `on_empty_book` when they are set and `within_body_price` when it is True.

    Raises:
        Nothing.

    Examples:
        Print a peg that sits on the order's own side of the book with UBI's defaults:

        ```python
        from tradingmachine.orders.plan_parts import peg_pricing

        pricing = peg_pricing.PegPricing()
        print(pricing.document())
        ```

        Print a peg to the midpoint, one tick further from filling:

        ```python
        from tradingmachine.orders.plan_parts import peg_pricing

        pricing = peg_pricing.PegPricing(reference="mid", offset_ticks=1)
        print(pricing.document())
        ```

        Print a peg priced once at the own touch and kept within the template's limit price:

        ```python
        from tradingmachine.orders.plan_parts import peg_pricing

        pricing = peg_pricing.PegPricing(
            reference="own_touch",
            follows=False,
            within_body_price=True,
        )
        print(pricing.document())
        ```

        Print a peg two ticks through the other side's best price that is refused, rather than left waiting, when nobody is on that side, which is the pricing of a `marketable_limit` order:

        ```python
        from tradingmachine.orders.plan_parts import peg_pricing

        pricing = peg_pricing.PegPricing(
            reference="opposite_touch",
            offset_ticks=-2,
            on_empty_book="refuse",
        )
        print(pricing.document())
        ```
    """
    settings = {}
    if self.reference is not None:
        settings["reference"] = self.reference
    if self.offset_ticks is not None:
        settings["offset_ticks"] = self.offset_ticks
    if self.follows is not None:
        settings["follows"] = self.follows
    if self.within_body_price:
        settings["within_body_price"] = True
    if self.on_empty_book is not None:
        settings["on_empty_book"] = self.on_empty_book
    return {
        "peg": settings,
    }

Example programs

Build a buy of a share pegged to each of the three places in the book a peg can follow

Run it with .venv/bin/python examples/orders/plan_parts/peg_pricing/peg_pricing/bid_on_each_reference.py.

"""Build a buy of a share pegged to each of the three places in the book a peg can follow.

The program looks up Vodafone Idea and builds three orders, one pegged to its own side of the book, one to the midpoint a tick further from filling, and one to the other side's touch, which fills at once. It prints the order object UBI would read for each. Nothing is sent to UBI's order routes.

Typical usage example:

  .venv/bin/python examples/orders/plan_parts/peg_pricing/peg_pricing/bid_on_each_reference.py
"""

import json

from tradingmachine.assets import equities
from tradingmachine.orders.plan_parts import order_part
from tradingmachine.orders.plan_parts import peg_pricing


class PegReferences:
    """Three pegged buys of Vodafone Idea, one for each reference.

    Attributes:
        share: The tradingmachine.assets.equities.Equity for Vodafone Idea on the NSE.
    """

    def __init__(self):
        """Looks up the share.

        Raises:
            tradingmachine.assets.exceptions.InstrumentError: The share could not be found in UBI.
        """
        self.share = equities.Equity(exchange="nse", symbol="IDEA")

    def run(self) -> None:
        """Prints the three orders' objects.

        Returns:
            None.

        Raises:
            Nothing.
        """
        rules = {
            "on the bid": peg_pricing.PegPricing(reference="own_touch"),
            "a tick below the midpoint": peg_pricing.PegPricing(
                reference="mid",
                offset_ticks=1,
            ),
            "on the offer, filling at once": peg_pricing.PegPricing(
                reference="opposite_touch",
            ),
        }
        for description, rule in rules.items():
            part = order_part.OrderPart(
                instrument=self.share,
                transaction_type="buy",
                quantity=1,
                pricing=rule,
            )
            print(f"Buy of {self.share.symbol} pegged {description}:")
            print(json.dumps(part.document(), indent=2))


if __name__ == "__main__":
    PegReferences().run()

Build a buy priced once at the bid and never above a limit worked out from the last price

Run it with .venv/bin/python examples/orders/plan_parts/peg_pricing/peg_pricing/one_shot_bid_within_a_limit.py.

"""Build a buy priced once at the bid and never above a limit worked out from the last price.

The program reads Vodafone Idea's last price and builds a plan order whose template is a limit buy 1% above it, with one order pegged to its own side of the book that does not follow it afterwards and treats the template's limit as the worst price it takes. This is how each purchase of UBI's accumulation type is priced. It prints the plan's synthetic object. The plan order is only built; nothing is sent to UBI's order routes.

Typical usage example:

  .venv/bin/python examples/orders/plan_parts/peg_pricing/peg_pricing/one_shot_bid_within_a_limit.py
"""

import json

from tradingmachine.assets import equities
from tradingmachine.orders import plan
from tradingmachine.orders.plan_parts import order_part
from tradingmachine.orders.plan_parts import peg_pricing


class OneShotBid:
    """A buy of Vodafone Idea priced once at the bid, within a limit.

    Attributes:
        share: The tradingmachine.assets.equities.Equity for Vodafone Idea on the NSE.
    """

    def __init__(self):
        """Looks up the share.

        Raises:
            tradingmachine.assets.exceptions.InstrumentError: The share could not be found in UBI.
        """
        self.share = equities.Equity(exchange="nse", symbol="IDEA")

    def run(self) -> None:
        """Prints the limit and the plan's synthetic object.

        Returns:
            None.

        Raises:
            ValueError: UBI has no last price for the share.
        """
        last_price = self.share.last_price
        if last_price is None:
            raise ValueError(f"UBI has no last price for {self.share!r}")
        limit_price = round(last_price * 1.01, 2)
        order = plan.PlanOrder(
            self.share,
            transaction_type="buy",
            product="mis",
            order_type="limit",
            quantity=1,
            price=limit_price,
            plan=order_part.OrderPart(
                pricing=peg_pricing.PegPricing(
                    reference="own_touch",
                    follows=False,
                    within_body_price=True,
                ),
            ),
        )
        print(f"Last price of {self.share.symbol}: {last_price}")
        print(f"Template limit, the most the buy pays: {limit_price}")
        print(json.dumps(order.synthetic, indent=2))


if __name__ == "__main__":
    OneShotBid().run()