Example #1
0
class OrderBook:

    def __init__(self, bids=[], asks=[]):
        self.bids = SortedList(bids, key = lambda order: -order.price)
        self.asks = SortedList(asks, key = lambda order: order.price)

    def __len__(self):
        return len(self.bids) + len(self.asks)

    def best_bid(self):
        if len(self.bids) > 0:
            return self.bids[0].price
        else:
            return 0

    def best_ask(self):
        if len(self.asks) > 0:
            return self.asks[0].price
        else:
            return 0

    def add(self, order):
        if order.side == 'buy':
            index = self.bids.bisect_right(order)
            self.bids.insert(index, order)
        elif order.side == 'sell':
            index = self.asks.bisect_right(order)
            self.asks.insert(index, order)

    def remove(self, order):
        if order.side == 'buy':
            self.bids.remove(order)
        elif order.side == 'sell':
            self.asks.remove(order)
Example #2
0
class FastSplitter2d:
    def __init__(self, max_size=5000, chunk_count=5):
        self.max_size = max_size
        self.max_x = 0
        self.points = SortedList(key=lambda p: -p[1])
        self.chunk_count = chunk_count

    def add_to_pack(self, p):
        self.max_x = max(self.max_x, p[0])
        new_pos = self.points.bisect_right(p)
        self.points.insert(new_pos, p)

        offset = 0
        bs_vec = []
        while offset < len(self.points):
            bs = self.max_size // (self.max_x + self.points[offset][1])
            bs = min(len(self.points) - offset, bs)
            bs_vec.append(bs)
            offset += bs

        return new_pos, bs_vec

    def make_chunk_gen(self, points):
        prev_bs_vec = [0]
        for p in sorted(list(points), key=lambda p: p[0], reverse=True):
            new_pos, bs_vec = self.add_to_pack(p)

            if len(bs_vec) > len(prev_bs_vec):
                if len(prev_bs_vec) >= self.chunk_count:
                    self.points.pop(new_pos)
                    offset = 0
                    for sz in prev_bs_vec:
                        yield self.points[offset:offset + sz]
                        offset += sz
                    self.points.clear()
                    self.points.add(p)
                    prev_bs_vec = [1]
                    self.max_x = p[0]
            prev_bs_vec = bs_vec
        offset = 0
        for sz in prev_bs_vec:
            yield self.points[offset:offset + sz]
            offset += sz
def test_insert_valueerror4():
    slt = SortedList(range(10), load=4)
    slt.insert(5, 7)
def test_insert():
    slt = SortedList(range(10), load=4)
    slt.insert(-1, 9)
    slt._check()
    slt.insert(-100, 0)
    slt._check()
    slt.insert(100, 10)
    slt._check()

    slt = SortedList(load=4)
    slt.insert(0, 5)
    slt._check()

    slt = SortedList(range(5, 15), load=4)
    for rpt in range(8):
        slt.insert(0, 4)
        slt._check()

    slt = SortedList(range(10), load=4)
    slt.insert(8, 8)
    slt._check()
Example #5
0
def test_insert_valueerror4():
    slt = SortedList(range(10), load=4)
    slt.insert(5, 7)
Example #6
0
def test_insert():
    slt = SortedList(range(10), load=4)
    slt.insert(-1, 9)
    slt._check()
    slt.insert(-100, 0)
    slt._check()
    slt.insert(100, 10)
    slt._check()

    slt = SortedList(load=4)
    slt.insert(0, 5)
    slt._check()

    slt = SortedList(range(5, 15), load=4)
    for rpt in range(8):
        slt.insert(0, 4)
        slt._check()

    slt = SortedList(range(10), load=4)
    slt.insert(8, 8)
    slt._check()
Example #7
0
class PortfolioHistory(SortedDict):
    """Represents the historical holdings of a portfolio.

  Usually this class should only be instantiated by GetPortfolio.
  """
    def __init__(self, user_id):
        super(PortfolioHistory, self).__init__()
        self._user_id = user_id
        with sql.GetCursor() as cursor:
            cursor.execute(
                'SELECT type, timestamp, in_symbol, in_amount, out_symbol, out_amount '
                'FROM transactions where user_id = %s' % user_id)
            self._transactions = SortedList([
                Transaction(type=t[0],
                            timestamp=t[1],
                            in_symbol=t[2],
                            in_amount=t[3],
                            out_symbol=t[4],
                            out_amount=t[5]) for t in cursor.fetchall()
            ])
        self.InitFromTransactions()

    def InitFromTransactions(self):
        # TODO(brandonsalmon): If it becomes necessary, we can greatly improve
        # the performance of !buy, !sell, !trade, by adding a transaction cursor
        # and not reinitializing all transactions every time.
        self.clear()
        for t in self._transactions:
            if t.type == "INIT":
                self[t.timestamp] = {}
                continue
            if t.timestamp not in self:
                bisect_point = self.bisect(t.timestamp)
                if (bisect_point) is 0:
                    copy = {}
                else:
                    copy = self[self._list[bisect_point - 1]].copy()
                self[t.timestamp] = copy
            if t.in_symbol:
                if t.in_symbol not in self[t.timestamp]:
                    self[t.timestamp][t.in_symbol] = 0
                self[t.timestamp][t.in_symbol] += t.in_amount
            if t.out_symbol:
                if t.out_symbol not in self[t.timestamp]:
                    raise Exception(
                        '%s tried to remove coin %s they didn\'t own' %
                        (self._user_id, t.out_symbol))
                self[t.timestamp][t.out_symbol] -= t.out_amount
                if self[t.timestamp][t.out_symbol] < 1e-10:
                    del self[t.timestamp][t.out_symbol]

    def CreationDate(self):
        return self._transactions[0].timestamp

    def GetValueList(self, t_list):
        return [self.Value(t) for t in t_list]

    def GetChange(self, timestamp=None, timedelta='24h'):
        dt = datetime.fromtimestamp(timestamp) if timestamp else datetime.now()
        old_timestamp = (dt - util.GetTimeDelta(timedelta)).timestamp()
        old_value = self.Value(old_timestamp)
        new_value = self.Value(timestamp)
        if old_value != 0:
            return '%.2f%s' % (100 * (new_value - old_value) / old_value, '%')
        elif new_value == 0:
            return "No change"
        elif new_value > 0:
            return "+Inf%"
        else:
            return "-Inf%"

    def ClearRemote(self):
        with sql.GetCursor() as cursor:
            cursor.execute('DELETE FROM transactions where user_id = %s' %
                           self._user_id)
        self.clear()

    def Init(self, tuples, timestamp=None):
        """Takes a list of tuples of (symbol, amount)."""
        timestamp = int(timestamp if timestamp else time.time())
        with sql.GetCursor() as cursor:
            cursor.execute(
                'INSERT INTO transactions (user_id, type, timestamp) '
                'values (%s, "%s", %s)' % (self._user_id, "INIT", timestamp))

        transaction = Transaction(type="INIT", timestamp=timestamp)
        self._transactions.insert(self._transactions.bisect(transaction),
                                  transaction)
        for t in tuples:
            self.Buy(t[0], t[1], timestamp, init=False)
        self.InitFromTransactions()

    def Buy(self, symbol, amount, timestamp=None, init=True):
        timestamp = int(timestamp if timestamp else time.time())
        with sql.GetCursor() as cursor:
            cursor.execute(
                'INSERT INTO transactions (user_id, type, timestamp, in_symbol, in_amount) '
                'values (%s, "%s", %s, "%s", %s)' %
                (self._user_id, "BUY", timestamp, symbol.upper(), amount))
        transaction = Transaction(type="BUY",
                                  timestamp=timestamp,
                                  in_symbol=symbol.upper(),
                                  in_amount=amount)
        self._transactions.insert(self._transactions.bisect(transaction),
                                  transaction)
        if init:
            self.InitFromTransactions()

    def Sell(self, symbol, amount, timestamp=None):
        timestamp = int(timestamp if timestamp else time.time())
        with sql.GetCursor() as cursor:
            cursor.execute(
                'INSERT INTO transactions (user_id, type, timestamp, out_symbol, out_amount) '
                'values (%s, "%s", %s, "%s", %s)' %
                (self._user_id, "SELL", timestamp, symbol.upper(), amount))
        transaction = Transaction(type="SELL",
                                  timestamp=timestamp,
                                  out_symbol=symbol.upper(),
                                  out_amount=amount)
        self._transactions.insert(self._transactions.bisect(transaction),
                                  transaction)
        self.InitFromTransactions()

    def Trade(self,
              in_symbol,
              in_amount,
              out_symbol,
              out_amount,
              timestamp=None):
        timestamp = int(timestamp if timestamp else time.time())
        with sql.GetCursor() as cursor:
            cursor.execute(
                'INSERT INTO transactions (user_id, type, timestamp, in_symbol, in_amount, '
                'out_symbol, out_amount) values (%s, "%s", %s, "%s", %s, "%s", %s)'
                % (self._user_id, "SELL", timestamp, in_symbol.upper(),
                   in_amount, out_symbol.upper(), out_amount))
        transaction = Transaction(type="TRADE",
                                  timestamp=timestamp,
                                  out_symbol=out_symbol.upper(),
                                  out_amount=out_amount,
                                  in_symbol=in_symbol.upper(),
                                  in_amount=in_amount)
        self._transactions.insert(self._transactions.bisect(transaction),
                                  transaction)
        self.InitFromTransactions()

    def Value(self, timestamp=None):
        try:
            if timestamp:
                bisect_point = self.bisect(timestamp)
                if (bisect_point) is 0:
                    return 0.0
                data = self[self._list[bisect_point - 1]]
            else:
                data = self[self._list[-1]]
        except (IndexError, KeyError):
            return 0.0
        value = 0.0
        for symbol, amount in data.items():
            price = coin_data.GetHistory(symbol).GetValue(timestamp)
            value += amount * price
        return value

    def GetOwnedCurrency(self, timestamp=None):
        try:
            if timestamp:
                bisect_point = self.bisect(timestamp)
                if (bisect_point) is 0:
                    return {}
                return self[self._list[bisect_point - 1]]
            else:
                return self[self._list[-1]]
        except (IndexError, KeyError):
            return {}

    def AsTable(self, timestamp=None):
        tuples = []
        for symbol, amount in self.GetOwnedCurrency(timestamp).items():
            history = coin_data.GetHistory(symbol)
            price = history.GetValue(timestamp)
            curr_value = amount * price
            change_day = history.GetDayChange(timestamp)
            tuples.append([
                symbol, amount,
                '$%.2f (%.2f%s)' % (curr_value, change_day, "%"), curr_value
            ])
        tuples = sorted(tuples, key=lambda x: x[3], reverse=True)
        for t in tuples:
            t.pop()
        return tabulate(tuples, tablefmt='fancy_grid', floatfmt='.4f')

    def BreakTable(self, timestamp=None):
        tuples = []
        for symbol, amount in self.GetOwnedCurrency(timestamp).items():
            price = coin_data.GetHistory(symbol).GetValue(timestamp)
            value_at_t = amount * price
            tuples.append([
                symbol, amount,
                '%.2f%s' % ((value_at_t / self.Value(timestamp)) * 100, "%"),
                (value_at_t / self.Value(timestamp)) * 100
            ])
        tuples = sorted(tuples, key=lambda x: x[3], reverse=True)
        for t in tuples:
            t.pop()
        return tabulate(tuples, tablefmt='fancy_grid', floatfmt='.4f')
Example #8
0
def test_insert_valueerror4():
    slt = SortedList(range(10))
    slt._reset(4)
    slt.insert(5, 7)
Example #9
0
class InclusionTreeBuilder:
    """
    this class builds a tree of polygons included in one another.
    it works through a sweeping line algorithm.
    also identifies each as a hole or a polygon.
    """
    def __init__(self, polygons):
        # the algorithm works in O(n) (times sorted container's costs) in this way:
        # we have a SortedList of all currently crossed paths
        self.crossed_paths = SortedList()
        # for each polygon, a SortedList of all of its currently crossed paths
        self.polygons = defaultdict(SortedList)
        # when meeting a new polygon for the first time
        # we will insert it in the crossed_paths list ; we get it's top neighbour (smaller)
        # and get the corresponding polygon
        # now if we are contained inside it, we are its child
        # if we are not contained inside it, we are its brother
        # to figure out whether we are inside or not, we look at #paths smaller than us
        # in the neighbour polygon's SortedList

        set_comparer(self)
        # we store all keys used for comparing paths
        # this speeds up keys computations and more importantly removes
        # rounding errors
        self.sweeping_keys = dict()

        polygons_number = self._create_events(polygons)
        self.current_point = None
        self.tree = InclusionTree()
        self.nodes = dict()  # store for each poly its node and father node

        for event in self.events:
            self.execute_event(event)
            if len(self.nodes) == polygons_number:
                return  # no need to finish the sweep once everyone is identified

    def _create_events(self, polygons):
        """
        create all start/end events for each path.
        each event is : a comparison key ; the path.
        """
        self.events = []
        polygons_number = 0
        for height, polygons in polygons.items():
            for polygon in polygons:
                polygons_number += 1
                for segment in polygon_segments(height, polygon):
                    angle = segment.key_angle()
                    print("angle for", segment, "is", angle)
                    for point, event_type in zip(sorted(segment.endpoints),
                                                 (START_EVENT, END_EVENT)):
                        key = (point, event_type, -height)
                        raise Exception("we lack an angle here")
                        self.events.append((key, segment))
                        self.sweeping_keys[(id(segment), point)] =\
                            (point.coordinates[1], angle, -height)

        self.events.sort(key=lambda e: e[0])
        return polygons_number

    def key(self, path):
        """
        returns key at current point for given path.
        """
        key_id = (id(path), self.current_point)
        if key_id in self.sweeping_keys:
            return self.sweeping_keys[key_id]
        else:
            current_x = self.current_point.coordinates[0]
            return (path.vertical_intersection_at(current_x), path.key_angle(),
                    -path.height)

    def execute_event(self, event):
        """
        execute start path or end path event
        """
        event_key, event_path = event
        event_point, event_type = event_key[0:2]

        if event_type == START_EVENT:
            self.current_point = event_point
            self.start_path(event_path)
        else:
            self.end_path(event_path)
            self.current_point = event_point

        if __debug__:
            # very slow
            paths = iter(self.crossed_paths)
            previous_path = next(paths, None)
            for path in paths:
                if self.key(previous_path) >= self.key(path):
                    paths = list(self.crossed_paths)
                    print(paths)
                    print("previous", previous_path, self.key(previous_path))
                    print("current", path, self.key(path))
                    tycat(self.current_point, paths, previous_path, path)
                    raise Exception("pb ordre")
                previous_path = path

    def start_path(self, path):
        """
        handles incoming path
        """
        index = self.crossed_paths.bisect(path)
        self.crossed_paths.insert(index, path)
        polygon = path.polygon_id()
        self.polygons[polygon].add(path)

        if polygon not in self.nodes:
            father_node = self.identify_father_node(path, index)
            new_node = father_node.add_child(path)
            self.nodes[polygon] = (new_node, father_node)
            print("adding", polygon, "as child of", id(father_node.content))

    def identify_father_node(self, path, index):
        """
        identify where polygon is in tree.
        we need the path and its position in crossed paths
        """
        if index == 0:
            # no one above us, we are below root
            return self.tree
        else:
            neighbour_polygon = self.crossed_paths[index - 1].polygon_id()
            above_paths = self.polygons[neighbour_polygon].bisect(path)
            if above_paths % 2:
                # odd neighbour's paths above us
                # we are inside him
                return self.nodes[neighbour_polygon][0]
            else:
                # event neighbour's paths above us
                # we are beside him
                return self.nodes[neighbour_polygon][1]

    def end_path(self, path):
        """
        handles ending path
        """
        print("removing", path, "from", self.crossed_paths)
        self.crossed_paths.remove(path)
        self.polygons[path.polygon_id()].remove(path)