class OrderQueue(object): """ """ def __init__(self): self.Orders = FastRBTree() self.totalAmount = 0.0 def append(self,order): k = order.timestamp self.Orders.insert(k,order) self.totalAmount += self.Orders[k].amount def count(self): return self.Orders.count def min_item(self): return self.Orders.min_item() def eat(self,amount): """ use this only if amount <= self.amount return OrderToPop,RestAmount """ current_amount = amount to_pop_orders = [] while self.totalAmount>0 and current_amount>0: if not self.Orders or self.Orders.count==0: #print "amount:%.4f" % self.totalAmount self.totalAmount = 0.0 return [] min_item = self.Orders.min_item() min_i = min_item[1] # 1.enough # 2.not enough if min_i.amount <= current_amount: current_amount -= min_i.amount self.totalAmount -= min_i.amount to_pop_orders.append(self.Orders.pop_min()[1]) continue # this is a hard case , need to take care of # first we split the order , take amount from current order # and make elif min_i.amount > current_amount: new_order = min_i.copy() new_order.amount = current_amount to_pop_orders.append(new_order) min_i.amount -= current_amount self.totalAmount -= current_amount current_amount = 0 break # return: # 1.orders # 2.amount to trade # 3.amount left return to_pop_orders def remove(self,order): k = order.timestamp self.totalAmount -= self.Orders[k].amount self.Orders.remove(k) def get_price_depth(self): return self.totalAmount def is_empty(self): return self.Orders.count == 0
class Tdigest(object): def __init__(self, delta=0.01, K=25, CX=1.1): self.delta = delta self.K = K self.CX = CX self.centroids = RBTree() self.nreset = 0 self.reset() def reset(self): self.centroids.clear() self.n = 0 self.nreset += 1 self.last_cumulate = 0 self.compressing = False def push(self, x, n=1): if not isinstance(x, list): x = [x] for item in x: self._digest(item, n) def percentile(self, p): if self.size() == 0: return None self._cumulate(True) cumn = self.n * p lower = self.centroids.min_item()[1] upper = self.centroids.max_item()[1] for c in self.centroids.values(): if c.cumn <= cumn: lower = c else: upper = c break if lower == upper: return lower.mean return lower.mean + (cumn - lower.cumn) * (upper.mean - lower.mean) / \ (upper.cumn - lower.cumn) def serialize(self): result = '%s~%s~%s~' % (self.delta, self.K, self.size()) if self.size() == 0: return result self._cumulate(True) means = [] counts = [] for c in self.centroids.values(): means.append(str(c.mean)) counts.append(str(c.n)) return '%s%s~%s' % (result, '~'.join(means), '~'.join(counts)) @classmethod def deserialize(cls, serialized_str): if not isinstance(serialized_str, basestring): raise Exception(u'serialized_str must be str') data = serialized_str.split('~') t = Tdigest(delta=float(data[0]), K=int(data[1])) size = int(data[2]) for i in xrange(size): t.push(float(data[i + 3]), int(data[size + i + 3])) t._cumulate(True) return t def _digest(self, x, n): if self.size() == 0: self._new_centroid(x, n, 0) else: _min = self.centroids.min_item()[1] _max = self.centroids.max_item()[1] nearest = self.find_nearest(x) if nearest and nearest.mean == x: self._addweight(nearest, x, n) elif nearest == _min: self._new_centroid(x, n, 0) elif nearest == _max: self._new_centroid(x, n, self.n) else: p = (nearest.cumn + nearest.n / 2.0) / self.n max_n = int(4 * self.n * self.delta * p * (1 - p)) if max_n >= nearest.n + n: self._addweight(nearest, x, n) else: self._new_centroid(x, n, nearest.cumn) self._cumulate(False) if self.K and self.size() > self.K / self.delta: self.compress() def find_nearest(self, x): if self.size() == 0: return None try: lower = self.centroids.ceiling_item(x)[1] except KeyError: lower = None if lower and lower.mean == x: return lower try: prev = self.centroids.floor_item(x)[1] except KeyError: prev = None if not lower: return prev if not prev: return lower if abs(prev.mean - x) < abs(lower.mean - x): return prev else: return lower def size(self): return len(self.centroids) def compress(self): if self.compressing: return points = self.toList() self.reset() self.compressing = True for point in sorted(points, key=lambda x: random()): self.push(point['mean'], point['n']) self._cumulate(True) self.compressing = False def _cumulate(self, exact): if self.n == self.last_cumulate: return if not exact and self.CX and self.last_cumulate and \ self.CX > (self.n / self.last_cumulate): return cumn = 0 for c in self.centroids.values(): cumn = c.cumn = cumn + c.n self.n = self.last_cumulate = cumn def toList(self): return [dict(mean=c.mean, n=c.n, cumn=c.cumn) for c in self.centroids.values()] def _addweight(self, nearest, x, n): if x != nearest.mean: nearest.mean += n * (x - nearest.mean) / (nearest.n + n) nearest.cumn += n nearest.n += n self.n += n def _new_centroid(self, x, n, cumn): c = Centroid(x, n, cumn) self.centroids.insert(x, c) self.n += n return c
class OrderQueue(object): """ """ def __init__(self): self.Orders = FastRBTree() self.totalAmount = 0.0 def append(self, order): k = order.timestamp self.Orders.insert(k, order) self.totalAmount += self.Orders[k].amount def count(self): return self.Orders.count def min_item(self): return self.Orders.min_item() def eat(self, amount): """ use this only if amount <= self.amount return OrderToPop,RestAmount """ current_amount = amount to_pop_orders = [] while self.totalAmount > 0 and current_amount > 0: if not self.Orders or self.Orders.count == 0: #print "amount:%.4f" % self.totalAmount self.totalAmount = 0.0 return [] min_item = self.Orders.min_item() min_i = min_item[1] # 1.enough # 2.not enough if min_i.amount <= current_amount: current_amount -= min_i.amount self.totalAmount -= min_i.amount to_pop_orders.append(self.Orders.pop_min()[1]) continue # this is a hard case , need to take care of # first we split the order , take amount from current order # and make elif min_i.amount > current_amount: new_order = min_i.copy() new_order.amount = current_amount to_pop_orders.append(new_order) min_i.amount -= current_amount self.totalAmount -= current_amount current_amount = 0 break # return: # 1.orders # 2.amount to trade # 3.amount left return to_pop_orders def remove(self, order): k = order.timestamp self.totalAmount -= self.Orders[k].amount self.Orders.remove(k) def get_price_depth(self): return self.totalAmount def is_empty(self): return self.Orders.count == 0