События, обусловленные обратным тестированием с Python - Часть II

Автор:Доброта, Создано: 2019-03-23 09:13:33, Обновлено:

В предыдущей статье мы описали концепцию обратного теста, основанного на событиях. В остальной части этой серии статей мы сосредоточимся на каждой из отдельных иерархий классов, которые составляют общую систему.

Как было обсуждено в предыдущей статье, торговая система использует две петли while - внешнюю и внутреннюю. Внутренняя петля while обрабатывает захват событий из очереди в памяти, которые затем перенаправляются на соответствующий компонент для последующих действий. В этой инфраструктуре есть четыре типа событий:

  • MarketEvent - запускается, когда внешняя петля while начинает новый heartbeat. Это происходит, когда объект DataHandler получает новое обновление данных рынка для любых символов, которые в настоящее время отслеживаются. Он используется для запуска объекта Strategy, генерирующего новые торговые сигналы. Объект события просто содержит идентификацию того, что это событие рынка, без другой структуры.
  • SignalEvent - объект Strategy использует рыночные данные для создания новых SignalEvents. SignalEvent содержит символ тикера, временную метку, когда он был создан, и направление (длинное или короткое).
  • OrderEvent - когда объект портфеля получает SignalEvents, он оценивает их в более широком контексте портфеля с точки зрения риска и размещения позиций.
  • FillEvent - когда ExecutionHandler получает OrderEvent, он должен совершить транзакцию. как только ордер будет выполнен, он генерирует FillEvent, который описывает стоимость покупки или продажи, а также затраты на транзакцию, такие как сборы или скольжение.

Родительский класс называется Event. Он является базовым классом и не обеспечивает никакой функциональности или конкретного интерфейса. В последующих реализациях объекты Event, вероятно, будут развивать большую сложность, и, таким образом, мы будущее-устойчивость дизайна таких систем путем создания иерархии классов.

# event.py

class Event(object):
    """
    Event is base class providing an interface for all subsequent 
    (inherited) events, that will trigger further events in the 
    trading infrastructure.   
    """
    pass

MarketEvent наследует от Event и обеспечивает немного больше, чем самоидентификацию, что это событие типа MARKET.

# event.py

class MarketEvent(Event):
    """
    Handles the event of receiving a new market update with 
    corresponding bars.
    """

    def __init__(self):
        """
        Initialises the MarketEvent.
        """
        self.type = 'MARKET'

SignalEvent требует символа тикера, временной отметки для генерации и направления для того, чтобы сообщить объекту Portfolio.

# event.py

class SignalEvent(Event):
    """
    Handles the event of sending a Signal from a Strategy object.
    This is received by a Portfolio object and acted upon.
    """
    
    def __init__(self, symbol, datetime, signal_type):
        """
        Initialises the SignalEvent.

        Parameters:
        symbol - The ticker symbol, e.g. 'GOOG'.
        datetime - The timestamp at which the signal was generated.
        signal_type - 'LONG' or 'SHORT'.
        """
        
        self.type = 'SIGNAL'
        self.symbol = symbol
        self.datetime = datetime
        self.signal_type = signal_type

OrderEvent немного сложнее, чем SignalEvent, поскольку он содержит поле количества в дополнение к вышеупомянутым свойствам SignalEvent. Количество определяется ограничениями портфеля. Кроме того, OrderEvent имеет метод print_order ((), используемый для вывода информации в консоль при необходимости.

# event.py

class OrderEvent(Event):
    """
    Handles the event of sending an Order to an execution system.
    The order contains a symbol (e.g. GOOG), a type (market or limit),
    quantity and a direction.
    """

    def __init__(self, symbol, order_type, quantity, direction):
        """
        Initialises the order type, setting whether it is
        a Market order ('MKT') or Limit order ('LMT'), has
        a quantity (integral) and its direction ('BUY' or
        'SELL').

        Parameters:
        symbol - The instrument to trade.
        order_type - 'MKT' or 'LMT' for Market or Limit.
        quantity - Non-negative integer for quantity.
        direction - 'BUY' or 'SELL' for long or short.
        """
        
        self.type = 'ORDER'
        self.symbol = symbol
        self.order_type = order_type
        self.quantity = quantity
        self.direction = direction

    def print_order(self):
        """
        Outputs the values within the Order.
        """
        print "Order: Symbol=%s, Type=%s, Quantity=%s, Direction=%s" % \
            (self.symbol, self.order_type, self.quantity, self.direction)

FillEvent - это событие с наибольшей сложностью. Он содержит временную метку, когда был выполнен ордер, символ ордера и обмен, на котором он был выполнен, количество сделанных акций, фактическую цену покупки и понесенную комиссию.

Комиссия рассчитывается с использованием комиссий Interactive Brokers. Для заказов API США эта комиссия составляет минимум 1,30 доллара США за заказ, с фиксированной ставкой 0,013 доллара США или 0,08 доллара США за акцию в зависимости от того, составляет ли размер торговли менее или выше 500 единиц акций.

# event.py

class FillEvent(Event):
    """
    Encapsulates the notion of a Filled Order, as returned
    from a brokerage. Stores the quantity of an instrument
    actually filled and at what price. In addition, stores
    the commission of the trade from the brokerage.
    """

    def __init__(self, timeindex, symbol, exchange, quantity, 
                 direction, fill_cost, commission=None):
        """
        Initialises the FillEvent object. Sets the symbol, exchange,
        quantity, direction, cost of fill and an optional 
        commission.

        If commission is not provided, the Fill object will
        calculate it based on the trade size and Interactive
        Brokers fees.

        Parameters:
        timeindex - The bar-resolution when the order was filled.
        symbol - The instrument which was filled.
        exchange - The exchange where the order was filled.
        quantity - The filled quantity.
        direction - The direction of fill ('BUY' or 'SELL')
        fill_cost - The holdings value in dollars.
        commission - An optional commission sent from IB.
        """
        
        self.type = 'FILL'
        self.timeindex = timeindex
        self.symbol = symbol
        self.exchange = exchange
        self.quantity = quantity
        self.direction = direction
        self.fill_cost = fill_cost

        # Calculate commission
        if commission is None:
            self.commission = self.calculate_ib_commission()
        else:
            self.commission = commission

    def calculate_ib_commission(self):
        """
        Calculates the fees of trading based on an Interactive
        Brokers fee structure for API, in USD.

        This does not include exchange or ECN fees.

        Based on "US API Directed Orders":
        https://www.interactivebrokers.com/en/index.php?f=commission&p=stocks2
        """
        full_cost = 1.3
        if self.quantity <= 500:
            full_cost = max(1.3, 0.013 * self.quantity)
        else: # Greater than 500
            full_cost = max(1.3, 0.008 * self.quantity)
        full_cost = min(full_cost, 0.5 / 100.0 * self.quantity * self.fill_cost)
        return full_cost

В следующей статье серии мы рассмотрим, как разработать иерархию классов DataHandler рынка, которая позволяет как историческую обратную проверку, так и прямую торговлю через один и тот же интерфейс класса.


Больше