事件駆動バックテストの概念について説明しました.このシリーズの残りの記事は,全体的なシステムを構成する個々のクラス階層に焦点を当てます.この記事では,イベントとオブジェクト間の情報通信に使用する方法について検討します.
前回の記事で議論したように,取引システムは,外側と内側の2つのウィンドウを使用します.内側ウィンドウは,メモリ内のキューからイベントのキャプチャを処理し,その後,次のアクションのために適切なコンポーネントにルーティングされます.このインフラストラクチャには,4種類のイベントがあります:
親クラスは 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から継承され,それが
# 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 は SignalEvent より少し複雑である.数値は Portfolio 制約によって決定される.また,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つの注文につき最低1.30USDで,取引規模が500株未満または上であるかどうかに基づいて,1株あたり0.013USDまたは0.08USDの固定金利である.
# 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 クラスの階層をどのように開発するかについて検討します.