Beispiel #1
0
def utest_MatchingEngine_15():
    print '-- Matching Engine: Example 2 --'
    m = MatchingEngine()

    m.addOrder(ASK, 1, 20, 10000, 100)
    m.addOrder(ASK, 2, 20, 10000, 200)

    m.addOrder(BID, 3, 20, 10300, 100)

    # Expected Book state
    b = Book()
    b.addOrder(ASK, 2, 20,  9700,  200)
    checkBooks( m.myBook, b )
    
    print 'OK'
Beispiel #2
0
def utest_MatchingEngine_14():    
    print '-- Matching Engine: Example 1 --'
    m = MatchingEngine()

    m.addOrder(ASK, 1, 56.5,  9000,  2000) 
    m.addOrder(ASK, 2, 56.5,  3000,  3000) 
    m.addOrder(ASK, 3, 56.6, 20000, 20000) 
    m.myBook.show()
    
    m.addOrder(BID, 4, 56.6, 8000, 8000) 
    m.myBook.show()

    # Expected Book state
    b = Book()
    b.addOrder(ASK, 1, 56.5,  4000,  2000)
    b.addOrder(ASK, 3, 56.6, 20000, 20000) 
    checkBooks( m.myBook, b )
    
    print 'OK'
class MatchingEngine(object):
    '''| TODO
    |
    |________'''
    def __init__(self):
        self.myBook = Book()

    def addOrder(self, isBid, orderId, price, qty, peakSize):
        '''| TODO 
        | price is an integer number, i.e. divide by 100 to get the actual price
        |________'''

        if self.myBook.isPresent(orderId):
            print "Order with the same Id (", orderId, ") found! Order will not be added to the Book!"
        else:
            self.matchOrder(isBid, orderId, price, qty, peakSize)

    def removeOrder(self, orderId):
        '''| TODO 
        | Called as a result of command X (remove order)
        |________'''
        if self.myBook.removeOrder(orderId):
            print "Order removed:", orderId
            self.myBook.removeEmptyLevels()
        else:
            print "Order not found:", orderId

    def showBook(self):
        '''| TODO 
        | Called as a result of command s (show book state)
        |________'''
        myBook.show()

# TODO: Verbose or log i.s.o. print?

    def matchOrder(self, isBid, orderId, price, quantity, peakSize):
        '''|
        | Match a bid/ask order against the orders of the ask/bid depth of the book starting from the best ask/bid price level
        |________'''

        matching_side = self.myBook.ask if isBid else self.myBook.bid

        if len(matching_side) != 0:
            # Iterating over the different price levels
            for lprice, level in matching_side.iteritems():
                match = lprice <= int(price * 100) if isBid else lprice >= int(
                    price * 100)
                # Note:                 best ask price <= bid price            best bid price >= ask price
                if match:
                    # Check complete or partial fills against visible and iceberg orders
                    quantity = self.checkExecution(level, quantity, orderId)

                    # Remove filled orders, update iceberg orders - visible and invisible part
                    self.updateLevel(level)

                    # Continue with the next price level (if needed)
                    # Exit the loop if the incoming order is completely filled or the matching side of the book becomes empty
                    if quantity == 0:
                        break
                else:
                    break

            # Clean the book from levels containing only filled orders; in this way - set the next best price
            self.myBook.removeEmptyLevels()

        # Add an order (also, if not filled completely)
        if quantity > 0:
            if peakSize > quantity:
                peakSize = quantity
            self.myBook.addOrder(isBid, orderId, price, quantity, peakSize)
            str_o = "B" if isBid else "A"
            print "A:", str_o, orderId, price, quantity, peakSize

    def checkFill(self, level, myQty, orderId):
        for order in level:
            if order.quantity >= myQty:  # complete fill of incoming order
                # E <incoming order id> <matched order id> <price> <matched quantity>
                print "E1", orderId, "with", order.orderId, order.price, myQty
                order.quantity -= myQty  # update order
                myQty = 0  # all matched
                return myQty

            else:  # partial fill of incoming order (order.quantity < myQty)
                print "E2", orderId, "with", order.orderId, order.price, order.quantity
                myQty -= order.quantity  # matched quantity
                order.quantity = 0  # marked to be removed

        return myQty

    def checkExecution(self, level, myQty, orderId):
        '''|
        | First check visible orders, then icebergs
        | Returns remaining quantity
        |________'''
        remQty = self.checkFill(level.visible_orders, myQty, orderId)
        if remQty > 0: remQty = self.checkFill(level.icebergs, remQty, orderId)
        return remQty

    def updateLevel(self, level):
        '''| TODO 
        | Matched orders from the book are marked as 'peakSize=0'. This indicates that they have to be removed from the level
        | The visible part of iceberg orders is replenished with a 'reload' value <= peakSize and moved back to the queue of visible orders
        | If a hidden part of an iceberg does not have a remaining quantity anymore, it is removed from the level.
        |________'''

        for order in list(
                level.visible_orders
        ):  # Note: list() due to RuntimeError: deque mutated during iteration
            if order.quantity == 0:
                # Remove filled limit orders from the book
                orderId = order.orderId
                # From the particular level
                level.removeVisible(orderId)
                # Remove the order from the map of active orders
                self.myBook.removeActiveOrder(
                    orderId)  # TODO: Check isIceberg and not remove if True?
                print "Removed (visible) Id:", orderId

        for order in list(
                level.icebergs
        ):  # Note: list() due to RuntimeError: deque mutated during iteration

            if order.quantity == 0:  # Complete fill: Remove the order
                self.myBook.removeOrder(order.orderId)
                level.removeIceberg(order.orderId)

            else:  # Replanish visible part
                if order.peakSize < order.quantity:  # Update the quantity accordingly
                    order.quantity -= order.peakSize

                else:  # order.peakSize >= quantity
                    order.peakSize = order.quantity
                    # Remove the invisible part of the iceberg because its quantity is consumed
                    level.removeIceberg(orderId)
                    print "Iceberg removed", orderId

                # Replenish the visible part of the order
                myOrder = Order(order.isBuy, order.orderId, order.price,
                                order.peakSize, order.peakSize)
                myOrder.isIceberg = True  # peakSize can be == quantity

                # Add the visible part of the order at the end of the queue of visible orders
                self.myBook.addOrder(order=myOrder)

                print "Replanished", order.orderId
Beispiel #4
0
def utest_Book():    
    print '-- Book --',
    bo, ao = createOrders()
    b = Book()
    assert b.isEmpty()         == True,  "Book not empty!" 
    assert b.isPresent(999)    == False, "Order found in an empty book!"
        
    b.addOrder( order=bo )
    assert b.isBidEmpty()      == False, "Bid level is empty!" 
    assert b.isAskEmpty()      == True,  "Ask level not empty!"
    assert b.isEmpty()         == False, "Book is empty!" 
    assert b.isPresent(999)    == True,  "Order '999' not present!"

    b.addOrder( order=ao )
    assert b.isBidEmpty()      == False, "Bid level is empty!" 
    assert b.isAskEmpty()      == False, "Ask level is empty!"
    assert b.isEmpty()         == False, "Book is empty!" 
    assert b.isPresent(9191)   == True,  "Order '9191' not present!"
    
    assert b.removeOrder(999)  == True,  "Removing order '999' failed!"
    assert b.isBidEmpty()      == False, "Bid level is empty!" 
    assert b.isAskEmpty()      == False, "Ask level is empty!"
    assert b.isEmpty()         == False, "Book is empty!" 
        
    b.removeEmptyLevels()
    assert b.isBidEmpty()      == True,  "Bid level not empty!" 
    assert b.isAskEmpty()      == False, "Asklevel is empty!"
    assert b.isEmpty()         == False, "Book is empty!" 

    assert b.removeOrder(9191) == True,  "Removing order '9191' failed!"
    assert b.isBidEmpty()      == True,  "Bid level not empty!" 
    assert b.isAskEmpty()      == False, "Ask level is empty!"
    assert b.isEmpty()         == True,  "Book not empty!" 
    
    b.removeEmptyLevels()
    assert b.isBidEmpty()      == True,  "Bid level not empty!" 
    assert b.isAskEmpty()      == True,  "Ask levle not empty!"
    
    b.addOrder( order=bo )
    b.addOrder( order=ao )

    b.addOrder(BID, 199, 54.12, 1000, 100) # iceberg
    b.addOrder(BID, 111, 54.12,  100, 100)
    
    assert len(b.bid) == 2, "Wrong number of bid level! Expected: 2"
    
    prev_price = 1000*100
    for lprice, level in b.bid.iteritems():
        assert lprice < prev_price, "Order of levels not monotonically decending in price"
        prev_price = lprice

    b.addOrder(ASK, 191,  45.23,  100, 100)
    b.addOrder(ASK, 777,  32.54,  100, 100)
    b.addOrder(ASK, 991,  22.21,  100, 100)
    b.addOrder(ASK, 181, 222.22,  100, 100)
    b.addOrder(ASK, 888,  32.54,  100, 100)
    b.addOrder(ASK,  33,  25.18,  100, 100)
    b.addOrder(ASK, 111,  25.18,  100, 100)

    assert len(b.ask) == 5, "Wrong number of ask level! Expected: 5"

    prev_price = 0*100
    for lprice, level in b.ask.iteritems():
        assert lprice > prev_price, "Order of levels not monotonically increasing in price"
        prev_price = lprice
    
    b.clear()
    assert b.isEmpty() == True, "Book not empty!" 

    print 'OK'
Beispiel #5
0
def createBook():
    bo, ao = createOrders()
    b = Book()

    b.addOrder(order=bo)
    b.addOrder(order=ao)

    b.addOrder(BID, 199, 54.12, 1000, 100)  # iceberg
    b.addOrder(BID, 111, 54.12, 100, 100)

    b.addOrder(ASK, 191, 45.23, 100, 100)
    b.addOrder(ASK, 777, 32.54, 100, 100)
    b.addOrder(ASK, 991, 22.21, 100, 100)
    b.addOrder(ASK, 181, 222.22, 200, 100)  # iceberg
    b.addOrder(ASK, 888, 32.54, 100, 100)
    b.addOrder(ASK, 33, 25.18, 100, 100)
    b.addOrder(ASK, 111, 25.18, 100, 100)

    return b