Ejemplo n.º 1
0
def scan_1D(result,
            d,
            self_edges=False,
            weight=False,
            bound=None,
            handling=None,
            memory=False):
    # recover sim parameters
    N = len(result[0][0])  # "N" = N + 1
    D = len(result[0])
    P = len(result)

    G = []  # list of graphs

    # Each time
    for t in range(N):
        # copy previous matrix or start fresh as appropriate
        if t is 0 or memory is False:
            G.append(nx.Graph())
        else:
            G.append(G[t - 1].copy())

        G[t].add_nodes_from(range(P))

        idx = FastAVLTree()
        # insert all points not out of bounds
        for i in range(P):
            I = result[i][0][t]
            if I < 999999999.0:
                idx.insert(I, i)

        for i in range(P):
            I = result[i][0][t]
            if I < 999999999.0:
                minimum = I - d
                maximum = I + d
                # get all results within range
                hits = [v for (k, v) in idx.item_slice(minimum, maximum)]
                if handling is "Torus" and maximum > bound:
                    hits += [
                        v for (k, v) in idx.item_slice(0, maximum % bound)
                    ]
                if handling is "Torus" and minimum < 0:
                    hits += [
                        v for (k, v) in idx.item_slice(minimum % bound, bound)
                    ]
                for j in hits:
                    if self_edges or i != j:
                        G[t].add_edge(i, j, weight=1)
                    # add something to handle weight case here
        stdout.write(".")
        stdout.flush()
    print("")
    return G
Ejemplo n.º 2
0
class AkashicRecord(object):
    """
    Database of Tumblr Post

    get by id
    sorted with unix_timestamp
    viewed flag.
    new note check
  """

    def __init__(self):
        self.impl = FastAVLTree()

    def get(self, post_id):
        return self.impl.get(post_id)

    def put(self, post):
        assert isinstance(post, Post)
        return self.impl.insert(post.id, post)

    def get_after(self, start):
        pass
Ejemplo n.º 3
0
class OrderBook:
    """Limit order book able to process LMT and MKT orders
        MKT orders are disassembled to LMT orders up to current liquidity situation
    """

    def __init__(self):
        # AVL trees are used as a main structure due its optimal performance features for this purpose

        self._participants = FastAVLTree()
        self._order_owners = FastAVLTree() # Assigning ID -> Owner

        self._asks = FastAVLTree()  # MIN Heap
        self._bids = FastAVLTree()  # MAX Heap
        self._price_ids = FastAVLTree()  # Assigning ID -> Price

        self._total_ask_size = 0 # For monitoring purpose
        self._total_bid_size = 0 # For monitoring purpose

        self._last_order_id = 0 # Increases with each order processed
        self._cleared_orders_count = 0 # For monitoring purpose
        self._total_volume_trad = 0 # For monitoring purpose
        self._total_volume_pending = 0 # For monitoring purpose


    def __getstate__(self):
        """ Whole book could be repopulated from dict containing class attributes """

        return self.__dict__

    def __setstate__(self, state):
        """ Book repopulation (recovery) """

        for at_name, at_val in state.items():
            setattr(self, at_name, at_val)

    def _get_order_id(self):
        """ Orders id managment """

        self._last_order_id += 1
        return self._last_order_id

    def _balance(self, trades_stack):
        """ Executes trades if it finds liquidity for them """

        # No liquidity at all
        if self._asks.is_empty() or self._bids.is_empty():
            return trades_stack

        min_ask = self._asks.min_key()
        max_bid = self._bids.max_key()

        # Check liquidity situation
        if max_bid >= min_ask:
            ask_orders = self._asks.get(min_ask)
            bid_orders = self._bids.get(max_bid)

            for ask_order in ask_orders:
                for bid_order in bid_orders:
                    if not ask_order in ask_orders or not bid_order in bid_orders:
                        continue

                    trad = min(ask_orders[ask_order], bid_orders[bid_order])

                    ask_orders[ask_order] -= traded
                    bid_orders[bid_order] -= traded

                    self._total_ask_size -= traded
                    self._total_bid_size -= traded

                    self._total_volume_trad += traded
                    self._total_volume_pending -= 2 * traded

                    ask_owner = self._order_owners[ask_order]
                    bid_owner = self._order_owners[bid_order]

                    # Buy side order fully liquidated
                    if bid_orders[bid_order] == 0:
                        # print("BID ORDER LIQUIDATED")
                        self._cleared_orders_count += 1
                        del bid_orders[bid_order]
                        del self._price_ids[bid_order]

                        del self._order_owners[bid_order]
                        owner_ids = self._participants[bid_owner]
                        owner_ids.remove(bid_order)

                        del self._participants[bid_owner]
                        self._participants.insert(bid_owner, owner_ids)

                    # Sell side order fully liquidated
                    if ask_orders[ask_order] == 0:
                        # print("ASK ORDER LIQUIDATED")
                        self._cleared_orders_count += 1
                        del ask_orders[ask_order]
                        del self._price_ids[ask_order]

                        del self._order_owners[ask_order]
                        owner_ids = self._participants[ask_owner]
                        owner_ids.remove(ask_order)

                        del self._participants[ask_owner]
                        self._participants.insert(ask_owner, owner_ids)

                    # Inform sides about state of their orders
                    trades_stack.append((0, traded, max_bid))
                    trades_stack.append((1, ask_order, traded, max_bid, ask_owner, 'ask'))
                    trades_stack.append((1, bid_order, traded, max_bid, bid_owner, 'bid'))

            # Whole ASK price level were liquidated, remove it from three and let it rebalance
            if self._asks[min_ask].is_empty():
                # print("ASK level liquidated")
                del self._asks[min_ask]

            # Whole BID price level were liquidated, remove it from three and let it rebalance
            if self._bids[max_bid].is_empty():
                # print("BID level liquidated")
                del self._bids[max_bid]
        else:
            return trades_stack

        return self._balance(trades_stack)

    def _submit_mkt(self, side, size, pi_d):
        """ Find liquidity for mkt order - put multiple lmt orders to extract liquidity for order execution """

        olst = []
        trades_stack = []

        while size > 0:
            if side == 'ask':
                second_side_size = self.bid_size
                second_side_price = self.bid
            else:
                second_side_size = self.ask_size
                second_side_price = self.ask

            # We could only taky liquidity which exists
            trade_size = min([second_side_size, size])
            olst.append(self._submit_lmt(side, trade_size, second_side_price, pi_d))
            trades_stack = self._balance(trades_stack)

            size -= trade_size

        return 0, trades_stack


    def _submit_lmt(self, side, size, price, pi_d):
        """ Submits LMT order to book """

        # Assign order ID
        order_id = self._get_order_id()

        # Pending volume monitoring
        self._total_volume_pending += size
        self._price_ids.insert(order_id, (price, side))

        # Keep track of participant orders, book will be asked for sure
        if pi_d not in self._participants:
            self._participants.insert(pi_d, [order_id])
        else:
            owner_trades = self._participants.get(pi_d, [])
            owner_trades.append(order_id)

        self._order_owners.insert(order_id, pi_d)

        # Assign to right (correct) side
        if side == 'ask':
            self._total_ask_size += size
            ask_level = self._asks.get(price, FastAVLTree())
            ask_level.insert(order_id, size)

            if price not in self._asks:
                self._asks.insert(price, ask_level)
        else:  # bid
            self._total_bid_size += size
            bid_level = self._bids.get(price, FastAVLTree())
            bid_level.insert(order_id, size)

            if price not in self._bids:
                self._bids.insert(price, bid_level)

        return order_id

    def cancel(self, order_id):
        """ Cancel order """

        # Finds and cancels order

        order = self._price_ids[order_id]

        if order[1] == 'ask':
            del self._asks[order[0]][order_id]

            if self._asks[order[0]].is_empty():
                del self._asks[order[0]]
        else:
            del self._bids[order[0]][order_id]

            if self._bids[order[0]].is_empty():
                del self._bids[order[0]]

    @property
    def ask_size(self):
        """ Volume waiting on ask side bottom level - liquidity level size for ask price """

        best_ask = self.gmd(1)[0]

        if len(best_ask) == 0:
            return 0
        else:
            return best_ask[0][1]

    @property
    def total_ask_size(self):
        return self._total_ask_size

    @property
    def bid_size(self):
        """ Volume waiting on bid side top level - liquidity level size for bid price """

        best_bid = self.gmd(1)[1]
        if len(best_bid) == 0:
            return 0
        else:
            return best_bid[0][1]

    @property
    def total_volume_traded(self):
        """ Total trad volume """

        return self._total_volume_traded

    @property
    def total_volume_pending(self):
        """ Total size of orders in whole book """

        return self._total_volume_pending

    @property
    def total_bid_size(self):
        return self._total_bid_size

    @property
    def ask(self):
        """ Best ask """

        try:
            return self.gmd(1)[0][0][0]
        except:
            return -1

    @property
    def bid(self):
        """ Best bid """

        try:
            return self.gmd(1)[1][0][0]
        except:
            return -1

    @property
    def spread(self):
        """ Difference between ask and bid """

        return self.ask - self.bid

    def get_participant_orders(self, pi_d):
        """ Orders of given participant """

        olst = self._participants.get_value(pi_d)

        order_prices = {}
        for order_id in olst:
            order = self._price_ids.get_value(order_id)

            if order[1] == 'ask':
                order_size = self._asks.get_value(order[0]).get_value(order_id)
            else:
                order_size = self._bids.get_value(order[0]).get_value(order_id)

            # price, side, size
            order_prices[order_id] = (order[0], order[1], order_size)

        return olst, order_prices

    def submit_order(self, order_type, side, size, price, pi_d):
        """ Abstraction on order placement - boht LMT and MKT """

        if order_type == 'lmt':
            order_id = self._submit_lmt(side, size, price, pi_d)
            trades = self._balance([])
            return order_id, trades

        if order_type == 'mkt':
            second_side_ask = 0
            if side != 'ask':
                second_side_ask = self._total_ask_size
            else:
                second_side_ask = self._total_bid_size

            if second_side_ask >= size:
                return self._submit_mkt(side, size, pi_d)
            else:
                # Insufficient liquidity
                return -1, []

    def gmd(self, depth):
        """ Liquidity levels size for both bid and ask """

        ask_side = []
        if not self._asks.is_empty():
            for price in self._asks.keys():
                ask_level = self._asks.get(price)
                ask_size = 0
                for order_id in ask_level.keys():
                    # print(ask_size, order_id, ask_level.get(order_id))
                    ask_size += ask_level.get(order_id)

                ask_side.append([price, ask_size])

                if len(ask_side) >= depth:
                    break

        bid_side = []
        if not self._bids.is_empty():
            for price in self._bids.keys(reverse=True):
                bid_level = self._bids.get(price)
                bid_size = 0
                for order_id in bid_level.keys():
                    bid_size += bid_level.get(order_id)

                bid_side.append([price, bid_size])

                if len(bid_side) >= depth:
                    break

        return [ask_side, bid_side]
Ejemplo n.º 4
0

def ok():
    if max_tree.is_empty():
        return True
    else:
        difference = max_tree.max_item()[0][0] \
                     - min_tree.min_item()[0][0]
        return difference <= k


start, end = 0, 0

while end < len(A):
    # extend the sequence until violation reached.
    while end < len(A) and ok():
        best_sequence_length = max(best_sequence_length, end - start)
        min_tree.insert((A[end], end), None)
        max_tree.insert((A[end], end), None)
        end += 1

    if ok():
        best_sequence_length = max(best_sequence_length, end - start)

    # move starting position by 1.
    min_tree.remove((A[start], start))
    max_tree.remove((A[start], start))
    start += 1

print best_sequence_length
Ejemplo n.º 5
0
class Scoreboard():
    """
        Keeps Scoreboard info and allows highly efficient checks.

        On the one hand, keeps a hash table (dict) to the updated information of each client.
        On the other hand, keeps a lookup accelerator that allows to retrieve client score sorting with logaritmic
         complexity (O(log N)).
    """
    def __init__(self):
        # Clients that have reported score
        #   <key> :<value> -> <client_id> : <client>
        #
        #   where:
        #
        #           <client_id> (int) : Id that uniquelly specifies the client.
        #           <client> (Client) : Information of the client (including score)
        #
        self.clients = {}

        # AVL tree in which each node is a list of Client instances (i.e., all the clients with the same score)
        # Allows to access sorted info in O(log(N))
        self.sorted_clients = FastAVLTree()

    def reset(self):
        """
            Resets all info.

        :return: None
        """
        self.clients = {}
        self.sorted_clients = FastAVLTree()

    def get(self, client_id):
        """
            Returns the current score of the specified client.

        :param client_id: (int) The id of the client.
        :return: (int) The current score. None if not found.
        """
        try:
            result = self.clients[client_id]
        except KeyError:
            result = None

        return result

    def update(self, client_info):
        """
            Modifies the client total score.

        :param client_info: (dict) A JSON submitted by the client, as specified in the Code Challenge:

                Examples:

                            {"user": 123, "total": 250}
                            {"user": 456, "score": "+10"}
                            {"user": 789, "score": "-20"}

        :return: (bool) True if successfully updated; False otherwise.
        """
        try:
            #
            # Handle first report/old sorting order
            #
            client_id = int(client_info["user"])

            if client_id not in self.clients:
                # First client report
                self.clients[client_id] = Client(client_id)

            else:
                # Remove client prior score, since it is going to be modified
                prior_score = self.clients[client_id].score
                if len(self.sorted_clients[prior_score]) > 1:
                    # There are other clients with that score
                    self.sorted_clients[prior_score].remove(
                        self.clients[client_id])
                else:
                    # The only one with that score
                    del self.sorted_clients[prior_score]

            #
            # Compute/Update new score
            #
            try:
                result = self.clients[client_id].total(client_info["total"])
            except KeyError:
                # Try with relative update
                result = self.clients[client_id].relative(client_info["score"])

            #
            # Update/restore client sorting order
            #
            new_score = self.clients[client_id].score
            if new_score not in self.sorted_clients:
                # First client with that score. Initialize an empty list to hold all users with that same score.
                self.sorted_clients.insert(new_score, [])

            self.sorted_clients[new_score].append(self.clients[client_id])

        except (KeyError, ValueError):
            # Invalid client_info
            result = False

        return result

    def top(self, top_size):
        """
            Returns the clients that occupy the specified number of top ranking positions (i.e., those with the higher
                score values), according to the absolute ranking.

            IMPLEMENTATION NOTE: If more than one clients are tied in a given position the returned list considers them
                as a single ranking position.

                Example: [{"user": 123, "total": 100}, {"user": 456, "total": 200}, {"user": 789, "total": 100}]

                    The top-2 (i.e., top_size = 2) is:

                    [1st-{"user": 456, "total": 200},
                     2nd-{"user": 123, "total": 100}
                     2nd-{"user": 789, "total": 100}
                    ]

        :param top_size: (int) Number of higher ranking positions to retrieve.
        :return: (list of Client) The clients that occupies the specified ranking positions.
        """
        result = []
        try:
            top_positions = self.sorted_clients.nlargest(top_size)
            for position in top_positions:
                result.extend(position[1])
        except TypeError:
            pass

        return result

    def relative_top(self, ranking_position, scope_size):
        """
            Returns the clients in the specified scope around the one that occupy the specified ranking position of
                top ranking positions (i.e., those with the higher score values), according to the absolute ranking.
                The scope around a given ranking position is defined as the clients that occupy the scope_size ranking
                positions before the client that occupies the specified ranking position, followed by the scope_size
                ranking positions before the client that occupies the specified ranking position.

                Example:

                [{"user": 1, "total": 150}, {"user": 2, "total": 200}, {"user": 3, "total": 100},
                 {"user": 4, "total": 300}, {"user": 5, "total": 120}, {"user": 6, "total": 90}]

                The relative_top(ranking_position=3, scope_size=2) is the following:

                [{"user": 4, "total": 300}
                 {"user": 2, "total": 200},
                 {"user": 1, "total": 150},
                 {"user": 5, "total": 120},
                 {"user": 3, "total": 100}
                ]

                Since the 3rd ranking position is occupied by {"user": 1, "total": 150}, the full requested positions
                are: 1st, 2nd, 3rd, 4th, and 5th (i.e., from (ranking_position - scope_size) to
                (ranking_position + scope_size)

            IMPLEMENTATION NOTE: If more than one clients are tied in a given position the returned list considers them
                as a single ranking position. (same as with top but for relative ranking)

        :param ranking_position: (int) Ranking position to retrieve scope around. Must be a positive value, from 1 to N.
        :param scope_size: (int) Scope size (see explanation above). Must be a positive value.
        :return: (list of Client) The clients that occupies the specified ranking positions.
        """
        result = []

        if ranking_position >= 1 and scope_size >= 0:

            try:
                top_positions = self.sorted_clients.nlargest(
                    len(self.sorted_clients))

                if (ranking_position - scope_size >
                        1) and (ranking_position - scope_size < len(
                            self.sorted_clients)):
                    #
                    # Not truncated on the left (high scores)
                    #
                    if ranking_position + scope_size <= len(
                            self.sorted_clients):
                        #
                        #  Full range exists
                        #

                        top_positions = top_positions[ranking_position -
                                                      scope_size -
                                                      1:ranking_position +
                                                      scope_size]

                    else:
                        #
                        # Range truncated on the right (not enough low scores)
                        #

                        top_positions = top_positions[ranking_position -
                                                      scope_size -
                                                      1:len(top_positions)]

                elif ranking_position - scope_size < 1:
                    #
                    # Range truncated on the left (not enough high scores)
                    #
                    if ranking_position + scope_size <= len(
                            self.sorted_clients):
                        #
                        #  Only truncated on the left (enough low scores)
                        #

                        top_positions = top_positions[0:ranking_position +
                                                      scope_size]

                    else:
                        #
                        # Range truncated both on the left and on the right (not enough neither low nor high scores)
                        #
                        # That is, all the positions.
                        #
                        pass

                for position in top_positions:
                    result.extend(position[1])

            except TypeError:
                pass

        return result
Ejemplo n.º 6
0
def get_tree(dico, size):
    tree = FastAVLTree()
    for i in range(size):
        tree.insert(dico[i],None)