def setUp(self) -> None: try: os.remove(TEST_DATABASE) except IOError as e: print(e) print('cwd: ', os.getcwd()) self.dbm = DBManager(db_name=TEST_DATABASE, order_tables=['orders']) self.order = Order( session_id='S_20210501_2008', order_id='ORDER_ID', pt_id='PT_ID', k_side=k_binance.SIDE_BUY, price=50_000.0, amount=1.0, ) self.order_2 = Order( session_id='S_20210501_2008', order_id='OR_000001', pt_id='PT_000001', k_side=k_binance.SIDE_SELL, price=60_000.88, amount=1.0876548765, uid='0123456789abcdef' )
def place_order(self, order: Order) -> Optional[dict]: # TODO: check and test it try: msg = self.client.create_order( symbol='BTCEUR', side=order.k_side, type=k_binance.ORDER_TYPE_LIMIT, timeInForce=k_binance.TIME_IN_FORCE_GTC, # TODO: check precision quantity=order.get_amount(precision=6), price=order.get_price_str(precision=2), newClientOrderId=order.uid) if msg: d = dict(binance_id=msg['orderId'], status=msg.get('status')) return d else: log.critical(f'error when placing order {order}') except (BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException) as e: log.critical(e) except (ConnectionError, ReadTimeout) as e: log.critical(e) return None # msg['orderId'], msg['status'] == 'FILLED' or 'NEW'
def setUp(self) -> None: m1 = Order( session_id='S_TEST', order_id='OR_M1', pt_id='PT_ID', k_side=k_binance.SIDE_BUY, price=47300.0, amount=0.012, uid='abcdef0123456789' ) m2 = Order( session_id='S_TEST', order_id='OR_M2', pt_id='PT_ID', k_side=k_binance.SIDE_SELL, price=47900.0, amount=0.012, uid='0123456789abcdef' ) orders = [m1, m2] dbm = FakeDBManager() table = 'test_table' # create orders book self.orders_book = PendingOrdersBook(orders=orders, dbm=dbm, table=table)
def place_back_order(self, order: Order) -> None: if order in self.placed: self.placed.remove(order) self.monitor.append(order) order.set_status(OrderStatus.MONITOR) else: log.critical( f'trying to place back to monitor an order not found in the placed list: {order}' )
def place_order(self, order: Order) -> None: if order in self.monitor: self.monitor.remove(order) self.placed.append(order) # in session, once placement confirmed, will be set to status PLACED order.set_status(OrderStatus.TO_BE_PLACED) else: log.critical( f'trying to place an order not found in the monitor list: {order}' )
def _process_place_order(self, order: Order) -> bool: new_placement_allowed = True self.pob.place_order(order=order) is_order_placed, new_status = self._place_order(order=order) if is_order_placed: # 2. placed: (s: PLACED, t: pending_orders, l: placed) order.set_status(status=OrderStatus.PLACED) # to control one new placement per cycle mode if K_ONE_PLACE_PER_CYCLE_MODE: new_placement_allowed = False else: self.pob.place_back_order(order=order) log.critical(f'for unknown reason the order has not been placed: {order}') return new_placement_allowed
class TestOrder(unittest.TestCase): def setUp(self) -> None: self.order = Order( session_id='S_20210501_2008', order_id='ORDER_ID', pt_id='PT_ID', k_side=k_binance.SIDE_BUY, price=50_000.0, amount=1.0, ) self.order_2 = Order(session_id='S_20210501_2008', order_id='OR_000001', pt_id='PT_000001', k_side=k_binance.SIDE_SELL, price=60_000.88, amount=1.0876548765, uid='0123456789abcdef') def test_init(self): self.assertNotEqual('', self.order.uid) print(self.order) self.assertEqual('0123456789abcdef', self.order_2.uid) self.assertEqual('MONITOR', self.order.status.name) print(self.order_2) def test_is_ready_for_placement(self): self.assertTrue( self.order.is_ready_for_placement(cmp=50_020.0, min_dist=25))
def setUp(self) -> None: self.order = Order( session_id='S_20210501_2008', order_id='ORDER_ID', pt_id='PT_ID', k_side=k_binance.SIDE_BUY, price=50_000.0, amount=1.0, ) self.order_2 = Order(session_id='S_20210501_2008', order_id='OR_000001', pt_id='PT_000001', k_side=k_binance.SIDE_SELL, price=60_000.88, amount=1.0876548765, uid='0123456789abcdef')
def get_order_from_row(row) -> Order: order = Order(session_id=row[6], pt_id=row[5], uid=row[0], k_side=row[1], price=row[2], amount=row[3], status=OrderStatus[row[4]], order_id='FROM_DATABASE') return order
def get_b1s1(self, dynamic_parameters: dict, ) -> (Optional[Order], Optional[Order]): b1 = None s1 = None order_id = 'NA' # get perfect trade b1_qty, b1_price, s1_price, g = get_pt_values(**dynamic_parameters) s1_qty = dynamic_parameters.get('s1_qty') # check filters before creating order if Order.is_filter_passed(filters=self.symbol_filters, qty=b1_qty, price=b1_price): # create orders b1 = Order( session_id=self.session_id, order_id=order_id, pt_id='PENDING', k_side=k_binance.SIDE_BUY, price=b1_price, amount=b1_qty, name='b1' ) else: log.critical(f'trying to create an order that do not meet limits: {dynamic_parameters}') if Order.is_filter_passed(filters=self.symbol_filters, qty=s1_qty, price=s1_price): s1 = Order( session_id=self.session_id, order_id=order_id, pt_id='PENDING', k_side=k_binance.SIDE_SELL, price=s1_price, amount=s1_qty, name='s1' ) else: log.critical(f'trying to create an order that do not meet limits: {dynamic_parameters}') return b1, s1
def is_balance_enough(self, order: Order) -> (bool, float): # if not enough balance, it returns False and the balance needed is_balance_enough = False if order.k_side == k_binance.SIDE_BUY: balance_allowance = self.current_ab.get_free_price_s2() available_liquidity = balance_allowance - EUR_MIN_BALANCE # [EUR] if (available_liquidity - order.get_total()) > 0: is_balance_enough = True else: # SIDE_SELL balance_allowance = self.current_ab.get_free_amount_s1() available_liquidity = balance_allowance - BTC_MIN_BALANCE # [BTC] if (available_liquidity - order.amount) > 0: is_balance_enough = True return is_balance_enough
def split_n_order(self, order: Order, inter_distance: float, child_count: int) -> List[Order]: new_orders = [] # calculate new amount new_amount = order.amount / child_count # create positions list positions = [] if (child_count % 2) != 0: positions.append(0) # child_count is odd # add positive positions += [x for x in range(1, 1 + int(child_count / 2)) ] # if n=4: [1, 2] # add negative positions += [-x for x in range(1, 1 + int(child_count / 2)) ] # if n=4: [1, 2, -1, -2] # loop positions for n in positions: new_price = order.price + inter_distance * n new_order = Order(session_id=order.session_id, order_id=f'CHILD({n:+})', pt_id=order.pt_id, k_side=order.k_side, price=new_price, amount=new_amount, status=OrderStatus.MONITOR, uid=Order.get_new_uid(), name=order.name + f'({n:+})') new_order.split_count = order.split_count + 1 new_order.compensation_count = order.compensation_count new_order.concentration_count = order.concentration_count # add to monitor and pending_orders table self.pob.monitor.append(new_order) # add to return list new_orders.append(new_order) # delete original order from orders book self.pob.monitor.remove(order) return new_orders
def concentrate_orders(self, orders: List[Order], ref_mp: float, ref_gap: float) -> bool: """concentration does not include n-split :param orders: list of orders to concentrate :param ref_mp: market price to concentrate to :param ref_gap: concentration gap :return: True if concentration is successful """ # check orders list is not empty if len(orders) < 1: return False # get equivalent amount and total amount, total, _, _ = BalanceManager.get_balance_for_list(orders) # get equivalent pair b1-s1 s1_p, b1_p, s1_qty, b1_qty = get_compensation(cmp=ref_mp, gap=ref_gap, qty_bal=amount, price_bal=total, buy_fee=self.buy_fee, sell_fee=self.sell_fee) # validate values received for b1 and s1 if s1_p < 0 or b1_p < 0 or s1_qty < 0 or b1_qty < 0: log.critical( f'!!!!!!!!!! negative value(s) after compensation: b1p: {b1_p} - b1q: {b1_qty} !!!!!!!!!!' f'- s1p: {s1_p} - s1q: {s1_qty}') return False else: # get pt_id of all orders to concentrate pt_ids = [] for order in orders: if order.pt_id not in pt_ids: pt_ids.append(order.pt_id) # increment counter and save mapping between count and pt_ids # at this point the concentration is sure and will return True self.concentrator_count += 1 self.concentrated_pt_id.append((self.concentrator_count, pt_ids)) print(self.concentrated_pt_id) # change pending orders with this pt_id to new pt_id new_pt_id = f'C-{self.concentrator_count:04}' for order in self.pob.get_pending_orders(): if order.pt_id in pt_ids: order.pt_id = new_pt_id # change pt_id also in traded orders self.tob.set_new_pt_id(new_pt_id=new_pt_id, pt_id_list=pt_ids) # create both orders session_id = orders[0].session_id # same session_id b1 = Order(session_id=session_id, order_id='CONCENTRATED', pt_id=new_pt_id, k_side=k_binance.SIDE_BUY, price=b1_p, amount=b1_qty, status=OrderStatus.MONITOR, uid=Order.get_new_uid(), name='con-b1') s1 = Order(session_id=session_id, order_id='CONCENTRATED', pt_id=new_pt_id, k_side=k_binance.SIDE_SELL, price=s1_p, amount=s1_qty, status=OrderStatus.MONITOR, uid=Order.get_new_uid(), name='con-s1') # add new orders to appropriate list self.pob.monitor.append(b1) self.pob.monitor.append(s1) # delete original orders from list for order in orders: self.pob.monitor.remove(order) # log log.info('////////// ORDER COMPENSATED //////////') for order in orders: log.info(f'initial order: {order}') log.info(f'compensation count: {order.compensation_count}') log.info(f'compensated b1: {b1}') log.info(f'compensated s1: {s1}') # update concentrated variables and inverse counter b1.concentration_count = 1 s1.concentration_count = 1 # update variables b1.compensation_count = 0 b1.split_count = 0 s1.compensation_count = 0 s1.split_count = 0 # split n # self.split_n_order(order=b1, inter_distance=interdistance_after_concentration, child_count=n_for_split) # self.split_n_order(order=s1, inter_distance=interdistance_after_concentration, child_count=n_for_split) return True
def concentrate_for_liquidity(self, order: Order, ref_mp: float, ref_gap: float) -> bool: """concentration does not include n-split :param order: order to concentrate :param ref_mp: market price to concentrate to :param ref_gap: concentration gap :return: True if concentration is successful """ # get equivalent amount and total amount, total, _, _ = BalanceManager.get_balance_for_list([order]) # get equivalent pair b1-s1 s1_p, b1_p, s1_qty, b1_qty = get_compensation(cmp=ref_mp, gap=ref_gap, qty_bal=amount, price_bal=total, buy_fee=self.buy_fee, sell_fee=self.sell_fee) # validate values received for b1 and s1 if s1_p < 0 or b1_p < 0 or s1_qty < 0 or b1_qty < 0: log.critical( f'!!!!!!!!!! negative value(s) after compensation: b1p: {b1_p} - b1q: {b1_qty} !!!!!!!!!!' f'- s1p: {s1_p} - s1q: {s1_qty}') return False else: # increment counter and save mapping between count and pt_ids # at this point the concentration is sure and will return True self.concentrator_count += 1 # create both orders session_id = order.session_id # same session_id b1 = Order(session_id=session_id, order_id='CONCENTRATED', pt_id=order.pt_id, k_side=k_binance.SIDE_BUY, price=b1_p, amount=b1_qty, status=OrderStatus.MONITOR, uid=Order.get_new_uid(), name='con-b1') s1 = Order(session_id=session_id, order_id='CONCENTRATED', pt_id=order.pt_id, k_side=k_binance.SIDE_SELL, price=s1_p, amount=s1_qty, status=OrderStatus.MONITOR, uid=Order.get_new_uid(), name='con-s1') # add new orders to appropriate list self.pob.monitor.append(b1) self.pob.monitor.append(s1) # delete original order from list self.pob.monitor.remove(order) # log print(f'concentrated order: {order}') log.info(f'initial order: {order}') log.info(f'concentration count: {order.concentration_count}') log.info(f'compensated b1: {b1}') log.info(f'compensated s1: {s1}') # update concentrated variables and inverse counter b1.concentration_count = 1 s1.concentration_count = 1 # update variables b1.compensation_count = 0 b1.split_count = 0 s1.compensation_count = 0 s1.split_count = 0 return True