diff --git a/config_handler.py b/config_handler.py index 83a2680..4d0adf8 100644 --- a/config_handler.py +++ b/config_handler.py @@ -37,6 +37,9 @@ class ConfigHandler: "force_restart_if_retries_exhausted": False, "check_old_long_price": False #switch_to_short should flip this to True unless stated } + if self.broker.get_exchange_name()=="kucoin": + self.default_config_dictionary["concurrent_safety_orders"]=1 + self.default_config_dictionary["boosted_concurrent_safety_orders"]=1 self.config_file_path = f"configs/{pair.split('/')[0]}{pair.split('/')[1]}.json" self.config_dictionary = self.default_config_dictionary.copy() @@ -70,10 +73,10 @@ class ConfigHandler: def get_max_short_safety_orders(self): return self.config_dictionary["max_short_safety_orders"] - def get_concurrent_safety_orders(self): + def get_concurrent_safety_orders(self): return self.config_dictionary["concurrent_safety_orders"] - def get_boosted_concurrent_safety_orders(self): + def get_boosted_concurrent_safety_orders(self): return self.config_dictionary["boosted_concurrent_safety_orders"] def get_safety_order_deviance(self): diff --git a/exchange_wrapper.py b/exchange_wrapper.py index 22fb3b9..962d626 100755 --- a/exchange_wrapper.py +++ b/exchange_wrapper.py @@ -379,6 +379,11 @@ class Broker: if self.get_exchange_name()=="binance": a = self.exchange.fetch_last_prices(pair_list) return {x: a[x]["price"] for x in a.keys()} + elif self.get_exchange_name()=="kucoin": + a = self.exchange.fetch_tickers(pair_list) + if pair_list is None: + return {x: a[x]["close"] for x in a.keys()} + return {x: a[x]["close"] for x in a.keys() if x in pair_list} else: a = self.exchange.fetch_tickers() if pair_list is None: diff --git a/main.py b/main.py index 1886caa..86b9314 100644 --- a/main.py +++ b/main.py @@ -18,7 +18,7 @@ import exchange_wrapper import trader -version = "2025.09.02" +version = "2025.09.03" ''' Color definitions. If you want to change them, check the reference at https://en.wikipedia.org/wiki/ANSI_escape_code#Colors @@ -277,7 +277,7 @@ def main_routine(): global reload_interval global screen_buffer - executor = ThreadPoolExecutor(max_workers=len(running_traders)+worker_threads_overprovisioning) + executor = ThreadPoolExecutor(max_workers=len(broker.get_config()["pairs"])+worker_threads_overprovisioning) is_testnet = "TESTNET " if broker.get_config()["is_sandbox"] else "" exchange_version_label = f"{bright_white}{broker.get_config()['exchange'].upper()} {is_testnet}{white}| DCAv2 {version} | CCXT v{ccxt.__version__}" separator_line = blue + "="*80 + white @@ -325,7 +325,6 @@ def main_routine(): price_list = broker.get_prices(pairs_to_fetch) #Here, assign the prices to the dusters (if any) - for future in as_completed(futures): try: future.result() diff --git a/todo.txt b/todo.txt index 6d874ca..81df0fd 100755 --- a/todo.txt +++ b/todo.txt @@ -7,8 +7,7 @@ Mandatory: 3. API documentation. 4. Implement api key hashing. 5. Dockerize. -6. When autoswitching to long, instead of using a big market order, the last safety order should be a sell order of all the available funds. -7. Earn should be integrated into the instance, in order to be able to invest the idle funds from the short traders. +6. Earn should be integrated into the instance, in order to be able to invest the idle funds from the short traders. Would be nice to have: @@ -16,7 +15,8 @@ Would be nice to have: 0. Trader order: alphabetical; by uptime; by safety orders, by percentage_to_completion. (Although this may be more suitable for the web and mobile apps) 1. Local implementation of amount_to_precision, cost_to_precision and price_to_precision. (Unless the plan is to continue to use CCXT forever) 2. Instead of cancelling and resending the take profit order, edit it (Kucoin only supports editing on high frequency orders) -3. Round-robin trading pairs: Instead of a fixed list of trading pairs, after n closed deals the trader is terminated and a new one spawns, picking the trading pair +3. When autoswitching to long, instead of using a big market order, the last safety order should be a sell order of all the available funds. +4. Round-robin trading pairs: Instead of a fixed list of trading pairs, after n closed deals the trader is terminated and a new one spawns, picking the trading pair from a pre-populated list (the trading pairs can be selected by using Yang-Zhang, Parkinson or another volatility indicator) This could be very benefitial, since it limits the long time commitment to a small list of trading pairs, enabling the instance to react to market trends very rapidly. diff --git a/trader.py b/trader.py index 89dffea..24f0498 100755 --- a/trader.py +++ b/trader.py @@ -1086,7 +1086,7 @@ class trader: ''' Main routine. It checks for closed orders and proceeds accordingly. ''' - + #It does not even try if it receives an empty list or the worker is paused if open_orders==[] or self.pause: self.update_status(False) @@ -1150,14 +1150,14 @@ class trader: self.broker.logger.log_this("Take profit order closed but not filled, trader restart disabled.",1,self.status.get_pair()) return 1 elif tp_status["status"]=="canceled": - #TODO: Here, if the safety order is still open, we could resend the tp order. - if self.config.get_attempt_restart(): - self.broker.logger.log_this("Take profit order canceled. Restarting the trader.",1,self.status.get_pair()) - self.status.save_to_file(is_backup=True) - self.restart = True - else: - self.broker.logger.log_this("Take profit order canceled. Trader restart disabled.",1,self.status.get_pair()) - return 1 + #TODO: Here, if the safety order is still open, we could resend the tp order. + if self.config.get_attempt_restart(): + self.broker.logger.log_this("Take profit order canceled. Restarting the trader.",1,self.status.get_pair()) + self.status.save_to_file(is_backup=True) + self.restart = True + else: + self.broker.logger.log_this("Take profit order canceled. Trader restart disabled.",1,self.status.get_pair()) + return 1 elif tp_status["status"]=="": self.broker.logger.log_this(f"Take profit order search returned empty order. Order ID: {tp_status['id']}",1,self.status.get_pair()) return 1