def test_symmetrical_volume_age_weighted(self): # Symmetrical in distance to mid-price and amounts, BUT different ages current_time_mock = 1234567891 self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 300}000000", "BTC-USDT", True, "BTC", "USDT", Decimal(99), Decimal(6))) self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 600}000000", "BTC-USDT", True, "BTC", "USDT", Decimal(91), Decimal(5))) self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 800}000000", "BTC-USDT", False, "BTC", "USDT", Decimal(101), Decimal(6))) self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 1200}000000", "BTC-USDT", False, "BTC", "USDT", Decimal(109), Decimal(5))) with patch('time.time', return_value=current_time_mock): self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_TIME_WEIGHTED) self.tracker.update_strategy_orders_with_equivalent_orders() self.assertEqual(self.tracker.strategy_current_hanging_orders, {HangingOrder(order_id=None, trading_pair='BTC-USDT', is_buy=True, price=Decimal('95.69098'), amount=Decimal('11.00000')), HangingOrder(order_id=None, trading_pair='BTC-USDT', is_buy=False, price=Decimal('104.20177'), amount=Decimal('11.00000'))})
def _execute_orders_in_strategy(self, candidate_orders: Set[HangingOrder]): new_hanging_orders = set() order_type = self.strategy.market_info.market.get_maker_order_type() for order in candidate_orders: # Only execute if order is new if order.order_id is None: if order.amount > 0: if order.is_buy: order_id = self.strategy.buy_with_specific_market( self.strategy.market_info, amount=order.amount, order_type=order_type, price=order.price, expiration_seconds=self.strategy.order_refresh_time ) else: order_id = self.strategy.sell_with_specific_market( self.strategy.market_info, amount=order.amount, order_type=order_type, price=order.price, expiration_seconds=self.strategy.order_refresh_time ) new_hanging_order = HangingOrder(order_id, order.trading_pair, order.is_buy, order.price, order.amount) new_hanging_orders.add(new_hanging_order) # If it's a preexistent order we don't create it but we add it to hanging orders else: new_hanging_orders.add(order) return new_hanging_orders
def _process_cancel_as_part_of_renew(self, event: OrderCancelledEvent): renewing_order = next((order for order in self.orders_being_renewed if order.order_id == event.order_id), None) if renewing_order: self.logger().info( f"({self.trading_pair}) Hanging order {event.order_id} " f"has been canceled as part of the renew process. " f"Now the replacing order will be created.") self.strategy_current_hanging_orders.remove(renewing_order) self.orders_being_renewed.remove(renewing_order) order_to_be_created = HangingOrder(None, renewing_order.trading_pair, renewing_order.is_buy, renewing_order.price, renewing_order.amount, self.strategy.current_timestamp) executed_orders = self._execute_orders_in_strategy( [order_to_be_created]) self.strategy_current_hanging_orders = self.strategy_current_hanging_orders.union( executed_orders) for new_hanging_order in executed_orders: limit_order_from_hanging_order = next( (o for o in self.strategy.active_orders if o.client_order_id == new_hanging_order.order_id), None) if limit_order_from_hanging_order: self.add_order(limit_order_from_hanging_order)
def test_renew_hanging_orders_past_max_order_age(self): current_time_mock = 1234567891 # Order just executed self.tracker.add_order(LimitOrder("Order-1234567890000000", "BTC-USDT", True, "BTC", "USDT", Decimal(101), Decimal(1))) # Order executed 1900 seconds ago self.tracker.add_order(LimitOrder("Order-1234565991000000", "BTC-USDT", True, "BTC", "USDT", Decimal(105), Decimal(1))) with patch('time.time', return_value=current_time_mock): self.tracker.update_strategy_orders_with_equivalent_orders() self.tracker.renew_hanging_orders_past_max_order_age() self.assertEqual(self.tracker.orders_to_be_created, {HangingOrder(None, "BTC-USDT", True, Decimal(105), Decimal(1))})
def renew_hanging_orders_past_max_order_age(self): max_age = getattr(self.strategy, "max_order_age", None) to_be_cancelled: Set[HangingOrder] = set() to_be_created: Set[HangingOrder] = set() if max_age: for order in self.strategy_current_hanging_orders: if order.age > max_age: self.logger().info( f"Reached max_order_age={max_age}sec hanging order: {order}. Renewing..." ) to_be_cancelled.add(order) self._cancel_multiple_orders_in_strategy( [o.order_id for o in to_be_cancelled if o.order_id]) for order in to_be_cancelled: self.strategy_current_hanging_orders.remove(order) order_to_be_created = HangingOrder(None, order.trading_pair, order.is_buy, order.price, order.amount) if self.aggregation_method == HangingOrdersAggregationType.NO_AGGREGATION: self.original_orders.remove( next(o for o in self.original_orders if o.client_order_id == order.order_id)) self.orders_renewed.add(order_to_be_created) to_be_created.add(order_to_be_created) self.orders_to_be_created = self.orders_to_be_created.union( to_be_created)
def test_symmetrical_volume_distance_weighted(self): # Symmetrical in distance to mid-price and amounts, BUT with distance affecting the weight exponentially self.tracker.add_order(LimitOrder("Order-number-1", "BTC-USDT", True, "BTC", "USDT", Decimal(99), Decimal(6))) self.tracker.add_order(LimitOrder("Order-number-2", "BTC-USDT", True, "BTC", "USDT", Decimal(91), Decimal(5))) self.tracker.add_order(LimitOrder("Order-number-3", "BTC-USDT", False, "BTC", "USDT", Decimal(101), Decimal(6))) self.tracker.add_order(LimitOrder("Order-number-4", "BTC-USDT", False, "BTC", "USDT", Decimal(109), Decimal(5))) self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_DISTANCE_WEIGHTED) self.tracker.update_strategy_orders_with_equivalent_orders() self.assertEqual(self.tracker.strategy_current_hanging_orders, {HangingOrder(order_id=None, trading_pair='BTC-USDT', is_buy=True, price=Decimal('96.82055'), amount=Decimal('11.00000')), HangingOrder(order_id=None, trading_pair='BTC-USDT', is_buy=False, price=Decimal('103.17945'), amount=Decimal('11.00000'))})
def test_asymmetrical_volume_weighted(self): # Asymmetrical in distance to mid-price and amounts self.tracker.add_order(LimitOrder("Order-number-1", "BTC-USDT", True, "BTC", "USDT", Decimal(99), Decimal(2))) self.tracker.add_order(LimitOrder("Order-number-2", "BTC-USDT", True, "BTC", "USDT", Decimal(95), Decimal(1))) self.tracker.add_order(LimitOrder("Order-number-3", "BTC-USDT", False, "BTC", "USDT", Decimal(94), Decimal(6))) self.tracker.add_order(LimitOrder("Order-number-4", "BTC-USDT", False, "BTC", "USDT", Decimal(109), Decimal(5))) self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_WEIGHTED) self.tracker.update_strategy_orders_with_equivalent_orders() self.assertEqual(self.tracker.strategy_current_hanging_orders, {HangingOrder(order_id=None, trading_pair='BTC-USDT', is_buy=True, price=Decimal('97.66667'), amount=Decimal('3.00000')), HangingOrder(order_id=None, trading_pair='BTC-USDT', is_buy=False, price=Decimal('107.36364'), amount=Decimal('11.00000'))})
def _obtain_equivalent_weighted_order(self, orders, weight_function): result = set() buys = [o for o in orders if o.is_buy] sells = [o for o in orders if not o.is_buy] current_price = self.strategy.get_price() distance_prod_buys = sum( abs(current_price - o.price) * o.quantity * weight_function(o) for o in buys) distance_prod_sells = sum( abs(current_price - o.price) * o.quantity * weight_function(o) for o in sells) if distance_prod_buys > 0: price = current_price - distance_prod_buys / sum( o.quantity * weight_function(o) for o in buys) amount = sum(o.quantity for o in buys) quantized_amount = self.strategy.market_info.market.quantize_order_amount( self.trading_pair, amount) quantized_price = self.strategy.market_info.market.quantize_order_price( self.trading_pair, price) if quantized_amount > 0: result.add( HangingOrder(None, self.trading_pair, True, quantized_price, quantized_amount)) if distance_prod_sells > 0: price = current_price + distance_prod_sells / sum( o.quantity * weight_function(o) for o in sells) amount = sum(o.quantity for o in sells) quantized_amount = self.strategy.market_info.market.quantize_order_amount( self.trading_pair, amount) quantized_price = self.strategy.market_info.market.quantize_order_price( self.trading_pair, price) if quantized_amount > 0: result.add( HangingOrder(None, self.trading_pair, False, quantized_price, quantized_amount)) return frozenset(result)
def test_asymmetrical_volume_age_weighted(self): current_time_mock = 1234567891 self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 500}000000", "BTC-USDT", True, "BTC", "USDT", Decimal(99), Decimal(2))) self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 600}000000", "BTC-USDT", True, "BTC", "USDT", Decimal(95), Decimal(1))) self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 700}000000", "BTC-USDT", True, "BTC", "USDT", Decimal(94), Decimal(6))) self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 800}000000", "BTC-USDT", False, "BTC", "USDT", Decimal(109), Decimal(5))) with patch('time.time', return_value=current_time_mock): self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_TIME_WEIGHTED) self.tracker.update_strategy_orders_with_equivalent_orders() self.assertEqual(self.tracker.strategy_current_hanging_orders, {HangingOrder(order_id=None, trading_pair='BTC-USDT', is_buy=True, price=Decimal('95.31641'), amount=Decimal('9.00000')), HangingOrder(order_id=None, trading_pair='BTC-USDT', is_buy=False, price=Decimal('109.00000'), amount=Decimal('5.00000'))})
def _execute_orders_in_strategy(self, candidate_orders: Set[HangingOrder]): new_hanging_orders = set() order_type = self.strategy.market_info.market.get_maker_order_type() for order in candidate_orders: # Only execute if order is new if order.order_id is None: if order.amount > 0: if order.is_buy: order_id = self.strategy.buy_with_specific_market( self.strategy.market_info, amount=order.amount, order_type=order_type, price=order.price, expiration_seconds=self.strategy.order_refresh_time ) else: order_id = self.strategy.sell_with_specific_market( self.strategy.market_info, amount=order.amount, order_type=order_type, price=order.price, expiration_seconds=self.strategy.order_refresh_time ) new_hanging_order = HangingOrder(order_id, order.trading_pair, order.is_buy, order.price, order.amount) # If newly created order is an original order which was renewed, it will be added to original_orders if order in self.orders_renewed: limit_order_from_hanging_order = next( o for o in self.strategy.active_orders if o.client_order_id == order_id) if limit_order_from_hanging_order: self.add_order(limit_order_from_hanging_order) self.orders_renewed.remove(order) new_hanging_orders.add(new_hanging_order) # If it's a preexistent order we don't create it but we add it to hanging orders else: new_hanging_orders.add(order) return new_hanging_orders
def _process_cancel_as_part_of_renew(self, event: OrderCancelledEvent): renewing_order = next((order for order in self.orders_being_renewed if order.order_id == event.order_id), None) if renewing_order: self.strategy_current_hanging_orders.remove(renewing_order) self.orders_being_renewed.remove(renewing_order) order_to_be_created = HangingOrder(None, renewing_order.trading_pair, renewing_order.is_buy, renewing_order.price, renewing_order.amount) executed_orders = self._execute_orders_in_strategy( [order_to_be_created]) self.strategy_current_hanging_orders = self.strategy_current_hanging_orders.union( executed_orders) for new_hanging_order in executed_orders: limit_order_from_hanging_order = next( (o for o in self.strategy.active_orders if o.client_order_id == new_hanging_order.order_id), None) if limit_order_from_hanging_order: self.add_order(limit_order_from_hanging_order)
def _get_hanging_order_from_limit_order(self, order: LimitOrder): return HangingOrder(order.client_order_id, order.trading_pair, order.is_buy, order.price, order.quantity)