Example #1
0
class VirtualMarket(object):
    """ Used to evaluates price at which a market order of given volume would be executed
        Since this query might be computationally expensive and done asynchronously,
        we wrap function OrderQueue.evaluateOrderPrice by this class.
        The result will returned in on_matched event with empty 'other' field
        TBD: we make use of on_matched machinery since that is supported in RemoteBook
        but i'm not sure that it is a good design decision.  
    """
    def __init__(self, side, volume):
        self.volume = volume
        self.side = side
        self.on_matched = Event()
        self.on_charged = Event()
        
    def copyTo(self, dst):
        pass # we might copy here the total price
    
    def processIn(self, orderBook):
        def callback((price, volume_unmatched)):
            self.on_matched.fire(self, None, (price, self.volume - volume_unmatched))
            
        orderBook.evaluateOrderPriceAsync(self.side, self.volume, callback)

    @staticmethod
    def Buy(volume): return VirtualMarket(Side.Buy, volume)
    
    @staticmethod
    def Sell(volume): return VirtualMarket(Side.Sell, volume)
Example #2
0
 def __init__(self, tickSize=1, book=None):
     """ Initializes an empty queue with given tickSize 
     and remembers order book the queue belong to if any
     """
     self._tickSize = tickSize   # tick size
     self._book = book           # book the queue belongs to if any
     self.on_best_changed = Event()  # event to be called when the best order changes
     self.on_order_cancelled = Event() # event (orderQueue, cancelledOrder) to be called when an order is cancelled 
     self.reset()
Example #3
0
 def __init__(self, queue, book, link):
     self._queue = queue
     self.book = book
     self._link = link
     self._onBestChanged = bind.Method(self, '_onBestChanged_impl')
     queue.on_best_changed += self._onBestChanged
     self.on_best_changed = Event()
     self.reset()
Example #4
0
 def __init__(self, side, volume):
     """ Initializes order by volume to trade
     """
     self._volume = volume
     self._side = side
     self._cancelled = False
     self._PnL = 0
     # TODO: these events should be replaces by a reference to the trader
     # but in that case we'll have to introduce proxy classes for
     # remote book and virtual orders but it is ok
     self.on_matched = Event()
     self.on_charged = Event()
Example #5
0
class Queue(object):
    
    def __init__(self, queue, book, link):
        self._queue = queue
        self.book = book
        self._link = link
        self._onBestChanged = bind.Method(self, '_onBestChanged_impl')
        queue.on_best_changed += self._onBestChanged
        self.on_best_changed = Event()
        self.reset()
        
    def reset(self):
        self._best = self._queue.best
        self._lastT = 0
        
    @property
    def side(self):
        return self._queue.side
    
    @property
    def lastPrice(self):
        return self._best.price if self._best is not None else None
        
    def _update_impl(self, best):
        self._best = best
        self.on_best_changed.fire(self)

    def _onBestChanged_impl(self, queue):
        best = queue.best
        self._link.send(bind.Method(self, '_update_impl', best))
        
    @property 
    def best(self):
        return self._best
    
    @property
    def empty(self):
        return self._best is None
Example #6
0
class Queue(object):
    """ Queue of limit orders at one side (Sell or Buy).
    It is implemented over a heap so has following comlexity for operations:
    - pushing order: O(logN)
    - accessing to the best order: O(1)
    - popping the best order: O(logN)
    """
    def __init__(self, tickSize=1, book=None):
        """ Initializes an empty queue with given tickSize 
        and remembers order book the queue belong to if any
        """
        self._tickSize = tickSize   # tick size
        self._book = book           # book the queue belongs to if any
        self.on_best_changed = Event()  # event to be called when the best order changes
        self.on_order_cancelled = Event() # event (orderQueue, cancelledOrder) to be called when an order is cancelled 
        self.reset()
        
    def reset(self):
        self._elements = []         # pairs ((signedTicks, arrivalSeqNo), order) kept in a heap
        self._counter = 0           # arrival order counter
        self._lastBest = None       # pair (bestPrice, bestVolume)
        self._lastPrice = None      # last valid price

    @property
    def book(self):
        """ Book the queue belongs to if any
        """
        return self._book

    def notifyIfBestChanged(self):
        """Notifies order queue listeners if the best order has changed
        """
        best = self.best
        bestpv = None if best is None else (best.price, best.volume)
            
        if bestpv != self._lastBest:
            self._lastBest = bestpv
            if bestpv != None:
                self._lastPrice = bestpv[0]
            self.on_best_changed.fire(self)
            
    @property
    def lastPrice(self):
        return self._lastPrice
            
    def __str__(self):
        return type(self).__name__ + "(" + str(self._elements) + ")"

    def __repr__(self):
        return self.__str__()

    def ticks(self, price):
        """ Corrects 'price' with respect to the tick size
        Returns signed integer number of ticks for the price 
        and corrected unsigned order price
        """
        ticks = int(math.ceil(self.side.makePriceSigned(price) / self._tickSize))
        return (+ticks, self.side.makePriceSigned(ticks * self._tickSize))

    def push(self, order):
        """ Pushes 'order' into the queue.
        May correct limit price of the order with respect to the tick size
        May notify listeners about that the best order changed 
        """
        (ticks, correctedPrice) = self.ticks(order.price)
        if order.price != correctedPrice:
            # save corrected price in the order if needed
            order.price = correctedPrice
        heapq.heappush(self._elements, ((ticks, self._counter), order))
        self._counter += 1
        # notify listeners if the best order changed
        self.notifyIfBestChanged()
        
    def cancelOrder(self, order):
        """ To be called when 'order' is marked as cancelled 
        Notifies 'on_order_cancelled' event listeners.
        May fire 'on_best_changed' event
        """
        order.cancel()
        self._makeValid()
        self.notifyIfBestChanged()
        self.on_order_cancelled.fire(self, order)

    def _makeValid(self):
        """ Ensures that the queue is either empty or has a valid order on top
        Valid order == not empty and not cancelled
        Returns True iff the queue is not empty
        """
        while self._elements != []:
            (_, top) = self._elements[0]
            if top.empty or top.cancelled:
                heapq.heappop(self._elements)
            else:
                return True
        return False

    @property
    def empty(self):
        """ Returns True iff queue is empty
        May remove invalid orders from it 
        """
        return not self._makeValid()

    @property
    def best(self):
        """ Returns the best order if any 
        Otherwise returns None 
        """
        return self._elements[0][1] if self._makeValid() else None

    def matchWith(self, other):
        """ Matches an order against our order queue
        Returns True iff the incoming order is matched completely
        The order is considered as market order for the moment
        May notify listeners if the best order changed
        """
        # while there are orders
        while not self.empty:
            # take the best one
            (_, top) = self._elements[0]
            # match the incoming order with our best one
            # and if our best order becomes empty,
            if not other.empty and top.matchWith(other):
                # remove it from the queue
                self._makeValid()
            else:
                # our best order is not matched completely
                break
        self.notifyIfBestChanged()
        return other.empty
    
    @property
    def sorted(self):
        """ Enumerates orders in order of their price 
        Enumeration best M orders requires O(MlogM) operations 
        """
        if self._elements <> []:
            def nth(i):
                return (self._elements[i][0], i)
            grey = [nth(0)]
            while grey <> []:
                (_, idx) = heapq.heappop(grey)
                yield self._elements[idx][1]
                if idx * 2 + 1 < len(self._elements):
                    heapq.heappush(grey, nth(idx * 2 + 1))
                if idx * 2 + 2 < len(self._elements):
                    heapq.heappush(grey, nth(idx * 2 + 2))
    
    @property             
    def sortedPVs(self):
        lastPV = (None, None)
        for x in self.sorted:
            if not x.cancelled and not x.empty:
                if x.price == lastPV[0]:
                    lastPV = (x.price, lastPV[1] + x.volume)
                else: 
                    if lastPV[0] is not None:
                        yield lastPV
                    lastPV = (x.price, x.volume)
        if lastPV[0] is not None:
            yield lastPV
            
    def evaluateOrderPrice(self, volume):
        """ Evaluates price for a potential market order with given 'volume'
        Returns pair (price, volume_unmatched) where 'volume_unmatched' may be positive
        if there is not enough volume in the order queue  
        Complexity of the operation: O(MlogM) where M - number of orders involved       
        """
        price = 0
        for x in self.sorted:
            if volume > 0:
                v = min(volume, x.volume)
                price += x.price * v
                volume -= v
            else:
                break
        return (price, volume)
    
    def getVolumePrices(self, volumes):
        deltas = [volumes[0]] + [volumes[i] - volumes[i-1] for i in range(1, len(volumes))]
        i = 0
        lastPrice = None
        for x in self.sorted:
            v = x.volume
            lastPrice = x.price
            while i < len(deltas) and v > 0:
                if v > deltas[i]:
                    yield (volumes[i], x.price)
                    v -= deltas[i]
                    i += 1
                else:
                    deltas[i] -= v
                    break
            if i == len(deltas):
                return
        if i < len(deltas):
            yield (volumes[i], lastPrice)
            i += 1
        while i < len(deltas):
            yield (volumes[i], None)
            i += 1
        
        
        
        

    def withPricesBetterThan(self, limit, idx=0):
        """ Enumerates orders with price better than or equal to 'limit'
        """
        if len(self._elements) <= idx:
            return
        if not self.side.better(limit, self._elements[idx][1].price):
            yield self._elements[idx][1]
            for x in self.withPricesBetterThan(limit, idx * 2 + 1):
                yield x
            for x in self.withPricesBetterThan(limit, idx * 2 + 2):
                yield x
                
    def volumeWithPriceBetterThan(self, limit):
        """ Returns total volume of orders having price better than or equal to 'limit'
        """
        return sum([x.volume for x in self.withPricesBetterThan(limit)])
Example #7
0
 def __init__(self, intervalFunc):
     Event.__init__(self)
     self._wakeUp = bind.Method(self, '_wakeUp_impl')
     self.intervalFunc = intervalFunc
     self._cancelled = False
Example #8
0
 def __init__(self, side, volume):
     self.volume = volume
     self.side = side
     self.on_matched = Event()
     self.on_charged = Event()
Example #9
0
 def __init__(self, orderbook):
     Event.__init__(self)
     self.orderbook = orderbook
Example #10
0
 def __init__(self, trader):
     Event.__init__(self)
     self.trader = trader
Example #11
0
class Base(object):
    """ Base class for market and limit orders.
    Responsible for:
    - tracking order's volume
    - tracking order's P&L
    - keeping order cancellation flag (does it needed for market orders???)
    - notifying order listeners about order matching
    TBD: split into Cancelable, HavingVolume base classes
    """

    def __init__(self, side, volume):
        """ Initializes order by volume to trade
        """
        self._volume = volume
        self._side = side
        self._cancelled = False
        self._PnL = 0
        # TODO: these events should be replaces by a reference to the trader
        # but in that case we'll have to introduce proxy classes for
        # remote book and virtual orders but it is ok
        self.on_matched = Event()
        self.on_charged = Event()
        
    @property
    def side(self):
        return self._side
        
    def copyTo(self, dst):
        dst._volume = self._volume
        dst._side = self._side
        dst._PnL = self._PnL
        dst._cancelled = self._cancelled

    def __str__(self):
        return type(self).__name__ + "("+self._side+", volume=" + str(self.volume) + ", P&L="+str(self.PnL)+")"

    def __repr__(self):
        return self.__str__()

    @property
    def volume(self):
        """ Volume to trade
        """
        return self._volume
    
    @property 
    def PnL(self):
        """ P&L of the order. 
        positive, if it is a sell side order
        negative, if it is a buy side order
        """
        return self.side.makePriceSigned(self._PnL)

    @property
    def empty(self):
        """ Volume is empty iff its volume is 0
        """
        return self.volume == 0

    @property
    def cancelled(self):
        """ Is order cancelled
        """
        return self._cancelled
    

    def cancel(self):
        """ Marks order as cancelled. Notifies the order book about it
        """
        self._cancelled = True

    #--------------------------------- these methods are to be called by order book
            
    def charge(self, price): 
        self.on_charged.fire(price)

    def onMatchedWith(self, other, (price,volume)):
        """ Called when the order is matched with another order
        other - other order
        price - price at which the match was done
        volume - volume of the match.
        In this method we correct order volume and P&L 
        and notify order listener about the match
        """
        self._volume -= volume
        self._PnL += volume * price
        #print "OrderMatched:", self, other, (price, volume)
        self.on_matched.fire(self, other, (price, volume))