while True: # new_event = get_new_event() # # if new_event.type == "LEFT_MOUSE_CLICK": open_menu() elif new_event.type == "ESCAPE_KEY_PRESS": quit_game() elif new_event.type == "UP_KEY_PRESS": move_player_north() # ... and many more events redraw_screen() # tick(50) # 50
event
is a fundamental unit of a class of event-oriented system. Contains a type (for example, “MARKET”, “SIGNAL”, “ORDER” or “FILL”), which affects how the event will be handled in a loop.event queue
is an in-memory Python object that stores all objects of the Event
subclasses generated by the rest of the system.DataHandler
is an abstract base class (ABK), which is an interface for processing historical and current market data. This increases the flexibility of the system, since the modules of the strategy and portfolio management can be used both for testing on historical data and for working on a “live” market. The DataHandler generates a MarketEvent
event at each heartbeat of the system.Strategy
) is another ABA, which is an interface for collecting market data and generating signal events ( SignalEvent
), which are used by the Portfolio
object. SignalEvent
contains the symbol of the exchange ticker, the direction of the order (Long, Short) and a timestamp.Portfolio
is also ABA, responsible for processing orders related to the current and subsequent positions implied by the Strategy
. This includes risk management portfolio, including control of the size of positions and analysis of market sectors. In more complex implementations, this part of the work can be transferred to the RiskManagement
class. Portfolio
takes SignalEvent
from the queue and generates order events ( OrderEvent
), which also get into the queue.ExecutionHandler
- in our case simulates a connection to the brokerage system. The task of the handler is to take OrderEvent events from the queue, execute them (in simulation mode or through a real connection to the broker). When the order is executed, the handler generates a FillEvent
event that describes the transaction, including broker and exchange fees, and slippage (if it is taken into account in the model).Portfolio
module. In addition, you can make different models of transaction costs in a separate class hierarchy. In our case, however, this will only create unnecessary difficulties, so we will only gradually introduce more realism into the system.bars.update_bars()
. # bars = DataHandler(..) strategy = Strategy(..) port = Portfolio(..) broker = ExecutionHandler(..) while True: # ( , ) if bars.continue_backtest == True: bars.update_bars() else: break # while True: try: event = events.get(False) except Queue.Empty: break else: if event is not None: if event.type == 'MARKET': strategy.calculate_signals(event) port.update_timeindex(event) elif event.type == 'SIGNAL': port.update_signal(event) elif event.type == 'ORDER': broker.execute_order(event) elif event.type == 'FILL': port.update_fill(event) # 10 time.sleep(10*60)
MarketEvent
- initiated when the outer loop starts a new “heart beat”. It occurs when a DataHandler object receives a new update of market data for any monitored financial instruments. It is used to start the generation of trading signals by the object Strategy
. The event object contains the identifier of what is a market event, and no other structure.SignalEvent
- The Strategy
object uses market information to create a new SignalEvent
signal event. This event contains a ticker symbol, generation timestamp and order direction (long or short). Such signaling events are used by the Portfolio
object as a kind of hint on how to trade.OrderEvent
— When a Portfolio
object receives a SignalEvent
, it uses such events for a broader portfolio context (calculation of risks and position size). All this leads to the creation of an OrderEvent
, which is then sent to the ExecutionHandler
.FillEvent
- when ExecutionHandler receives an OrderEvent
, it must execute it. After a transaction has occurred, a FillEvent
event is created that describes the cost of buying or selling and transaction costs (slippage, commissions, etc.)Event
- this is a base class that does not provide any functionality or special interface. In further implementations, the Event
class will most likely become more difficult, so it is worthwhile to foresee such an opportunity in advance by creating a class hierarchy: # event.py class Event(object): """ Event — , () , . """ pass
MarketEvent
inherits from Event
and carries a little more than a simple self-identification like 'MARKET': # event.py class MarketEvent(Event): """ . """ def __init__(self): """ MarketEvent. """ self.type = 'MARKET'
SignalEvent
requires a ticker symbol, time stamp and order direction, which the portfolio object can use as a “tip” when trading: # event.py class SignalEvent(Event): """ Signal Strategy. Portfolio, . """ def __init__(self, symbol, datetime, signal_type): """ SignalEvent. : symbol - , Google — 'GOOG'. datetime - . signal_type - 'LONG' 'SHORT'. """ self.type = 'SIGNAL' self.symbol = symbol self.datetime = datetime self.signal_type = signal_type
OrderEvent
more complicated than SignalEvent
, and contains an additional field for specifying the number of units of a financial instrument in an order. The number is determined by the limitations of the Portfolio
object. In addition, OrderEvent
contains the print_order()
method, which is used to output information to the console if necessary: # event.py class OrderEvent(Event): """ Order . (, GOOG), (market limit), . """ def __init__(self, symbol, order_type, quantity, direction): """ ( MKT LMT), (BUY SELL). : symbol - , . order_type - 'MKT' 'LMT' Market Limit. quantity - - (integer) . direction - 'BUY' 'SELL' . """ self.type = 'ORDER' self.symbol = symbol self.order_type = order_type self.quantity = quantity self.direction = direction def print_order(self): """ , Order. """ print "Order: Symbol=%s, Type=%s, Quantity=%s, Direction=%s" % \ (self.symbol, self.order_type, self.quantity, self.direction)
FillEvent
is an Event
increased complexity. It contains the timestamp of the execution of the order, the ticker and information about the exchange on which it was executed, the number of units of a financial instrument (stocks, futures, etc.), the actual price of the transaction and related fees. # event.py class FillEvent(Event): """ (Filled Order), . , / . . """ def __init__(self, timeindex, symbol, exchange, quantity, direction, fill_cost, commission=None): """ FillEvent. , , , , () . , Fill ( API) : timeindex - . symbol - , . exchange - , . quantity - . direction - ('BUY' 'SELL') fill_cost - . commission - , . """ 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): """ API ( , , .. ). . """ 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
class) for testing historical data and real trading.Source: https://habr.com/ru/post/263097/
All Articles