Pengujian Kembali yang Dikendalikan Acara dengan Python - Bahagian II

Penulis:Kebaikan, Dicipta: 2019-03-23 09:13:33, Dikemas kini:

Dalam artikel sebelumnya, kami menerangkan konsep backtester yang didorong oleh peristiwa. Selebihnya siri artikel ini akan menumpukan pada setiap hierarki kelas berasingan yang membentuk keseluruhan sistem. Dalam artikel ini, kami akan mempertimbangkan Acara dan bagaimana ia boleh digunakan untuk berkomunikasi maklumat antara objek.

Seperti yang dibincangkan dalam artikel sebelumnya, sistem perdagangan menggunakan dua gelung sementara - luar dan dalaman. gelung sementara dalaman mengendalikan penangkapan peristiwa dari antrian dalam memori, yang kemudiannya diarahkan ke komponen yang sesuai untuk tindakan berikutnya. Dalam infrastruktur ini terdapat empat jenis peristiwa:

  • MarketEvent - Ini dicetuskan apabila gelung sementara luar memulakan heartbeat baru. Ia berlaku apabila objek DataHandler menerima kemas kini baru data pasaran untuk mana-mana simbol yang sedang dikesan. Ia digunakan untuk mencetuskan objek Strategi menghasilkan isyarat perdagangan baru. Objek acara hanya mengandungi pengenalan bahawa ia adalah acara pasaran, tanpa struktur lain.
  • SignalEvent - Objek Strategi menggunakan data pasaran untuk membuat SignalEvents baru. SignalEvent mengandungi simbol ticker, cap masa untuk apabila ia dijana dan arah (panjang atau pendek). SignalEvents digunakan oleh objek Portfolio sebagai nasihat untuk bagaimana untuk berdagang.
  • OrderEvent - Apabila objek Portfolio menerima SignalEvents ia menilai mereka dalam konteks yang lebih luas portfolio, dari segi risiko dan saiz kedudukan.
  • FillEvent - Apabila ExecutionHandler menerima OrderEvent, ia mesti melakukan urus niaga. Setelah pesanan telah dilakukan, ia menghasilkan FillEvent, yang menerangkan kos pembelian atau penjualan serta kos transaksi, seperti yuran atau slippage.

Kelas induk dipanggil Acara. Ia adalah kelas asas dan tidak menyediakan sebarang fungsi atau antara muka tertentu. Dalam pelaksanaan kemudian objek Acara mungkin akan membangunkan kerumitan yang lebih besar dan dengan itu kita membuktikan reka bentuk sistem sedemikian dengan mewujudkan hierarki kelas.

# 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 mewarisi dari Event dan memberikan sedikit lebih daripada pengenalan diri bahawa ia adalah peristiwa jenis 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'

A SignalEvent memerlukan simbol ticker, stempel masa untuk penjanaan dan arah untuk memberi nasihat kepada objek 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 adalah sedikit lebih kompleks daripada SignalEvent kerana ia mengandungi medan kuantiti sebagai tambahan kepada sifat SignalEvent yang disebutkan di atas. kuantiti ditentukan oleh kekangan Portfolio. Di samping itu OrderEvent mempunyai print_order() kaedah, yang digunakan untuk mengeluarkan maklumat ke konsol jika perlu.

# 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 adalah Peristiwa dengan kerumitan terbesar. Ia mengandungi cap masa untuk apabila pesanan telah dipenuhi, simbol pesanan dan pertukaran yang dilaksanakan, jumlah saham yang ditransaksi, harga sebenar pembelian dan komisen yang dikenakan.

Komisen dikira menggunakan komisen Interactive Brokers. Untuk pesanan API AS, komisen ini adalah minimum 1.30 USD setiap pesanan, dengan kadar tetap sama ada 0.013 USD atau 0.08 USD setiap saham bergantung kepada sama ada saiz perdagangan di bawah atau di atas 500 unit saham.

# 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

Dalam artikel seterusnya dalam siri ini kita akan mempertimbangkan bagaimana untuk membangunkan hierarki kelas DataHandler pasaran yang membolehkan kedua-dua backtesting sejarah dan perdagangan langsung, melalui antara muka kelas yang sama.


Lebih lanjut