파이썬으로 이벤트 기반 백테스팅 - II부

저자:선함, 2019-03-23 09:13:33, 업데이트:

지난 기사에서는 이벤트에 의한 백테스터의 개념을 설명했습니다. 이 시리즈의 나머지 기사에서는 전체 시스템을 구성하는 개별 클래스 계층별로 집중할 것입니다. 이 기사에서는 이벤트를 고려하고 객체 간의 정보를 통신하는 데 사용할 수 있습니다.

이전 기사에서 논의 된 바와 같이 거래 시스템은 외부와 내부의 두 개의 윙을 사용합니다. 내부의 윙은 메모리 큐에서 이벤트를 캡처하고 다음 작업을 위해 적절한 구성 요소로 라우팅합니다. 이 인프라에는 네 가지 유형의 이벤트가 있습니다.

  • MarketEvent - 외부 while 루프가 새로운 heartbeat을 시작하면 트리거됩니다. 데이터 핸들러 객체가 현재 추적 중인 모든 기호에 대한 시장 데이터의 새로운 업데이트를 받을 때 발생합니다. 새로운 거래 신호를 생성하는 전략 객체를 트리거하는 데 사용됩니다. 이벤트 객체는 다른 구조가없는 시장 이벤트라는 식별을 포함합니다.
  • SignalEvent - 전략 객체는 새로운 SignalEvents를 생성하기 위해 시장 데이터를 사용합니다. SignalEvent에는 틱어 기호, 생성 된 시점 및 방향 (장 또는 단) 의 시간표가 포함되어 있습니다. SignalEvents는 포트폴리오 객체에 의해 거래 방법에 대한 조언으로 사용됩니다.
  • OrderEvent - 포트폴리오 객체가 SignalEvents를 수신하면 위험 및 포지션 사이징 측면에서 포트폴리오의 더 넓은 맥락에서 평가합니다. 이것은 궁극적으로 ExecutionHandler에 전송되는 OrderEvents로 이어집니다.
  • FillEvent - ExecutionHandler가 OrderEvent를 수신하면 주문을 처리해야 합니다. 주문이 처리되면 구매 또는 판매 비용과 수수료 또는 미끄러짐과 같은 거래 비용을 설명하는 FillEvent를 생성합니다.

부모 클래스는 이벤트라고 불립니다. 그것은 기본 클래스이며 어떤 기능이나 특정 인터페이스를 제공하지 않습니다. 후기 구현에서 이벤트 객체는 더 많은 복잡성을 개발할 가능성이 있으며 따라서 우리는 클래스 계층을 생성함으로써 그러한 시스템의 디자인을 미래로 증명하고 있습니다.

# 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는 포트폴리오 객체에 대해 알리기 위해 틱어 기호, 생성 시간표 및 방향을 필요로 합니다.

# 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의 앞서 언급한 속성 외에도 양분 필드를 포함하고 있기 때문에 OrderEvent보다 약간 복잡합니다. 양은 포트폴리오 제약에 의해 결정됩니다. 또한 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는 가장 복잡한 이벤트입니다. 주문이 완료 된 시점, 주문의 기호 및 거래소가 실행된 시점, 거래된 주식량, 실제 구매 가격 및 수수료를 포함합니다.

수수료는 인터랙티브 브로커 수수료를 사용하여 계산됩니다. 미국 API 주문의 경우 이 수수료는 주문당 최소 1.30 USD이며, 거래 규모가 500 유닛 이하 또는 이상인지에 따라 주당 0.013 USD 또는 0.08 USD의 일정한 비율로 계산됩니다.

# 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

이 시리즈의 다음 기사에서는 같은 클래스 인터페이스를 통해 역사적인 백테스팅과 실시간 거래를 모두 허용하는 시장 데이터 핸들러 클래스 계층 구조를 개발하는 방법을 고려할 것입니다.


더 많은