Kiểm tra ngược dựa trên sự kiện với Python - Phần II

Tác giả:Tốt, Tạo: 2019-03-23 09:13:33, Cập nhật:

Trong bài viết trước đây, chúng tôi đã mô tả khái niệm về backtester dựa trên sự kiện. Phần còn lại của loạt bài viết này sẽ tập trung vào từng phân cấp lớp riêng biệt tạo nên hệ thống tổng thể.

Như đã được thảo luận trong bài viết trước, hệ thống giao dịch sử dụng hai vòng lặp trong khi - một bên ngoài và một bên trong.

  • MarketEvent - Điều này được kích hoạt khi vòng lặp while bên ngoài bắt đầu một nhịp tim mới. Nó xảy ra khi đối tượng DataHandler nhận được một bản cập nhật mới về dữ liệu thị trường cho bất kỳ biểu tượng nào đang được theo dõi. Nó được sử dụng để kích hoạt đối tượng Chiến lược tạo ra các tín hiệu giao dịch mới. Đối tượng sự kiện chỉ chứa một nhận dạng rằng đó là một sự kiện thị trường, không có cấu trúc khác.
  • SignalEvent - Đối tượng Chiến lược sử dụng dữ liệu thị trường để tạo ra các SignalEvents mới. SignalEvent chứa biểu tượng ticker, dấu thời gian cho khi nó được tạo ra và hướng (dài hoặc ngắn). Các SignalEvents được sử dụng bởi đối tượng Portfolio như lời khuyên về cách giao dịch.
  • OrderEvent - Khi một đối tượng danh mục đầu tư nhận được SignalEvents, nó đánh giá chúng trong bối cảnh rộng lớn hơn của danh mục đầu tư, về rủi ro và kích thước vị trí.
  • FillEvent - Khi một ExecutionHandler nhận được một OrderEvent, nó phải giao dịch lệnh. Một khi lệnh đã được giao dịch, nó tạo ra FillEvent, mô tả chi phí mua hoặc bán cũng như chi phí giao dịch, chẳng hạn như phí hoặc trượt.

Các lớp cha mẹ được gọi là sự kiện. Nó là một lớp cơ sở và không cung cấp bất kỳ chức năng hoặc giao diện cụ thể. Trong các triển khai sau đó các đối tượng sự kiện có thể sẽ phát triển sự phức tạp lớn hơn và do đó chúng tôi đang chứng minh tương lai thiết kế của các hệ thống như vậy bằng cách tạo ra một hệ thống phân cấp lớp.

# 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 thừa hưởng từ Event và cung cấp ít hơn một tự xác định rằng nó là một sự kiện kiểu 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'

Một SignalEvent đòi hỏi một biểu tượng ticker, một dấu thời gian để tạo và một hướng để thông báo cho một đối tượng 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 phức tạp hơn một chút so với SignalEvent vì nó chứa một trường số lượng ngoài các thuộc tính được đề cập ở trên của SignalEvent. Số lượng được xác định bởi các hạn chế Portfolio. Ngoài ra, OrderEvent có phương thức print_order ((), được sử dụng để xuất thông tin đến bảng điều khiển nếu cần thiết.

# 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 là sự kiện phức tạp nhất. Nó chứa dấu thời gian cho khi một lệnh được thực hiện, biểu tượng của lệnh và trao đổi nó đã được thực hiện, số lượng cổ phiếu giao dịch, giá thực tế của việc mua và hoa hồng phát sinh.

Phụ phí được tính bằng cách sử dụng các khoản hoa hồng của Interactive Brokers. Đối với các đơn đặt hàng API của Hoa Kỳ, khoản hoa hồng này là tối thiểu 1,30 USD mỗi đơn đặt hàng, với tỷ lệ cố định là 0,013 USD hoặc 0,08 USD mỗi cổ phiếu tùy thuộc vào kích thước giao dịch dưới hoặc trên 500 đơn vị cổ phiếu.

# 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

Trong bài viết tiếp theo của loạt bài, chúng tôi sẽ xem xét cách phát triển một phân cấp lớp DataHandler thị trường cho phép cả kiểm tra ngược lịch sử và giao dịch trực tiếp, thông qua cùng một giao diện lớp.


Thêm nữa