Skip to main content

Event-driven Python backtesting engine - Broker - Part 7

·594 words·3 mins
Anthony Ori
Author
Anthony Ori
~ tinkerer ~

In the previous article we took a deep dive in the Portfolio component and discussed its role in communicating with the signal generator and the broker. In this article we will expand on the relationship between Portfolio and Broker.

The Broker component is concerned only with executing orders. It doesn’t need to involve itself with other components, except the Portfolio, and as such will be a “dumb” component. In a live implementation it will need to be more involved, but for a naive buy & hold strategy, we can get by with a dumb broker.

The final code for the broker is:

# trading_engine/broker.py

import datetime

from abc import ABC, abstractmethod
from events import FillEvent


class ExecutionHandler(ABC):
    """
    The ExecutionHandler abstract base class handles the interaction between a set of order objects generated
    by a Portfolio and the ultimate set of Fill objects that actually occur in the market.

    The derived handlers can be used to subclass simulated or live brokerages, with identical interfaces.
    This allows strategies to be backtested in a very similar environment to a live trading engine.
    """

    @abstractmethod
    def execute_order(self, event):
        """
        Takes an Order event and executes it, producing a Fill event that gets placed onto the events queue.

        :param event: an OrderEvent object
        """

        raise NotImplementedError("Should implement execute_order()")


class SimulatedExecutionHandler(ExecutionHandler):
    """
    The SimulatedExecutionHandler simply converts all order objects into their equivalent fill objects in a
    "dumb" manner, without latency, slippage or fill-ratio issues. More realistic implementations will have
    to implement those.
    """

    def __init__(self, events):
        """
        Initialise the handler, setting the event queues internally

        :param events: the queue of Event objects
        """

        self.events = events

    def execute_order(self, event):
        """
        Simply converts Order objects into Fill objects, naively, as explained in the main docstring.

        :param event: an OrderEvent object
        """

        if event.type == 'ORDER':
            event.print_order()

            fill_event = FillEvent(
                datetime.datetime.now(datetime.UTC),
                event.symbol, 'ARCA',
                event.quantity,
                # In a simulated environment ordered quantity = filled quantity,
                # but in a real world setting the quantities may differ, due to
                # slippage -- the broker not being able to fill the order entirely,
                # or not at the initially agreed price.
                # event.filled_quantity,
                event.direction,
                # fill cost is None for simplicity, but in a real setting it should be
                # computed here or more commonly sent from the broker's platform directly
                None
            )

            self.events.put(fill_event)

The execute_order method, which simply converts an OrderEvent to a FillEvent.

Adding on the code comments in the method, a smarter broker will also inform the Portfolio about leveraged positions and warn about the dreaded margin calls. Moreover, a broker could also be the data source, but for the sake of illustration, it conceptually makes sense to abstract the two into their own parts. After all the main data layer could originate from another source and not the broker’s data feed, or even if the data is coming from the broker, separating data from execution is the sensible thing to do.

That concludes the series. If you followed it all the way here then you can pat yourself on the back!

Concluding remarks
#

If you refer back to the first article, and the first code snippet, you will hopefully have a complete understanding of how the pieces weld together, how to cover application code with tests, how a backtesting engine works in its simplest form, and more generally how to develop an event-driven system and apply it to whatever other domain you’re concerned with.

If you want to reach out for whatever reason, to inform me of errors, questions, etc., you can do so via email here or Linkedin.


Feel free to share the article on socials: