Source code for oxberrypis.orderbook.matching_engine
"""Order book matching engine.
Created on Apr 28, 2013
.. codeauthor:: Hynek Jemelik
"""
from ..errors import OrderBookError
from .book import OrderBook
from .order import Order
class PrintingMatchingEngineCallback(object):
def trade(self, num_shares, price):
print 'Trading {} shares at price {}.'.format(num_shares, price)
[docs]class MatchingEngine(object):
"""Matching engine.
Main class for processing each individual stock, it implements
rules and logic of stock exchange and maintains orders in correct
order. It allows adding, changing, and removing orders.
"""
def __init__(self, callback=None):
self.supply = OrderBook()
self.demand = OrderBook()
self.callback = callback or PrintingMatchingEngineCallback()
def add_order(self, order_id, limit_price, num_shares, order_type):
order = Order(order_id, limit_price, num_shares, order_type)
book = self.get_book(order)
book.add_order(order)
self.execute_orders(order)
def remove_order(self, order_id):
self.supply.remove_order(order_id)
self.demand.remove_order(order_id)
def update_order(self, order_id, limit_price, num_shares, order_type):
updated_order = Order(order_id, limit_price, num_shares, order_type)
book = self.get_book(updated_order)
book.update_order(updated_order)
self.execute_orders(updated_order)
def decrease_order_amount_by(self, order_id, decr_by):
o = self.supply.get_order_by_id(order_id)
if o is not None:
self.update_order(o.id, o.price, o.num_shares - decr_by, o.type)
else:
o = self.demand.get_order_by_id(order_id)
if o is not None:
self.update_order(o.id, o.price, o.num_shares - decr_by, o.type)
else:
msg = 'Order with id {} has not been found.'.format(order_id)
raise OrderBookError(msg)
def get_best_orders(self):
return (self.supply.get_best(), self.demand.get_best())
def execute_orders(self, order):
return
opposite = self.get_opposite(order)
best = opposite.get_best()
if self.can_trade(order, best):
num_shares = min(order.num_shares, best.num_shares)
self.callback.trade(num_shares, best.price)
order.num_shares -= num_shares
best.num_shares -= num_shares
if best.num_shares == 0:
self.remove_order(best.id)
if order.num_shares == 0:
self.remove_order(order.id)
else:
self.execute_orders(order)
def can_trade(self, o1, o2):
if o1 is None or o2 is None:
return False
else:
if o1.type == Order.SELL:
sell = o1
buy = o2
else:
buy = o1
sell = o2
return sell.price <= buy.price
def get_book(self, order):
if order.type == Order.SELL:
return self.supply
elif order.type == Order.BUY:
return self.demand
else:
msg = 'Order type {} not recognized.'.format(order.type)
raise OrderBookError(msg)
def get_opposite(self, order):
if order.type == Order.SELL:
return self.demand
elif order.type == Order.BUY:
return self.supply
else:
msg = 'Order type {} not recognized.'.format(order.type)
raise OrderBookError(msg)