From ea29d490bf3e6cddb0bd66ce3a749655f08e7dc0 Mon Sep 17 00:00:00 2001 From: Guillaume De Saint Martin Date: Tue, 3 Oct 2023 19:01:46 +0200 Subject: [PATCH 1/2] [Kucoin] handle minFunds --- Trading/Exchange/kucoin/kucoin_exchange.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Trading/Exchange/kucoin/kucoin_exchange.py b/Trading/Exchange/kucoin/kucoin_exchange.py index 1a61dd11b..3a30b1f62 100644 --- a/Trading/Exchange/kucoin/kucoin_exchange.py +++ b/Trading/Exchange/kucoin/kucoin_exchange.py @@ -23,6 +23,7 @@ import octobot_trading.errors import octobot_trading.exchanges as exchanges import octobot_trading.exchanges.connectors.ccxt.enums as ccxt_enums +import octobot_trading.exchanges.connectors.ccxt.constants as ccxt_constants import octobot_commons.constants as commons_constants import octobot_trading.constants as constants import octobot_trading.enums as trading_enums @@ -165,6 +166,24 @@ async def get_account_id(self, **kwargs: dict) -> str: # raised when calling this endpoint with a subaccount return constants.DEFAULT_SUBACCOUNT_ID + def get_market_status(self, symbol, price_example=None, with_fixer=True): + """ + local override to take "minFunds" into account + "minFunds the minimum spot and margin trading amounts" https://docs.kucoin.com/#get-symbols-list + """ + market_status = super().get_market_status(symbol, price_example=price_example, with_fixer=with_fixer) + min_funds = market_status.get(ccxt_constants.CCXT_INFO, {}).get("minFunds") + if min_funds is not None: + # should only be for spot and margin, use it if available anyway + limit_costs = market_status[trading_enums.ExchangeConstantsMarketStatusColumns.LIMITS.value][ + trading_enums.ExchangeConstantsMarketStatusColumns.LIMITS_COST.value + ] + # use max (most restrictive) value + limit_costs[trading_enums.ExchangeConstantsMarketStatusColumns.LIMITS_COST_MIN.value] = min( + limit_costs[trading_enums.ExchangeConstantsMarketStatusColumns.LIMITS_COST_MIN.value], + float(min_funds) + ) + return market_status @_kucoin_retrier async def get_symbol_prices(self, symbol, time_frame, limit: int = 200, **kwargs: dict): From d94e254c00d988c44c23de1d1024949b08f64498 Mon Sep 17 00:00:00 2001 From: Guillaume De Saint Martin Date: Tue, 3 Oct 2023 19:02:18 +0200 Subject: [PATCH 2/2] [RemoteTradingSignalsTradingMode] accuratly handle chained orders error --- .../remote_trading_signals_trading.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Trading/Mode/remote_trading_signals_trading_mode/remote_trading_signals_trading.py b/Trading/Mode/remote_trading_signals_trading_mode/remote_trading_signals_trading.py index b143cd4c4..d9ef6bfd4 100644 --- a/Trading/Mode/remote_trading_signals_trading_mode/remote_trading_signals_trading.py +++ b/Trading/Mode/remote_trading_signals_trading_mode/remote_trading_signals_trading.py @@ -275,15 +275,20 @@ async def _bundle_order(self, order_description, to_create_orders, ignored_order async def _chain_order(self, order_description, created_orders, ignored_orders, chained_to, fees_currency_side, created_groups, symbol, order_description_by_id): + failed_order_creation = False try: base_order = created_orders[chained_to] if base_order is None: # when an error occurred when creating the initial order + failed_order_creation = True raise KeyError except KeyError as e: - if chained_to in ignored_orders: - self.logger.error(f"Ignored order chained to id {chained_to}: " - f"associated master order has not been created") + if chained_to in ignored_orders or failed_order_creation: + message = f"Ignored order chained to id {chained_to}: associated master order has not been created" + if failed_order_creation: + self.logger.info(message) + else: + self.logger.error(message) else: self.logger.error( f"Ignored chained order from {order_description}. Chained orders have to be sent in the same "