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
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
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]
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
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
def get_tree(dico, size): tree = FastAVLTree() for i in range(size): tree.insert(dico[i],None)