async def test_close_filled_sell_limit_order_one_in_two(self): _, exchange_manager, trader_inst = await self.init_default() portfolio_manager = exchange_manager.exchange_personal_data.portfolio_manager initial_portfolio = copy.copy(portfolio_manager.portfolio) orders_manager = exchange_manager.exchange_personal_data.orders_manager trades_manager = exchange_manager.exchange_personal_data.trades_manager # Test buy order limit_buy = create_order_instance(trader=trader_inst, order_type=TraderOrderType.BUY_LIMIT, symbol="BQX/BTC", current_price=decimal.Decimal("4"), quantity=decimal.Decimal("2"), price=decimal.Decimal("4")) await trader_inst.create_order(limit_buy, portfolio_manager.portfolio) # Test second buy order second_limit_buy = create_order_instance(trader=trader_inst, order_type=TraderOrderType.BUY_LIMIT, symbol="VEN/BTC", current_price=decimal.Decimal("1"), quantity=decimal.Decimal("1.5"), price=decimal.Decimal("1")) await trader_inst.create_order(second_limit_buy, portfolio_manager.portfolio) assert not trades_manager.trades with pytest.raises(KeyError): assert portfolio_manager.portfolio.portfolio["BQX"].available == 0 assert portfolio_manager.portfolio.portfolio["BTC"].available == 0.5 # Fill only 1st one limit_buy.filled_price = 4 limit_buy.status = OrderStatus.FILLED with patch.object(ccxt.async_support.binance, "calculate_fee", Mock(return_value=FEES_MOCK)) \ as calculate_fee_mock: await limit_buy.on_fill(force_fill=True) # ensure call ccxt calculate_fee for order fees calculate_fee_mock.assert_called_once() # added filled orders as filled trades assert len(trades_manager.trades) == 1 assert all(trade.status is OrderStatus.FILLED for trade in trades_manager.trades.values()) assert limit_buy not in orders_manager.get_open_orders() assert second_limit_buy in orders_manager.get_open_orders() assert initial_portfolio != portfolio_manager.portfolio # (mocked) fees are taken into account assert portfolio_manager.portfolio.portfolio["BQX"].available == decimal.Decimal(str(2 - 0.1)) assert portfolio_manager.portfolio.portfolio["BTC"].available == decimal.Decimal("0.5") assert portfolio_manager.portfolio.portfolio["BTC"].total == decimal.Decimal("2") await self.stop(exchange_manager)
async def test_close_filled_sell_limit_order_one_in_two(self): _, exchange_manager, trader_inst = await self.init_default() portfolio_manager = exchange_manager.exchange_personal_data.portfolio_manager initial_portfolio = copy.deepcopy(portfolio_manager.portfolio.portfolio) orders_manager = exchange_manager.exchange_personal_data.orders_manager trades_manager = exchange_manager.exchange_personal_data.trades_manager # Test buy order limit_buy = create_order_instance(trader=trader_inst, order_type=TraderOrderType.BUY_LIMIT, symbol="BQX/BTC", current_price=4, quantity=2, price=4) await trader_inst.create_order(limit_buy, portfolio_manager.portfolio) # Test second buy order second_limit_buy = create_order_instance(trader=trader_inst, order_type=TraderOrderType.BUY_LIMIT, symbol="VEN/BTC", current_price=1, quantity=1.5, price=1) await trader_inst.create_order(second_limit_buy, portfolio_manager.portfolio) assert not trades_manager.trades with pytest.raises(KeyError): assert portfolio_manager.portfolio.portfolio["BQX"][commons_constants.PORTFOLIO_AVAILABLE] == 0 assert portfolio_manager.portfolio.portfolio["BTC"][commons_constants.PORTFOLIO_AVAILABLE] == 0.5 # Fill only 1st one limit_buy.filled_price = 4 limit_buy.status = OrderStatus.FILLED await limit_buy.on_fill(force_fill=True) # added filled orders as filled trades assert len(trades_manager.trades) == 1 assert all(trade.status is OrderStatus.FILLED for trade in trades_manager.trades.values()) assert limit_buy not in orders_manager.get_open_orders() assert second_limit_buy in orders_manager.get_open_orders() assert initial_portfolio != portfolio_manager.portfolio assert portfolio_manager.portfolio.portfolio["BQX"][commons_constants.PORTFOLIO_AVAILABLE] == 2 assert portfolio_manager.portfolio.portfolio["BTC"][commons_constants.PORTFOLIO_AVAILABLE] == 0.5 assert portfolio_manager.portfolio.portfolio["BTC"][commons_constants.PORTFOLIO_TOTAL] == 2 await self.stop(exchange_manager)
async def test_close_filled_stop_buy_order(self): _, exchange_manager, trader_inst = await self.init_default() portfolio_manager = exchange_manager.exchange_personal_data.portfolio_manager initial_portfolio = copy.deepcopy(portfolio_manager.portfolio.portfolio) orders_manager = exchange_manager.exchange_personal_data.orders_manager trades_manager = exchange_manager.exchange_personal_data.trades_manager # Test buy order stop_order = create_order_instance(trader=trader_inst, order_type=TraderOrderType.BUY_LIMIT, symbol="BQX/BTC", current_price=decimal.Decimal("4"), quantity=decimal.Decimal("2"), price=decimal.Decimal("4"), side=TradeOrderSide.BUY) await trader_inst.create_order(stop_order, portfolio_manager.portfolio) assert not trades_manager.trades await stop_order.on_fill(force_fill=True) assert stop_order not in orders_manager.get_open_orders() assert not initial_portfolio == portfolio_manager.portfolio.portfolio # added filled orders as filled trades assert len(trades_manager.trades) == 1 assert all(trade.status is stop_order.status for trade in trades_manager.trades.values()) await self.stop(exchange_manager)
async def _sell_everything(self, symbol, inverted, timeout=None): created_orders = [] order_type = octobot_trading.enums.TraderOrderType.BUY_MARKET \ if inverted else octobot_trading.enums.TraderOrderType.SELL_MARKET async with self.exchange_manager.exchange_personal_data.portfolio_manager.portfolio.lock: current_symbol_holding, current_market_quantity, _, price, symbol_market = \ await order_util.get_pre_order_data(self.exchange_manager, symbol, timeout=timeout) if inverted: if price > 0: quantity = current_market_quantity / price else: quantity = 0 else: quantity = current_symbol_holding for order_quantity, order_price in decimal_order_adapter.decimal_check_and_adapt_order_details_if_necessary( quantity, price, symbol_market): current_order = order_factory.create_order_instance( trader=self, order_type=order_type, symbol=symbol, current_price=order_price, quantity=order_quantity, price=order_price) created_orders.append(await self.create_order( current_order, self.exchange_manager. exchange_personal_data.portfolio_manager.portfolio)) return created_orders
async def create_artificial_order(self, order_type, symbol, current_price, quantity, price, linked_portfolio): """ Creates an OctoBot managed order (managed orders example: stop loss that is not published on the exchange and that is maintained internally). """ await self.create_order( order_factory.create_order_instance( trader=self, order_type=order_type, symbol=symbol, current_price=current_price, quantity=quantity, price=price, linked_portfolio=linked_portfolio))
async def test_close_filled_sell_limit_order(self): _, exchange_manager, trader_inst = await self.init_default() portfolio_manager = exchange_manager.exchange_personal_data.portfolio_manager initial_portfolio = copy.deepcopy( portfolio_manager.portfolio.portfolio) orders_manager = exchange_manager.exchange_personal_data.orders_manager trades_manager = exchange_manager.exchange_personal_data.trades_manager # Test buy order limit_buy = create_order_instance(trader=trader_inst, order_type=TraderOrderType.BUY_LIMIT, symbol="BQX/BTC", current_price=0.1, quantity=10, price=0.1) await trader_inst.create_order(limit_buy, portfolio_manager.portfolio) limit_buy.filled_price = limit_buy.origin_price limit_buy.filled_quantity = limit_buy.origin_quantity limit_buy.status = OrderStatus.FILLED assert not trades_manager.trades with patch.object(ccxt.async_support.binance, "calculate_fee", Mock(return_value=FEES_MOCK)) \ as calculate_fee_mock: await limit_buy.on_fill(force_fill=True) calculate_fee_mock.assert_called_once() assert limit_buy not in orders_manager.get_open_orders() # added filled orders as filled trades assert len(trades_manager.trades) == 1 assert all(trade.status is OrderStatus.FILLED for trade in trades_manager.trades.values()) assert initial_portfolio != portfolio_manager.portfolio assert portfolio_manager.portfolio.portfolio["BTC"][ commons_constants.PORTFOLIO_AVAILABLE] == 9 assert portfolio_manager.portfolio.portfolio["BTC"][ commons_constants.PORTFOLIO_TOTAL] == 9 # 0.1 as fee assert portfolio_manager.portfolio.portfolio["BQX"][ commons_constants.PORTFOLIO_AVAILABLE] == 9.9 assert portfolio_manager.portfolio.portfolio["BQX"][ commons_constants.PORTFOLIO_TOTAL] == 9.9 await self.stop(exchange_manager)
async def close_position(self, position, limit_price=None, timeout=1): """ Creates a close position order :param position: the position to close :param limit_price: the close order limit price if None uses a market order :param timeout: the mark price timeout :return: the list of created orders """ created_orders = [] async with self.exchange_manager.exchange_personal_data.portfolio_manager.portfolio.lock: _, _, _, price, symbol_market = await order_util.get_pre_order_data( self.exchange_manager, position.symbol, timeout=timeout) for order_quantity, order_price in decimal_order_adapter.decimal_check_and_adapt_order_details_if_necessary( position.get_quantity_to_close().copy_abs(), price, symbol_market): if limit_price is not None: order_type = enums.TraderOrderType.SELL_LIMIT \ if position.is_long() else enums.TraderOrderType.BUY_LIMIT else: order_type = enums.TraderOrderType.SELL_MARKET \ if position.is_long() else enums.TraderOrderType.BUY_MARKET # TODO add reduce_only or close_position attribute current_order = order_factory.create_order_instance( trader=self, order_type=order_type, symbol=position.symbol, current_price=order_price, quantity=order_quantity, price=limit_price if limit_price is not None else order_price) created_orders.append(await self.create_order( current_order, self.exchange_manager. exchange_personal_data.portfolio_manager.portfolio)) return created_orders