예제 #1
0
class ConsistHash(object):
    def __init__(self, size=0xffff):
        self.size = size # set consistent hash circul size
        self.rbt = RBTree()  # red black tree

    def insert_host(self, host):
        host_id = host.get_id(self.size)
        self.rbt.insert(host_id, host)

    def remove_host(self, host):
        host_id = host.get_id(self.size)
        self.rbt.remove(host_id)

    @staticmethod
    def _find_upper(root, elem):
        if root is None:
            return -1

        if elem == root.key:
            return root.key
        elif elem < root.key:
            maybe_max = find_upper(root.left, elem)
            if _not_exists(maybe_max):
                return root.key
            return maybe_max
        else:
            maybe_max = find_upper(root.right, elem)
            if _not_exists(maybe_max):
                return -1
            return maybe_max

    def find_host(self, id):
        id %= self.size
        idx = self._find_upper(self.rbt._root, id)
        if idx == -1:  # id larger than max id
            # assert tree is not empty
            return self.rbt.min_item()[1]
        return self.rbt.get_value(idx)
class OrderBook:
    def __init__(self):
        """
        Instantiate OrderBook object which uses RBTree as main data structure
        """
        self.bids = RBTree()
        self.asks = RBTree()
        # keep track of max and min for bid and ask orders respectively
        self.bid_max = -math.inf
        self.bid_min = math.inf
        self.ask_max = -math.inf
        self.ask_min = math.inf

    def __repr__(self):
        """
        Return a string representation of OrderBook object

        :return: a string describing OrderBook object
        :rtype: str
        """
        return ("Bids Representation: \n"
                "{}\n"
                "Asks Representation: \n"
                "{}\n"
                "Current best bid price is {}\n"
                "Current best ask price is {}\n"
                "Current bid-ask spread is {}".format(str(self.bids),
                                                      str(self.asks),
                                                      str(self.bid_max),
                                                      str(self.ask_min),
                                                      str(self.get_spread())))

    def __eq__(self, other):
        """
        Return True iff self and other have exactly the same bids and asks attributes

        :param other: Any object used for comparison
        :type other: Any
        :return: whether self and other are the same
        :rtype: bool
        """
        if not type(self) == type(other):
            return False
        return self.bids == other.bids and self.asks == other.asks

    def get_spread(self):
        """
        Calculate the spread from best bid and ask

        :return: current spread on OrderBook
        :rtype: float
        """
        return self.ask_min - self.bid_max

    def get_midpoint(self):
        """
        Calculate mid point price from best bid and ask

        :return: current mid point price
        :rtype: float
        """
        return (self.ask_min + self.bid_max) / 2

    def get_liquidity(self):
        """
        Calculate the liquidity for both bid and ask side. Total volume of liquidity quoted on bids and asks within 2x
        the spread from the best bid and the best ask, in units of the base currency.

        :return: current bid and ask liquidity
        :rtype: float, float
        """
        spread = self.get_spread()
        lower_bound_bid = self.bid_max - 2 * spread
        upper_bound_ask = self.ask_min + 2 * spread
        # get orders in the liquidity range using TreeSlice
        liquidity_bids_tree = self.bids[lower_bound_bid:self.bid_max + 1]
        liquidity_asks_tree = self.asks[self.ask_min:upper_bound_ask]
        bid_liquidity = sum(liquidity_bids_tree.values())
        ask_liquidity = sum(liquidity_asks_tree.values())
        return bid_liquidity, ask_liquidity

    def update_order(self, price, amount):
        """
        Update OrderBook by inserting a new price as key and amount as value to RBTree. If a price (key) already exists,
        update its corresponding amount (value) to new amount.

        :param price: price of a limit order
        :type price: float
        :param amount: amount of the limit order
        :type amount: float
        :return: None
        :rtype: NoneType
        """
        # bid order
        if amount > 0:
            # insert() method updates amount if price exists, add new Node with price and amount otherwise
            self.bids.insert(price, amount)
            # update max and min
            if price > self.bid_max:
                self.bid_max = price
            if price < self.bid_min:
                self.bid_min = price
        # ask order
        elif amount < 0:
            self.asks.insert(price, -amount)
            if price > self.ask_max:
                self.ask_max = price
            if price < self.ask_min:
                self.ask_min = price
        # amount is 0, all liquidity at price level consumed
        else:
            # remove the order from bids
            if price in self.bids:
                self.bids.pop(price)
                # update max and min by searching RBTree, time complexity O(log(n))
                if price == self.bid_max:
                    self.bid_max = self.bids.max_key()
                elif price == self.bid_min:
                    self.bid_min = self.bids.min_key()
            # remove the order from asks
            if price in self.asks:
                self.asks.pop(price)
                if price == self.ask_max:
                    self.ask_max = self.asks.max_key()
                elif price == self.ask_min:
                    self.ask_min = self.asks.min_key()
예제 #3
0
                return -1
            return maybe_max

    def find_host(self, id):
        id %= self.size
        idx = self._find_upper(self.rbt._root, id)
        if idx == -1:  # id larger than max id
            # assert tree is not empty
            return self.rbt.min_item()[1]
        return self.rbt.get_value(idx)


if __name__ == "__main__":
    rbt = RBTree()
    for i in range(0, 30, 2):
        rbt.insert(i, "{}".format(i))
    print(find_next(rbt._root, 3))
    print(find_next(rbt._root, 4))
    print(find_next(rbt._root, 5))
    print(find_next(rbt._root, 21))
    print(find_lower(rbt._root, 10)) # should be 10
    print(find_lower(rbt._root, 11)) # should be 10
    print(find_lower(rbt._root, 9)) # should be 8
    print(find_lower(rbt._root, 7)) # should be 6
    print(find_lower(rbt._root, 5)) # should be 4
    print(find_lower(rbt._root, 3)) # should be 2
    print(find_lower(rbt._root, 1)) # should be 0
    print(find_lower(rbt._root, 0)) # should be 0
    print(find_lower(rbt._root, -2)) # should be -1
    print(find_upper(rbt._root, 10)) # should be 10
    print(find_upper(rbt._root, 11)) # should be 12