def pop_lowest_sell_order(r: redis.client.Redis) -> Tuple[Order, bool]:
    lowest_sell = r.zrange(redis_sell_prices_name,
                           0,
                           0,
                           desc=False,
                           withscores=True)
    if len(lowest_sell) == 0:
        return (None, False)
    else:
        (sell_order_id, sell_price) = lowest_sell[0]
        sell_order_size = int(
            r.hget(redis_order_sizes_name, sell_order_id).decode('utf-8'))
        sell_order_account_name = r.hget(redis_account_names_name,
                                         sell_order_id)

        successful_remove = remove_price_and_size(r, redis_sell_prices_name,
                                                  redis_order_sizes_name,
                                                  redis_account_names_name,
                                                  sell_order_id)
        if successful_remove:
            sell_order_id = sell_order_id.decode('utf-8')
            sell_order_account_name = sell_order_account_name.decode('utf-8')
            order = Order(sell_order_account_name, sell_order_id, "Sell",
                          sell_order_size, sell_price)
            return (order, True)
        else:
            return (None, False)
def pop_highest_buy_order(r: redis.client.Redis) -> Tuple[Order, bool]:
    highest_buy = r.zrange(redis_buy_prices_name,
                           0,
                           0,
                           desc=True,
                           withscores=True)
    if len(highest_buy) == 0:
        return (None, False)
    else:
        (buy_order_id, buy_price) = highest_buy[0]
        buy_order_size = int(
            r.hget(redis_order_sizes_name, buy_order_id).decode('utf-8'))
        buy_order_account_name = r.hget(redis_account_names_name, buy_order_id)
        successful_remove = remove_price_and_size(r, redis_buy_prices_name,
                                                  redis_order_sizes_name,
                                                  redis_account_names_name,
                                                  buy_order_id)
        if successful_remove:
            buy_order_id = buy_order_id.decode('utf-8')
            buy_order_account_name = buy_order_account_name.decode('utf-8')
            order = Order(buy_order_account_name, buy_order_id, "Buy",
                          buy_order_size, buy_price)
            return (order, True)
        else:
            return (None, False)
def get_all_orders(r: redis.client.Redis):
    # Order sizes and prices are stored in different sorted set/ hashset
    # May need to investigate if this can handle in high-frequency situation
    order_sizes = r.hgetall(redis_order_sizes_name)
    user_account_names = r.hgetall(redis_account_names_name)
    sell_prices = r.zrange(redis_sell_prices_name, 0, -1, withscores=True)
    buy_prices = r.zrange(redis_buy_prices_name, 0, -1, withscores=True)

    orders = [
        Order(username=user_account_names[order_id].decode('utf-8'),
              order_id=order_id.decode('utf-8'),
              side="Sell",
              size=int(order_sizes[order_id].decode('utf-8')),
              price=price) for order_id, price in sell_prices
    ] + [
        Order(username=user_account_names[order_id].decode('utf-8'),
              order_id=order_id.decode('utf-8'),
              side="Buy",
              size=int(order_sizes[order_id].decode('utf-8')),
              price=price) for order_id, price in buy_prices
    ]
    return orders
def zpop(r: redis.client.Redis, name, desc):
    try:
        r.watch(name)
        zrange_result = r.zrange(name, 0, 0, desc=desc)
        if len(zrange_result) == 0:
            return (None, False)
        result = zrange_result[0]
        p = r.pipeline()
        p.watch(name)
        p.multi()
        p.zrem(name, result)
        p.execute()
        return (result, True)
    except redis.WatchError as e:
        print(e)
        return (None, False)