Pruebas de retroceso basadas en eventos con Python - Parte VI

El autor:La bondad, Creado: 2019-03-26 09:13:08, Actualizado:

Este artículo continúa la discusión de los backtesters impulsados por eventos en Python. En el artículo anterior consideramos una jerarquía de clase de cartera que manejaba posiciones actuales, generaba órdenes comerciales y seguía el registro de ganancias y pérdidas (PnL).

En este artículo estudiaremos la ejecución de estas órdenes, mediante la creación de una jerarquía de clases que representará un mecanismo de manejo de órdenes simulado y, en última instancia, se vinculará a una correduría u otros medios de conectividad del mercado.

El ExecutionHandler descrito aquí es extremadamente simple, ya que cumple todas las órdenes al precio actual del mercado.

Al igual que con las jerarquías de clases base abstractas anteriores, debemos importar las propiedades y decoradores necesarios de la biblioteca abc. Además necesitamos importar el FillEvent y el OrderEvent:

# execution.py

import datetime
import Queue

desde abc importar ABCMeta, método abstracto

desde la importación de eventos FillEvent, OrderEvent El ExecutionHandler es similar a las clases básicas abstractas anteriores y simplemente tiene un método virtual puro, execute_order:

# execution.py

class ExecutionHandler(object):
    """
    The ExecutionHandler abstract 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 handlers can be used to subclass simulated brokerages
    or live brokerages, with identical interfaces. This allows
    strategies to be backtested in a very similar manner to the
    live trading engine.
    """

    __metaclass__ = ABCMeta

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

        Parameters:
        event - Contains an Event object with order information.
        """
        raise NotImplementedError("Should implement execute_order()")

Para probar estrategias de retroceso, necesitamos simular cómo se transacciona un comercio. La implementación más simple posible es asumir que todas las órdenes se cumplen al precio de mercado actual para todas las cantidades. Esto es claramente extremadamente poco realista y una gran parte de la mejora del realismo de retroceso provendrá del diseño de modelos más sofisticados de deslizamiento e impacto en el mercado.

Tenga en cuenta que el FillEvent se da un valor de Ninguno para el fill_cost (ver la línea penúltima en execute_order) ya que ya nos hemos ocupado del costo de llenado en el objeto NaivePortfolio descrito en el artículo anterior. En una implementación más realista haríamos uso del valor de datos de mercado current para obtener un costo de llenado realista.

En un entorno de ejecución en vivo esta dependencia del lugar sería mucho más importante:

# execution.py

class SimulatedExecutionHandler(ExecutionHandler):
    """
    The simulated execution handler simply converts all order
    objects into their equivalent fill objects automatically
    without latency, slippage or fill-ratio issues.

    This allows a straightforward "first go" test of any strategy,
    before implementation with a more sophisticated execution
    handler.
    """
    
    def __init__(self, events):
        """
        Initialises the handler, setting the event queues
        up internally.

        Parameters:
        events - The Queue of Event objects.
        """
        self.events = events

    def execute_order(self, event):
        """
        Simply converts Order objects into Fill objects naively,
        i.e. without any latency, slippage or fill ratio problems.

        Parameters:
        event - Contains an Event object with order information.
        """
        if event.type == 'ORDER':
            fill_event = FillEvent(datetime.datetime.utcnow(), event.symbol,
                                   'ARCA', event.quantity, event.direction, None)
            self.events.put(fill_event)

Esto concluye las jerarquías de clases necesarias para producir un backtester basado en eventos.


Más.