From 7d90b7d8333ab35191617b4b54606303685374b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20S=C3=A1nchez?= Date: Mon, 3 Mar 2025 10:01:05 -0300 Subject: [PATCH] 2025.03.03 --- changelog.txt | 5 + config_handler.py | 2 +- main.py | 119 +++++++++---- todo.txt | 5 +- trader.py | 431 ++++++++++++++++++++++----------------------- utils/commander.py | 16 +- 6 files changed, 318 insertions(+), 260 deletions(-) diff --git a/changelog.txt b/changelog.txt index 972eb37..a51d544 100755 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,8 @@ +2025.03.03: +. Replaced more variables with their respective config handlers. +. Added a new API endpoint: reload_trader_config. +. Removed the config reloading when a trader closes a deal. + 2025.03.02: . Fixed an error in restart_pair_no_json() diff --git a/config_handler.py b/config_handler.py index bb897a3..d73fbd0 100644 --- a/config_handler.py +++ b/config_handler.py @@ -40,7 +40,7 @@ class ConfigHandler: self.load_from_file() if config_dict is not None: self.config_dictionary = {**self.config_dictionary, **config_dict} - self.save_to_file() + self.save_to_file() diff --git a/main.py b/main.py index 1083169..b1d82a5 100644 --- a/main.py +++ b/main.py @@ -24,7 +24,7 @@ In case the permissions of the certificate changes, reset them this way: # ll /etc/letsencrypt/ ''' -version = "2025.03.02" +version = "2025.03.03" ''' Color definitions. If you want to change them, check the reference at https://en.wikipedia.org/wiki/ANSI_escape_code#Colors @@ -240,7 +240,7 @@ def restart_pair_no_json(base: str, quote: str) -> int: try: order_list = broker.fetch_full_orders(tickers) for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): x.pause = True #Backing up old status file x.status.save_to_file(is_backup=True) @@ -270,17 +270,17 @@ def main_loop(): #Restart traders that have the restart flag raised and remove traders that have the quit flag raised for x in running_instances: if x.restart and x.config.get_attempt_restart(): - broker.logger.log_this(f"Restarting trader",1,x.pair) + broker.logger.log_this(f"Restarting trader",1,x.config.get_pair()) restart_pair_no_json(x.base,x.quote) if x.quit: #Here, check if a duster is needed - broker.logger.log_this(f"Quit flag raised, removing pair.",0,x.pair) + broker.logger.log_this(f"Quit flag raised, removing pair.",0,x.config.get_pair()) if f"{x.base}{x.quote}" in tickers: tickers.remove(f"{x.base}{x.quote}") broker.remove_pair_from_config(f"{x.base}{x.quote}") broker.rewrite_config_file() - if x.pair in worker_status: - del(worker_status[x.pair]) + if x.config.get_pair() in worker_status: + del(worker_status[x.config.get_pair()]) running_instances.remove(x) #Adds pending traders @@ -296,7 +296,7 @@ def main_loop(): for x in running_instances: threads.append(Thread(target=x.check_status,args=(open_orders,))) online_pairs.append(f"{x.base}{x.quote}") - pairs_to_fetch.append(x.pair) + pairs_to_fetch.append(x.config.get_pair()) #Here, append the dusters' pairs to pairs_to_fetch, if missing. # @@ -333,11 +333,11 @@ def main_loop(): top += int(x.config.get_no_of_safety_orders()) # It shows the percentage of safety orders not filled if not x.quit: #Why? Maybe to protect return_status() from weird errors if the trader errored out? try: - if x.pair in price_list and price_list[x.pair] is not None: - x.get_status_dict()["price"] = price_list[x.pair] + if x.config.get_pair() in price_list and price_list[x.config.get_pair()] is not None: + x.get_status_dict()["price"] = price_list[x.config.get_pair()] except Exception as e: - broker.logger.log_this(f"Exception while querying for pair price, key not present on price_list dictionary: {e}",1,x.pair) - worker_status[x.pair] = x.get_status_dict() + broker.logger.log_this(f"Exception while querying for pair price, key not present on price_list dictionary: {e}",1,x.config.get_pair()) + worker_status[x.config.get_pair()] = x.get_status_dict() #Clear the screen buffer screen_buffer.clear() @@ -354,14 +354,14 @@ def main_loop(): global_status["online_workers"] = online_pairs.copy() #Check for paused pairs - global_status["paused_traders"] = [x.pair for x in running_instances if x.pause] + global_status["paused_traders"] = [x.config.get_pair() for x in running_instances if x.pause] if global_status["paused_traders"]: screen_buffer.append(f"{cyan}Paused pairs: {list(global_status['paused_traders'])}{white}") #Check for paused pairs for x in running_instances: if x.pause: - screen_buffer.append(f"{x.pair} paused: {x.get_status_dict()['pause_reason']}") + screen_buffer.append(f"{x.config.get_pair()} paused: {x.get_status_dict()['pause_reason']}") #Prints general info instance_uptime = int(time.time()) - instance_start_time @@ -395,7 +395,7 @@ def main_loop(): #Toggle pauses if toggle_pauses: for instance in running_instances: - if instance.pair in toggle_pauses: + if instance.config.get_pair() in toggle_pauses: instance.pause = not instance.pause toggle_pauses.clear() @@ -1226,6 +1226,30 @@ def reload_safety_order(): return jsonify({'Error': 'API key invalid'}), 401 +@base_api.route("/reload_trader_config", methods=['POST'])#type:ignore +def reload_trader_config(): + ''' + POST request + + Parameters: + base: str + quote: str + ''' + + if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: + try: + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + data = request.json + base = data["base"] + quote = data["quote"] + return unwrapped_reload_trader_config(base,quote) + except Exception as e: + print(e) + return jsonify({'Error': 'Halp'}) + return jsonify({'Error': 'API key invalid'}), 401 + + def run_API(): serve(base_api, host="0.0.0.0", port=broker.get_config()["port"], threads=16) #base_api.run(host="0.0.0.0", port=broker.get_config()["port"]) @@ -1294,7 +1318,7 @@ def unwrapped_add_pair(base,quote): try: #Check if the trader is already running for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): broker.logger.log_this(f"Pair already running",1,f"{base}/{quote}") return jsonify({"Error": "Pair already running"}) @@ -1348,7 +1372,7 @@ def unwrapped_remove_pair(base,quote): try: for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): x.quit = True return jsonify({"Success": "Pair to be removed"}) except Exception as e: @@ -1414,7 +1438,7 @@ def unwrapped_switch_to_long(base,quote,calculate_profits): if f"{base}{quote}" not in broker.get_pairs(): return jsonify({"Error": "Pair not running"}) for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): x.pause = True if x.switch_to_long(ignore_old_long=ignore_old_long)==1: return jsonify({"Error": "Error in switch_to_long()"}) @@ -1441,14 +1465,14 @@ def unwrapped_switch_to_short(base,quote): if f"{base}{quote}" not in broker.get_pairs(): return jsonify({"Error": "Pair not running"}) for x in running_instances: - if f"{base}/{quote}"==x.pair and x.switch_to_short()==1: + if f"{base}/{quote}"==x.config.get_pair() and x.switch_to_short()==1: return jsonify({"Error": "Error in switch_to_short()"}) #Restart instance try: broker.logger.log_this(f"Reinitializing trader",2,f"{base}/{quote}") for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): x.status.set_take_profit_order(x.broker.empty_order) x.so = x.broker.empty_order @@ -1496,7 +1520,7 @@ def unwrapped_load_old_long(base,quote): #Creates (or modifies) a key in the status dictionary and assigns the contents of the file to that same key. for x in running_instances: - if x.pair==f"{base}/{quote}": + if x.config.get_pair()==f"{base}/{quote}": x.get_status_dict()["old_long"]=old_long x.update_status(True) return jsonify({"Success": "old_long file loaded to status_dict"}) @@ -1522,7 +1546,7 @@ def unwrapped_view_old_long(base,quote,from_file): old_long = json.load(ol) return jsonify(old_long) for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): if "old_long" in x.get_status_dict(): return jsonify(x.get_status_dict()["old_long"]) return jsonify({"Error": "No old_long info found"}) @@ -1547,7 +1571,7 @@ def unwrapped_switch_to_long_price(base,quote): try: for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): if "old_long" in x.get_status_dict(): #minimum_switch_price = (old_target - quote_already_in)/base_left old_target = x.get_status_dict()["old_long"]["tp_price"]*x.get_status_dict()["old_long"]["tp_amount"] @@ -1577,7 +1601,7 @@ def unwrapped_add_safety_orders(base,quote,amount): try: for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): x.pause = True #x.no_of_safety_orders += int(amount) x.config.set_no_of_safety_orders(x.config.get_no_of_safety_orders()+int(amount)) @@ -1608,7 +1632,7 @@ def unwrapped_mod_tp_level(base,quote,amount): try: for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): x.config.set_tp_level(float(amount)) broker.logger.log_this("Done. The change will take effect when the next take profit order is placed",2,f"{base}/{quote}") return jsonify({"Success": "Success. The change will take effect when the next TP order is placed"}) @@ -1652,7 +1676,7 @@ def unwrapped_last_call(base,quote): try: if f"{base}{quote}" in broker.get_pairs(): for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): x.stop_when_profit = not x.stop_when_profit x.update_status(True) if x.stop_when_profit: @@ -1684,7 +1708,7 @@ def unwrapped_deferred_last_call(base,quote,yyyymmdd): if limit==0: return jsonify({"Error": "Can't convert date to unix"}) for x in running_instances: - if f"{base}{quote}"==x.pair: + if f"{base}{quote}"==x.config.get_pair(): x.config.set_programmed_stop_time(limit) x.config.set_programmed_stop(True) #save config file to disk @@ -1710,7 +1734,7 @@ def unwrapped_toggle_pause(base,quote): try: toggle_pauses.append(f"{base}/{quote}") for instance in running_instances: - if instance.pair==f"{base}/{quote}": + if instance.config.get_pair()==f"{base}/{quote}": if instance.pause: return jsonify({"Success": "Trader will be resumed"}) return jsonify({"Success": "Trader will be paused"}) @@ -1772,21 +1796,21 @@ def unwrapped_add_quote(base,quote,amount): ''' for x in running_instances: - if f"{base}/{quote}"==x.pair: + if f"{base}/{quote}"==x.config.get_pair(): if x.config.get_is_short(): return jsonify({"Error": "Quote can't be added to short bots"}) x.pause = True new_average_price = (x.status.get_quote_spent()+float(amount))/(x.status.get_base_bought()+(float(amount)/x.get_status_dict()["price"])) broker.logger.log_this(f"Your new average buy price will be {new_average_price} {x.quote}",2,f"{base}/{quote}") broker.logger.log_this(f"Your new take profit price price will be {new_average_price*x.get_tp_level()} {x.quote}",2,f"{base}/{quote}") - new_order = broker.new_market_order(x.pair,float(amount),"buy") + new_order = broker.new_market_order(x.config.get_pair(),float(amount),"buy") if new_order is None: broker.logger.log_this("Error: Market order returned None",2,f"{base}/{quote}") x.pause = False return jsonify({"Error": "Market order returned None"}) while True: time.sleep(broker.get_wait_time()) - returned_order = broker.get_order(new_order["id"],x.pair) + returned_order = broker.get_order(new_order["id"],x.config.get_pair()) if returned_order==broker.empty_order: broker.logger.log_this("Problems sending the order",2,f"{base}/{quote}") x.pause = False @@ -1803,7 +1827,7 @@ def unwrapped_add_quote(base,quote,amount): x.status.set_quote_spent(x.status.get_quote_spent()+returned_order["cost"]) broker.logger.log_this("Cancelling old take profit order and sending a new one",2,f"{base}/{quote}") attempts = 5 - while broker.cancel_order(x.status.get_tp_order_id(),x.pair)==1: + while broker.cancel_order(x.status.get_tp_order_id(),x.config.get_pair())==1: broker.logger.log_this("Can't cancel old take profit order, retrying...",2,f"{base}/{quote}") time.sleep(broker.get_wait_time()) attempts-=1 @@ -1812,7 +1836,7 @@ def unwrapped_add_quote(base,quote,amount): x.pause = False return jsonify({"Error": "Can't cancel old take profit order."}) x.status.set_take_profit_price(x.status.get_quote_spent()/x.status.get_base_bought()*x.get_tp_level()) - x.status.set_take_profit_order(broker.new_limit_order(x.pair,x.status.get_base_bought(),"sell",x.status.get_take_profit_price())) + x.status.set_take_profit_order(broker.new_limit_order(x.config.get_pair(),x.status.get_base_bought(),"sell",x.status.get_take_profit_price())) x.update_status(True) break else: @@ -1858,7 +1882,7 @@ def unwrapped_toggle_cleanup(base,quote): try: pair_to_toggle = f"{base}/{quote}" for x in running_instances: - if pair_to_toggle==x.pair: + if pair_to_toggle==x.config.get_pair(): x.config.set_cleanup(not x.config.get_cleanup()) if x.config.get_cleanup(): return jsonify({"Success": "Cleanup turned ON"}) @@ -1884,7 +1908,7 @@ def unwrapped_toggle_autoswitch(base,quote): try: pair_to_toggle = f"{base}/{quote}" for x in running_instances: - if pair_to_toggle==x.pair: + if pair_to_toggle==x.config.get_pair(): if x.config.get_autoswitch(): broker.logger.log_this("Autoswitch turned OFF",1,f"{base}/{quote}") x.config.set_autoswitch(False) @@ -1913,7 +1937,7 @@ def unwrapped_toggle_check_old_long_price(base,quote): try: pair_to_toggle = f"{base}/{quote}" for x in running_instances: - if pair_to_toggle==x.pair: + if pair_to_toggle==x.config.get_pair(): if x.config.get_check_old_long_price(): broker.logger.log_this("Check OFF",1,f"{base}/{quote}") x.config.set_check_old_long_price(False) @@ -1943,7 +1967,7 @@ def unwrapped_switch_quote_currency(base,quote,new_quote): try: pair_to_switch = f"{base}/{quote}" for trader in running_instances: - if pair_to_switch==trader.pair: + if pair_to_switch==trader.config.get_pair(): #Pause the trader trader.pause = True @@ -2122,9 +2146,10 @@ def unwrapped_reload_safety_order(base,quote): ''' try: for trader in running_instances: - if trader.pair==f"{base}/{quote}": - trader.reload_safety_order() - return jsonify({"Success": "Safety order reloaded successfully"}) + if trader.config.get_pair()==f"{base}/{quote}": + trader.config.load_from_file() + return jsonify({"Success": "Safety order reloaded successfully"}) + return jsonify({"Error": "Trader not found"}) except Exception as e: broker.logger.log_this(f"Exception while reloading safety order: {e}",1) return jsonify({"Error": "Safety order couldn't be reloaded"}) @@ -2149,7 +2174,23 @@ def unwrapped_get_balance(coin): except Exception as e: broker.logger.log_this(f"Exception while querying balance: {e}",1) return jsonify({"Error": "Balance could not be queried"}) + + +def unwrapped_reload_trader_config(base,quote): + ''' + Reloads the config file of the trader + Parameters: + base (str): The base currency of the pair. + quote (str): The quote currency of the pair. + + Returns: + jsonify: A jsonified dictionary detailing the outcome of the operation. + ''' + for trader in running_instances: + if trader.config.get_pair() == f"{base}/{quote}": + return jsonify(worker_status[f"{base}/{quote}"]) + return jsonify({"Error": "Worker does not exist"}) if __name__=="__main__": diff --git a/todo.txt b/todo.txt index 60b80ad..f73d8aa 100755 --- a/todo.txt +++ b/todo.txt @@ -9,11 +9,10 @@ Mandatory: 6. Multiple safety orders open at the same time (to catch big volatility spikes more effectively) 7. Things that should be objects (it's not 1994): * Orders. - * Config object (instead of a config dictionary). - * Status object (instead of a status dictionary). + * Config (parameter validation remains to be implemented). + * Status (parameter validation remains to be implemented). 8. Implement the ability to add safety orders to a short trader depending on the amount of free funds available, not just any number of orders. 9. API documentation. -10. Do not reload the config file every time a deal is closed and add an API endpoint to do it. Would be nice to have: diff --git a/trader.py b/trader.py index 5d31096..c54f415 100755 --- a/trader.py +++ b/trader.py @@ -7,24 +7,26 @@ from status_handler import StatusHandler class trader: def __init__(self, broker, pair: str, is_import: bool = False): - self.pause = True #Signals the trader to not process order info when an API call manhandles the trader - #True by default, once the trader is started the start_trader method toggles it + + #Flags + self.pause = True self.quit = False self.restart = False - self.broker = broker - self.config = ConfigHandler(pair,broker) - self.pair = self.config.get_pair() - self.base,self.quote = self.pair.split("/") - self.status = StatusHandler(broker, self.base, self.quote) - self.market = self.broker.fetch_market(self.pair) - self.market_load_time = int(time.time()) - self.market_reload_period = 86400 #Market reload period in seconds - self.status.set_start_time(int(time.time())) - self.last_time_seen = time.time() self.warnings = { "short_price_exceeds_old_long": False, "speol_notified": False } + + + self.broker = broker + self.config = ConfigHandler(pair,broker) + self.base,self.quote = self.config.get_pair().split("/") + self.status = StatusHandler(broker, self.base, self.quote) + self.market = self.broker.fetch_market(self.config.get_pair()) + self.market_load_time = int(time.time()) + self.market_reload_period = 86400 #Market reload period in seconds + self.status.set_start_time(int(time.time())) + self.last_time_seen = time.time() if self.config.get_is_short(): #Check if there is an old_long file. If so, load it. @@ -32,11 +34,11 @@ class trader: with open(f"status/{self.base}{self.quote}.oldlong") as ol: self.status.set_old_long(json.load(ol)) except Exception as e: - self.broker.logger.log_this(f"Exception: No old_long file. {e}",1,self.pair) + self.broker.logger.log_this(f"Exception: No old_long file. {e}",1,self.config.get_pair()) self.profit_filename = f"profits/{self.base}{self.quote}.profits" self.log_filename = f"logs/{self.base}{self.quote}.log" - self.deals_timestamps = self.broker.get_trades_timestamps(self.pair,self.config.get_boosted_time_range()) + self.deals_timestamps = self.broker.get_trades_timestamps(self.config.get_pair(),self.config.get_boosted_time_range()) self.status.set_pause_reason("Initialization") if is_import: @@ -84,7 +86,7 @@ class trader: Reloads the safety order. ''' - self.status.set_safety_order(self.broker.get_order(self.status.get_safety_order()["id"],self.pair)) + self.status.set_safety_order(self.broker.get_order(self.status.get_safety_order()["id"],self.config.get_pair())) return 0 @@ -101,7 +103,7 @@ class trader: self.status.set_safety_order(self.broker.get_empty_order()) #Reloads the market - new_market_data = self.broker.fetch_market(self.pair) + new_market_data = self.broker.fetch_market(self.config.get_pair()) if new_market_data is not None: self.market = new_market_data @@ -109,70 +111,70 @@ class trader: self.status.set_pause_reason("start_trader") if self.config.get_is_short(): - self.broker.logger.log_this("Calculating optimal order size...",2,self.pair) + self.broker.logger.log_this("Calculating optimal order size...",2,self.config.get_pair()) #Get minimum order size from exchange - self.broker.logger.log_this("Fetching minimum order size...",2,self.pair) - min_base_size = self.broker.get_min_base_size(self.pair) + self.broker.logger.log_this("Fetching minimum order size...",2,self.config.get_pair()) + min_base_size = self.broker.get_min_base_size(self.config.get_pair()) if min_base_size is None: - self.broker.logger.log_this("Can't fetch the minimum order size",1,self.pair) + self.broker.logger.log_this("Can't fetch the minimum order size",1,self.config.get_pair()) return 1 #Fetch the amount of free base available on the exchange - self.broker.logger.log_this("Fetching free base currency on the exchange...",2,self.pair) + self.broker.logger.log_this("Fetching free base currency on the exchange...",2,self.config.get_pair()) free_base = self.fetch_free_base() if free_base is None: - self.broker.logger.log_this("Can't fetch the amount of base at the exchange",1,self.pair) + self.broker.logger.log_this("Can't fetch the amount of base at the exchange",1,self.config.get_pair()) return 1 #Buy missing base sold because of rounding errors (rare) if self.status.get_old_long()!={}: diff = self.status.get_old_long()["tp_amount"] - free_base if diff>min_base_size: - diff = self.broker.amount_to_precision(self.pair,diff) - self.broker.logger.log_this(f"Buying missing {diff} {self.base}",1,self.pair) - self.broker.new_market_order(self.pair,diff,"buy",amount_in_base=True) + diff = self.broker.amount_to_precision(self.config.get_pair(),diff) + self.broker.logger.log_this(f"Buying missing {diff} {self.base}",1,self.config.get_pair()) + self.broker.new_market_order(self.config.get_pair(),diff,"buy",amount_in_base=True) time.sleep(self.broker.get_wait_time()*2) #Re-quering for the amount of base currency on the exchange free_base = self.fetch_free_base() if free_base is None: - self.broker.logger.log_this("Can't fetch the amount of base at the exchange",1,self.pair) + self.broker.logger.log_this("Can't fetch the amount of base at the exchange",1,self.config.get_pair()) return 1 #Calculate order size and amount of safety orders - self.broker.logger.log_this("Calculating the order size...",2,self.pair) + self.broker.logger.log_this("Calculating the order size...",2,self.config.get_pair()) order_size,no_of_safety_orders = self.calculate_order_size(free_base,min_base_size,self.config.get_max_short_safety_orders()) if order_size is None or no_of_safety_orders is None: - self.broker.logger.log_this("Can't calculate optimal size",1,self.pair) + self.broker.logger.log_this("Can't calculate optimal size",1,self.config.get_pair()) return 1 self.config.set_order_size(order_size) self.config.set_no_of_safety_orders(no_of_safety_orders) - self.broker.logger.log_this(f"Order size: {self.broker.amount_to_precision(self.pair,order_size)}. Amount of safety orders: {no_of_safety_orders}",2,self.pair) + self.broker.logger.log_this(f"Order size: {self.broker.amount_to_precision(self.config.get_pair(),order_size)}. Amount of safety orders: {no_of_safety_orders}",2,self.config.get_pair()) #Write the changes to the config file self.config.save_to_file() else: #Check order size self.status.set_pause_reason("start_trader - checking order size") - self.broker.logger.log_this("Checking for order size",2,self.pair) - minimum_order_size_allowed = self.broker.get_min_quote_size(self.pair) + self.broker.logger.log_this("Checking for order size",2,self.config.get_pair()) + minimum_order_size_allowed = self.broker.get_min_quote_size(self.config.get_pair()) if minimum_order_size_allowed is not None and minimum_order_size_allowed>self.config.get_order_size(): - self.broker.logger.log_this(f"Order size too small. Minimum order size is {minimum_order_size_allowed} {self.quote}",1,self.pair) + self.broker.logger.log_this(f"Order size too small. Minimum order size is {minimum_order_size_allowed} {self.quote}",1,self.config.get_pair()) if minimum_order_size_allowed0: - #step = self.broker.amount_to_precision(self.pair,min_size/divisor) + #step = self.broker.amount_to_precision(self.config.get_pair(),min_size/divisor) step = min_size/divisor if step!=0: #When using amount_to_precision, this comes handy. break divisor-=1 #if step==0: - # step = self.broker.amount_to_precision(self.pair,min_size) + # step = self.broker.amount_to_precision(self.config.get_pair(),min_size) previous_size = 0 while True: #This loop should have a safeguard - self.broker.logger.log_this(f"Calculating optimal order size ...",2,self.pair) + self.broker.logger.log_this(f"Calculating optimal order size ...",2,self.config.get_pair()) total_cost = self.dca_cost_calculator(total_size,amount_of_safety_orders,scalar) if total_cost>=amount: return previous_size @@ -378,7 +380,7 @@ class trader: # try: # fee_rate = self.market["maker"] if order["type"]=="limit" else self.market["taker"] # except Exception as e: - # self.broker.logger.log_this(f"Exception fetching market information: {e}. Using default fee rate of 0.1%",1,self.pair) + # self.broker.logger.log_this(f"Exception fetching market information: {e}. Using default fee rate of 0.1%",1,self.config.get_pair()) # fee_rate = 0.001 # # if order["side"]=="buy": @@ -411,21 +413,21 @@ class trader: return 0 balance_to_clean = self.fetch_free_base() if balance_to_clean is None: - self.broker.logger.log_this("Can't fetch free base",1,self.pair) + self.broker.logger.log_this("Can't fetch free base",1,self.config.get_pair()) return 1 #balance_to_clean /= 2 #Maybe it's a good idea, sort of DCAing the dust. - min_base_size = self.broker.get_min_base_size(self.pair) + min_base_size = self.broker.get_min_base_size(self.config.get_pair()) minimum_cleanup_size = self.status.get_safety_order()["amount"]*2 # type: ignore if balance_to_clean-minimum_cleanup_size >= min_base_size: - self.broker.logger.log_this(f"Balance to clean: {balance_to_clean-minimum_cleanup_size} {self.base}",2,self.pair) - self.broker.logger.log_this("Sending cleanup order...",2,self.pair) - cleanup_order = self.broker.new_limit_order(self.pair,balance_to_clean-minimum_cleanup_size,"sell",self.status.get_take_profit_price()) + self.broker.logger.log_this(f"Balance to clean: {balance_to_clean-minimum_cleanup_size} {self.base}",2,self.config.get_pair()) + self.broker.logger.log_this("Sending cleanup order...",2,self.config.get_pair()) + cleanup_order = self.broker.new_limit_order(self.config.get_pair(),balance_to_clean-minimum_cleanup_size,"sell",self.status.get_take_profit_price()) if cleanup_order not in [None,self.broker.get_empty_order()]: - self.broker.logger.log_this("Cleanup successful",2,self.pair) + self.broker.logger.log_this("Cleanup successful",2,self.config.get_pair()) return 0 - self.broker.logger.log_this("Problems with the cleanup order",1,self.pair) + self.broker.logger.log_this("Problems with the cleanup order",1,self.config.get_pair()) return 1 - self.broker.logger.log_this("No cleanup needed",2,self.pair) + self.broker.logger.log_this("No cleanup needed",2,self.config.get_pair()) return 0 @@ -439,16 +441,16 @@ class trader: while amount_of_so>minimum_amount_of_safety_orders: optimal_order_size = self.return_optimal_order_size(free_base,min_base_size,amount_of_so,self.config.get_safety_order_scale()) #safety_order_scale: safety order growth factor if optimal_order_size!=0: - self.broker.logger.log_this(f"Optimal order size is {optimal_order_size}",2,self.pair) + self.broker.logger.log_this(f"Optimal order size is {optimal_order_size}",2,self.config.get_pair()) break amount_of_so-=1 if optimal_order_size==0: - self.broker.logger.log_this("Not enough base to switch. Order size would be too small",1,self.pair) + self.broker.logger.log_this("Not enough base to switch. Order size would be too small",1,self.config.get_pair()) self.pause = False self.status.set_pause_reason("") return None,None if optimal_order_size0: - self.broker.logger.log_this(f"Old safety order is partially filled, ID: {old_so_order['id']}",1,self.pair) + self.broker.logger.log_this(f"Old safety order is partially filled, ID: {old_so_order['id']}",1,self.config.get_pair()) self.status.update_deal_order_history(old_so_order) self.status.set_base_bought(self.status.get_base_bought() + old_so_order["filled"] - self.parse_fees(old_so_order)[0]) self.status.set_quote_spent(self.status.get_quote_spent + old_so_order["cost"]) @@ -760,14 +762,14 @@ class trader: self.profit_to_file(profit,filled_order["id"]) self.profit_to_db(profit,filled_order["id"],self.broker.get_write_order_history()) else: #For logging purposes - self.broker.logger.log_this(f"NEGATIVE PROFIT - Total amount of base: {self.status.get_base_bought()}, base in the order: {filled_order['amount']}, base filled: {filled_order['filled']}, base 'profit': {base_profit}",1,self.pair) + self.broker.logger.log_this(f"NEGATIVE PROFIT - Total amount of base: {self.status.get_base_bought()}, base in the order: {filled_order['amount']}, base filled: {filled_order['filled']}, base 'profit': {base_profit}",1,self.config.get_pair()) self.telegram_bot_sendprofit(profit,filled_order,base_profit=base_profit) # Print profit message on screen extra = ' and {:.4f}'.format(base_profit) + f" {self.base}" if base_profit>0 else "" - self.broker.logger.log_this(f"Trader closed a deal. Profit: {'{:.4f}'.format(profit)} {self.quote}{extra}",2,self.pair) - self.broker.logger.log_this(f"Fill price: {filled_order['price']} {self.quote}",2,self.pair) - self.broker.logger.log_this(f"Safety orders triggered: {self.status.get_so_amount()-1}",2,self.pair) + self.broker.logger.log_this(f"Trader closed a deal. Profit: {'{:.4f}'.format(profit)} {self.quote}{extra}",2,self.config.get_pair()) + self.broker.logger.log_this(f"Fill price: {filled_order['price']} {self.quote}",2,self.config.get_pair()) + self.broker.logger.log_this(f"Safety orders triggered: {self.status.get_so_amount()-1}",2,self.config.get_pair()) self.status.set_pause_reason("take_profit_routine - check time limit") #Checks if there is a time limit for the trader @@ -776,19 +778,18 @@ class trader: self.status.set_pause_reason("take_profit_routine - if stop_when_profit") if self.status.get_stop_when_profit(): #Signal to stop when trade is closed - self.broker.logger.log_this("Pair shutting down. So long and thanks for all the fish",0,self.pair) + self.broker.logger.log_this("Pair shutting down. So long and thanks for all the fish",0,self.config.get_pair()) self.quit = True return 1 + + #self.config.load_from_file() - # Clear variables and reload the config dictionary (Only reloading the config file is needed.) - self.status.set_pause_reason("take_profit_routine - var cleanup") - self.config.load_from_file() - + self.status.set_pause_reason("Checking slippage") if self.config.get_check_slippage(): - self.broker.logger.log_this("Checking slippage...",2,self.pair) - price_to_compare = self.broker.get_top_bid_price(self.pair) if self.config.get_is_short() else self.broker.get_top_ask_price(self.pair) + self.broker.logger.log_this("Checking slippage...",2,self.config.get_pair()) + price_to_compare = self.broker.get_top_bid_price(self.config.get_pair()) if self.config.get_is_short() else self.broker.get_top_ask_price(self.config.get_pair()) if abs(filled_order["price"]-price_to_compare)/filled_order["price"]>self.broker.get_slippage_default_threshold(): - self.broker.logger.log_this(f"Slippage threshold exceeded, waiting for cooldown and restarting trader",1,self.pair) + self.broker.logger.log_this(f"Slippage threshold exceeded, waiting for cooldown and restarting trader",1,self.config.get_pair()) time.sleep(self.broker.get_wait_time()*self.broker.get_cooldown_multiplier()) #The trader is restarted by the instance instead of by itself to allow a couple of more seconds for the price to return to normal. #This could also be the default behavior. @@ -796,7 +797,7 @@ class trader: self.restart = True return 1 elif self.check_orderbook_depth(self.broker.get_slippage_default_threshold(),self.config.get_order_size(),filled_order["price"]): - self.broker.logger.log_this(f"Orderbook depth not sufficient, waiting for cooldown and restarting trader",1,self.pair) + self.broker.logger.log_this(f"Orderbook depth not sufficient, waiting for cooldown and restarting trader",1,self.config.get_pair()) time.sleep(self.broker.get_wait_time()*self.broker.get_cooldown_multiplier()) self.pause = False self.restart = True @@ -816,7 +817,7 @@ class trader: self.pause = False self.restart = True self.status.save_to_file(is_backup=True) - self.broker.logger.log_this(restart_errors[restart_trader],1,self.pair) + self.broker.logger.log_this(restart_errors[restart_trader],1,self.config.get_pair()) return restart_trader @@ -830,10 +831,10 @@ class trader: #Let's do some type checking first if self.status.get_take_profit_order() is None: - self.broker.logger.log_this("Take profit order is None, can't send a new safety order",1,self.pair) + self.broker.logger.log_this("Take profit order is None, can't send a new safety order",1,self.config.get_pair()) return 1 if self.status.get_safety_order() is None: #I don't think this is necessary - self.broker.logger.log_this("Safety order is None, can't send a new safety order",1,self.pair) + self.broker.logger.log_this("Safety order is None, can't send a new safety order",1,self.config.get_pair()) return 1 self.pause = True @@ -853,10 +854,10 @@ class trader: # Send the new safety order. If all expected safety orders are filled, it assigns an empty order to self.status.get_safety_order() if send_new_so: - self.broker.logger.log_this("Sending a new safety order",2,self.pair) + self.broker.logger.log_this("Sending a new safety order",2,self.config.get_pair()) if self.send_new_safety_order(self.status.get_order_size())==1: error_string = "Problems sending the new safety order. Maybe not enough funds?" - self.broker.logger.log_this(error_string,1,self.pair) + self.broker.logger.log_this(error_string,1,self.config.get_pair()) self.status.set_pause_reason(error_string) return 1 else: @@ -864,18 +865,18 @@ class trader: self.status.set_so_amount(self.status.get_so_amount()+1) # Cancel the old tp order - if self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.pair)==1: - error_string = f"{self.pair} | {self.status.get_take_profit_order()['id']} | Old TP order probably filled. Can't cancel. This trader should be restarted" - self.broker.logger.log_this(f"Old take profit order is probably filled, can't cancel. This trader should be restarted. Order ID: {self.status.get_take_profit_order()['id']}",1,self.pair) + if self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.config.get_pair())==1: + error_string = f"{self.config.get_pair()} | {self.status.get_take_profit_order()['id']} | Old TP order probably filled. Can't cancel. This trader should be restarted" + self.broker.logger.log_this(f"Old take profit order is probably filled, can't cancel. This trader should be restarted. Order ID: {self.status.get_take_profit_order()['id']}",1,self.config.get_pair()) self.status.set_pause_reason(error_string) return 2 # Check if the old tp order was partially filled. If so, update the previous two variables accordingly # TODO: This should also be taken into account for the profit calculation # Do the partial profit calculation and save it for later - old_tp_order = self.broker.get_order(self.status.get_take_profit_order()["id"],self.pair) + old_tp_order = self.broker.get_order(self.status.get_take_profit_order()["id"],self.config.get_pair()) if old_tp_order["filled"]>0: - self.broker.logger.log_this(f"Old take profit order is partially filled, id {old_tp_order['id']}",1,self.pair) + self.broker.logger.log_this(f"Old take profit order is partially filled, id {old_tp_order['id']}",1,self.config.get_pair()) self.status.update_deal_order_history(old_tp_order) #self.status.set_base_bought(old_tp_order["remaining"]) # Partial profit calculation @@ -897,7 +898,7 @@ class trader: # Send the new take profit order if self.send_new_tp_order()==1: error_string = "Problems sending the new take profit order" - self.broker.logger.log_this("Problems sending the new take profit order",1,self.pair) + self.broker.logger.log_this("Problems sending the new take profit order",1,self.config.get_pair()) self.status.set_pause_reason(error_string) return 3 @@ -925,7 +926,7 @@ class trader: self.warnings["speol_notified"] = True if not self.config.get_autoswitch(): message = f"{self.base}@{self.status.get_price()} ({str(self.broker.exchange)}), exceeds old long price of {self.status.get_old_long()['tp_price']}" - self.broker.logger.log_this(message,0,self.pair) + self.broker.logger.log_this(message,0,self.config.get_pair()) return 0 @@ -946,9 +947,9 @@ class trader: if self.config.get_is_short(): #Do not check for slippage in short traders (Pending to be implemented) return False - order_book = self.broker.get_order_book(self.pair,no_retries=True) + order_book = self.broker.get_order_book(self.config.get_pair(),no_retries=True) if order_book=={}: - self.broker.logger.log_this("Can't fetch orderbook",1,self.pair) + self.broker.logger.log_this("Can't fetch orderbook",1,self.config.get_pair()) return False suma = 0 try: @@ -968,7 +969,7 @@ class trader: return True return False except Exception as e: - self.broker.logger.log_this(f"Exception in check_orderbook_depth: {e}",1,self.pair) + self.broker.logger.log_this(f"Exception in check_orderbook_depth: {e}",1,self.config.get_pair()) return False @@ -983,61 +984,61 @@ class trader: return 0 #Extract ids from order list - open_orders_ids = [order["id"] for order in open_orders if order["symbol"]==self.pair] + open_orders_ids = [order["id"] for order in open_orders if order["symbol"]==self.config.get_pair()] #Checks if the orders are valid if self.status.get_take_profit_order() is None: - self.broker.logger.log_this("Take profit order is None",1,self.pair) + self.broker.logger.log_this("Take profit order is None",1,self.config.get_pair()) return 1 if self.status.get_safety_order() is None: #Here, would it be wise to attempt to reload the safety order from the status dict? - self.broker.logger.log_this("Safety order is None",1,self.pair) + self.broker.logger.log_this("Safety order is None",1,self.config.get_pair()) self.status.set_safety_order(self.broker.get_empty_order()) #return 1 if self.status.get_take_profit_order()["id"]=="": - self.broker.logger.log_this(f"Take profit order missing. Stopping bot. No order ID was provided.",1,self.pair) - self.broker.cancel_order(self.status.get_safety_order()["id"],self.pair) + self.broker.logger.log_this(f"Take profit order missing. Stopping bot. No order ID was provided.",1,self.config.get_pair()) + self.broker.cancel_order(self.status.get_safety_order()["id"],self.config.get_pair()) if self.config.get_attempt_restart(): self.status.save_to_file(is_backup=True) self.restart = True - self.broker.logger.log_this("Raising restart flag: take profit order missing, trader will be restarted",0,self.pair) + self.broker.logger.log_this("Raising restart flag: take profit order missing, trader will be restarted",0,self.config.get_pair()) else: - self.broker.logger.log_this("Take profit order missing. Trader restart disabled.",2,self.pair) + self.broker.logger.log_this("Take profit order missing. Trader restart disabled.",2,self.config.get_pair()) return 1 #Checks if the take profit order is filled if self.status.get_take_profit_order()["id"] not in open_orders_ids: - tp_status = self.broker.get_order(self.status.get_take_profit_order()["id"],self.pair) + tp_status = self.broker.get_order(self.status.get_take_profit_order()["id"],self.config.get_pair()) if tp_status["status"]=="closed": if tp_status["filled"]>0: return self.take_profit_routine(tp_status) - self.broker.logger.log_this(f"Take profit order closed but not filled, 0 filled. Stopping bot. Order ID: {self.status.get_take_profit_order()['id']}",1,self.pair) + self.broker.logger.log_this(f"Take profit order closed but not filled, 0 filled. Stopping bot. Order ID: {self.status.get_take_profit_order()['id']}",1,self.config.get_pair()) #Cancelling safety order and stopping bot - self.broker.cancel_order(self.status.get_safety_order()["id"],self.pair) + self.broker.cancel_order(self.status.get_safety_order()["id"],self.config.get_pair()) if self.config.get_attempt_restart(): self.status.save_to_file(is_backup=True) self.restart = True - self.broker.logger.log_this("Take profit order closed but not filled, trader will be restarted.",0,self.pair) + self.broker.logger.log_this("Take profit order closed but not filled, trader will be restarted.",0,self.config.get_pair()) else: - self.broker.logger.log_this("Take profit order closed but not filled, trader restart disabled.",1,self.pair) + self.broker.logger.log_this("Take profit order closed but not filled, trader restart disabled.",1,self.config.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 bot.",1,self.pair) + self.broker.logger.log_this("Take profit order canceled. Restarting the bot.",1,self.config.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.pair) + self.broker.logger.log_this("Take profit order canceled. Trader restart disabled.",1,self.config.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.pair) + self.broker.logger.log_this(f"Take profit order search returned empty order. Order ID: {tp_status['id']}",1,self.config.get_pair()) return 1 # Check if safety order is filled if self.status.get_safety_order()["id"] not in open_orders_ids and self.status.get_so_amount()<=self.config.get_no_of_safety_orders(): - so_status = self.broker.get_order(self.status.get_safety_order()["id"],self.pair) - tp_order_status = self.broker.get_order(self.status.get_take_profit_order()["id"],self.pair) + so_status = self.broker.get_order(self.status.get_safety_order()["id"],self.config.get_pair()) + tp_order_status = self.broker.get_order(self.status.get_take_profit_order()["id"],self.config.get_pair()) #Now we check 2 things: #1. That the prior safety order status is indeed closed (or canceled) @@ -1053,13 +1054,13 @@ class trader: a = self.new_so_routine(so_status,self.status.get_so_amount()0: if self.status.get_base_bought()==0: - self.broker.logger.log_this("Amount of base equals 0, can't send take profit order",1,self.pair) + self.broker.logger.log_this("Amount of base equals 0, can't send take profit order",1,self.config.get_pair()) return 1 if self.config.get_is_short(): self.status.set_take_profit_price(self.status.get_quote_spent()/self.status.get_base_bought()*(1-(self.get_tp_level(self.status.get_so_amount())-1))) - self.status.set_take_profit_order(self.broker.new_limit_order(self.pair,self.status.get_base_bought(),"buy",self.status.get_take_profit_price())) + self.status.set_take_profit_order(self.broker.new_limit_order(self.config.get_pair(),self.status.get_base_bought(),"buy",self.status.get_take_profit_price())) else: self.status.set_take_profit_price(self.status.get_quote_spent()/self.status.get_base_bought()*self.get_tp_level(self.status.get_so_amount())) - self.status.set_take_profit_order(self.broker.new_limit_order(self.pair,self.status.get_base_bought(),"sell",self.status.get_take_profit_price())) + self.status.set_take_profit_order(self.broker.new_limit_order(self.config.get_pair(),self.status.get_base_bought(),"sell",self.status.get_take_profit_price())) if self.status.get_take_profit_order()==1: #This means that there was a miscalculation of base currency amount, let's correct it. if self.config.get_is_short(): #If in short mode, we don't recalculate anything. return 1 @@ -1199,7 +1200,7 @@ class trader: return 0 tries-=1 time.sleep(self.broker.get_wait_time()) - self.broker.logger.log_this("Problems sending take profit order",1,self.pair) + self.broker.logger.log_this("Problems sending take profit order",1,self.config.get_pair()) return 1 @@ -1213,7 +1214,7 @@ class trader: profit_writer = csv.writer(profit_file, delimiter=",") profit_writer.writerow([time.strftime("%Y-%m-%d"), amount, orderid]) except Exception as e: - self.broker.logger.log_this(f"Exception in profit_to_file: {e}",1,self.pair) + self.broker.logger.log_this(f"Exception in profit_to_file: {e}",1,self.config.get_pair()) return 0 @@ -1225,12 +1226,12 @@ class trader: while retries>0: try: order_history = json.dumps(self.status.get_deal_order_history()) if write_deal_order_history else "" - dataset = (time.time(),self.pair,amount,self.broker.get_exchange_name(),str(orderid),order_history) + dataset = (time.time(),self.config.get_pair(),amount,self.broker.get_exchange_name(),str(orderid),order_history) #Write profit to cache self.broker.write_profit_to_cache(dataset) return self.broker.write_profit_to_db(dataset) except Exception as e: - self.broker.logger.log_this(f"Exception while writing profit: {e}",1,self.pair) + self.broker.logger.log_this(f"Exception while writing profit: {e}",1,self.config.get_pair()) retries-=1 time.sleep(self.broker.get_wait_time()) return 1 @@ -1242,12 +1243,12 @@ class trader: ''' so_size = self.gib_so_size(size,self.status.get_so_amount()+1,self.config.get_safety_order_scale()) #safety_order_scale: safety order growth factor if self.config.get_is_short(): - new_order = self.broker.new_limit_order(self.pair,so_size,"sell",self.status.get_safety_price_table()[self.status.get_so_amount()+1]) + new_order = self.broker.new_limit_order(self.config.get_pair(),so_size,"sell",self.status.get_safety_price_table()[self.status.get_so_amount()+1]) else: - new_order = self.broker.new_limit_order(self.pair,so_size/self.status.get_safety_price_table()[self.status.get_so_amount()+1],"buy",self.status.get_safety_price_table()[self.status.get_so_amount()+1]) + new_order = self.broker.new_limit_order(self.config.get_pair(),so_size/self.status.get_safety_price_table()[self.status.get_so_amount()+1],"buy",self.status.get_safety_price_table()[self.status.get_so_amount()+1]) if new_order==1: self.status.set_safety_order(self.broker.get_empty_order()) - self.broker.logger.log_this("Not enough balance to send a new safety order",1,self.pair) + self.broker.logger.log_this("Not enough balance to send a new safety order",1,self.config.get_pair()) #elif new_order in [None,self.broker.get_empty_order()] #MAYUBE THIS CONDITIONAL IS BETTER elif new_order is None: self.status.set_safety_order(None) @@ -1264,11 +1265,11 @@ class trader: ''' try: extra = f" and {round(base_profit,6)} {self.base}" if base_profit>0 else "" - message = f"{self.pair} closed a {'short' if self.config.get_is_short() else 'long'} trade.\nProfit: {round(profit,6)} {self.quote}{extra}\nSafety orders triggered: {self.status.get_so_amount()-1}\nTake profit price: {order['price']} {self.quote}\nTrade size: {round(order['cost'],2)} {self.quote}\nDeal uptime: {self.seconds_to_time(self.status.get_deal_uptime())}\nOrder ID: {order['id']}\nExchange: {self.broker.get_exchange_name().capitalize()}\n" + message = f"{self.config.get_pair()} closed a {'short' if self.config.get_is_short() else 'long'} trade.\nProfit: {round(profit,6)} {self.quote}{extra}\nSafety orders triggered: {self.status.get_so_amount()-1}\nTake profit price: {order['price']} {self.quote}\nTrade size: {round(order['cost'],2)} {self.quote}\nDeal uptime: {self.seconds_to_time(self.status.get_deal_uptime())}\nOrder ID: {order['id']}\nExchange: {self.broker.get_exchange_name().capitalize()}\n" self.broker.logger.send_tg_message(message) return 0 except Exception as e: - self.broker.logger.log_this(f"Exception in telegram_bot_sendprofit: {e}",1,self.pair) + self.broker.logger.log_this(f"Exception in telegram_bot_sendprofit: {e}",1,self.config.get_pair()) return 1 @@ -1341,41 +1342,41 @@ class trader: #First let's check if the market exists market = self.broker.fetch_market(f"{self.base}/{new_quote}") if market is None: - self.broker.logger.log_this("Market might not exist",1,self.pair) + self.broker.logger.log_this("Market might not exist",1,self.config.get_pair()) return 1 if "active" in market and not market["active"]: - self.broker.logger.log_this("Market is closed",1,self.pair) + self.broker.logger.log_this("Market is closed",1,self.config.get_pair()) return 1 if self.status.get_take_profit_order() is None: - self.broker.logger.log_this("Take profit order is None",1,self.pair) + self.broker.logger.log_this("Take profit order is None",1,self.config.get_pair()) return 1 if self.status.get_safety_order() is None: - self.broker.logger.log_this("Safety order is None",1,self.pair) + self.broker.logger.log_this("Safety order is None",1,self.config.get_pair()) return 1 #Replace the current take profit order with a new one with new quote currency - self.broker.logger.log_this("Replacing take profit order",2,self.pair) + self.broker.logger.log_this("Replacing take profit order",2,self.config.get_pair()) self.status.set_take_profit_order(self.quote_currency_replace_order(self.status.get_take_profit_order(),new_quote)) if self.status.get_take_profit_order()==self.broker.get_empty_order(): return 1 #Replace the current safety order (if any) with a new one with the new quote currency if self.status.get_safety_order()!=self.broker.get_empty_order(): - self.broker.logger.log_this("Replacing safety order",2,self.pair) + self.broker.logger.log_this("Replacing safety order",2,self.config.get_pair()) self.status.set_safety_order(self.quote_currency_replace_order(self.status.get_safety_order(),new_quote)) if self.status.get_safety_order()==self.broker.get_empty_order(): return 1 #Calls switch_quote_currency_config - self.broker.logger.log_this("Modifying config file",2,self.pair) + self.broker.logger.log_this("Modifying config file",2,self.config.get_pair()) self.quote_currency_switch_configs(new_quote) #Updates status_dict - self.broker.logger.log_this("Updating status file",2,self.pair) + self.broker.logger.log_this("Updating status file",2,self.config.get_pair()) self.update_status(True) #Done - self.broker.logger.log_this("Quote swap successful",2,self.pair) + self.broker.logger.log_this("Quote swap successful",2,self.config.get_pair()) return 0 @@ -1384,8 +1385,8 @@ class trader: Cancels the order and returns the new updated order ''' #Cancels the old order - if self.broker.cancel_order(old_order["id"],self.pair)==1: - self.broker.logger.log_this(f"Can't cancel old order {old_order['id']}",1,self.pair) + if self.broker.cancel_order(old_order["id"],self.config.get_pair())==1: + self.broker.logger.log_this(f"Can't cancel old order {old_order['id']}",1,self.config.get_pair()) return self.broker.get_empty_order() #Sends the new order @@ -1402,7 +1403,7 @@ class trader: if self.broker.rewrite_config_file()==1: #Error writing broker config file, undoing changes - self.broker.logger.log_this("Error writing new broker config file",1,self.pair) + self.broker.logger.log_this("Error writing new broker config file",1,self.config.get_pair()) self.quote_currency_undo_changes(new_quote,self.quote,False) return 1 @@ -1412,7 +1413,6 @@ class trader: self.config.set_pair(f"{self.base}/{self.quote}") self.profit_filename = f"profits/{self.base}{self.quote}.profits" self.log_filename = f"logs/{self.base}{self.quote}.log" - self.pair = self.config.get_pair() #If there is an old_long file, also copy it if self.config.get_is_short() and self.status.get_old_long()!={}: @@ -1420,11 +1420,11 @@ class trader: with open(f"status/{self.base}{self.quote}.oldlong","w") as c: c.write(json.dumps(self.status.get_old_long(), indent=4)) except Exception as e: - self.broker.logger.log_this(f"Exception while writing new old_long file: {e}",1,self.pair) + self.broker.logger.log_this(f"Exception while writing new old_long file: {e}",1,self.config.get_pair()) #Write the new config file if self.config.save_to_file(f"configs/{self.base}{self.quote}.json")==1: - self.broker.logger.log_this(f"Error while writing the new trader config file",1,self.pair) + self.broker.logger.log_this(f"Error while writing the new trader config file",1,self.config.get_pair()) #Undoing changes self.quote_currency_undo_changes(new_quote,old_quote,True) return 1 @@ -1445,11 +1445,10 @@ class trader: self.config.set_pair(f"{self.base}/{self.quote}") self.profit_filename = f"profits/{self.base}{self.quote}.profits" self.log_filename = f"logs/{self.base}{self.quote}.log" - self.pair = self.config.get_pair() #Writing config file if write_broker_file and self.broker.rewrite_config_file()==1: - self.broker.logger.log_this("Error in quote_currency_undo_changed: error writing new broker config file",1,self.pair) + self.broker.logger.log_this("Error in quote_currency_undo_changed: error writing new broker config file",1,self.config.get_pair()) #Done return 0 @@ -1557,7 +1556,7 @@ class trader: print(e) prices = f"{low_boundary_color}{low_boundary}{white}|{price_color}{mid_boundary}{white}|{target_price_color}{high_boundary}{white}|{pct_color}{pct_to_profit_str}%{white}" - line1 = f"{p}{pair_color}{self.pair.center(13)}{white}| {safety_order_string} |{prices}| Uptime: {self.seconds_to_time(self.status.get_deal_uptime())}" + line1 = f"{p}{pair_color}{self.config.get_pair().center(13)}{white}| {safety_order_string} |{prices}| Uptime: {self.seconds_to_time(self.status.get_deal_uptime())}" if self.status.get_is_boosted(): line1 = f"{line1} | BOOSTED" if self.config.get_autoswitch(): @@ -1579,7 +1578,7 @@ class trader: ''' #Load status dict if self.status.load_from_file()==1: - self.broker.logger.log_this(f"Error: Couldn't load status dict. Aborting",1,self.pair) + self.broker.logger.log_this(f"Error: Couldn't load status dict. Aborting",1,self.config.get_pair()) self.quit = True return 1 @@ -1587,18 +1586,18 @@ class trader: self.config.set_no_of_safety_orders(self.status.get_no_of_safety_orders()) #If this is not loaded from status_dict, it will ignore if safety orders were added at runtime #Refresh take profit order - self.status.set_take_profit_order(self.broker.get_order(self.status.get_take_profit_order()["id"],self.pair)) + self.status.set_take_profit_order(self.broker.get_order(self.status.get_take_profit_order()["id"],self.config.get_pair())) if self.status.get_take_profit_order()==self.broker.get_empty_order(): - self.broker.logger.log_this("Couldn't load take profit order (broker returned empty order). Aborting.",1,self.pair) + self.broker.logger.log_this("Couldn't load take profit order (broker returned empty order). Aborting.",1,self.config.get_pair()) self.quit = True return 1 #Refresh safety order - self.status.set_safety_order(self.broker.get_order(self.status.get_safety_order()["id"],self.pair)) + self.status.set_safety_order(self.broker.get_order(self.status.get_safety_order()["id"],self.config.get_pair())) if self.status.get_safety_order()==self.broker.get_empty_order() and self.status.get_so_amount()