2025.08.15

This commit is contained in:
Nicolás Sánchez 2025-08-15 23:36:22 -03:00
parent e11be69f00
commit 30d8e84833
5 changed files with 135 additions and 95 deletions

View File

@ -1,3 +1,7 @@
2025.08.15:
. "deal order history" is now disabled by default.
. CPU optimizations in status string generation.
2025.08.14: 2025.08.14:
. Refactored gib_so_size. . Refactored gib_so_size.
. Refactored seconds_to_time. . Refactored seconds_to_time.

View File

@ -23,7 +23,8 @@ class Broker:
self.retries = self.broker_config["retries"] if "retries" in self.broker_config else 5 self.retries = self.broker_config["retries"] if "retries" in self.broker_config else 5
self.slippage_default_threshold = self.broker_config["slippage_default_threshold"] if "slippage_default_threshold" in self.broker_config else .03 self.slippage_default_threshold = self.broker_config["slippage_default_threshold"] if "slippage_default_threshold" in self.broker_config else .03
self.logger = Logger(self.broker_config) self.logger = Logger(self.broker_config)
self.write_order_history = True #This should be a toggle in config_file self.follow_order_history = False #This should be a toggle in config_file
self.write_order_history = False #This should be a toggle in config_file
#Initialize database #Initialize database
self.profits_database_filename = "profits/profits_database.db" self.profits_database_filename = "profits/profits_database.db"
@ -198,6 +199,9 @@ class Broker:
def get_write_order_history(self): def get_write_order_history(self):
return self.write_order_history return self.write_order_history
def get_follow_order_history(self):
return self.follow_order_history
def get_cooldown_multiplier(self): def get_cooldown_multiplier(self):
return self.cooldown_multiplier return self.cooldown_multiplier

10
main.py
View File

@ -16,7 +16,7 @@ import exchange_wrapper
import trader import trader
version = "2025.08.14" version = "2025.08.15"
''' '''
Color definitions. If you want to change them, check the reference at https://en.wikipedia.org/wiki/ANSI_escape_code#Colors Color definitions. If you want to change them, check the reference at https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
@ -345,7 +345,9 @@ def main_loop():
screen_buffer.append(str(instance)) screen_buffer.append(str(instance))
#Updates some global status variables prior to deletion of those #Updates some global status variables prior to deletion of those
global_status["online_workers"] = online_pairs.copy() #global_status["online_workers"] = online_pairs.copy()
if len(running_traders)!=len(global_status["online_workers"]):
global_status["online_workers"] = [instance.config.get_pair() for instance in running_traders]
#Check for paused pairs #Check for paused pairs
global_status["paused_traders"] = [instance.config.get_pair() for instance in running_traders if instance.pause] global_status["paused_traders"] = [instance.config.get_pair() for instance in running_traders if instance.pause]
@ -2413,9 +2415,9 @@ if __name__=="__main__":
import_mode = True import_mode = True
if "--first_start" in argv: if "--first_start" in argv:
import_mode = False import_mode = False
print(time.strftime("[%Y/%m/%d %H:%M:%S] | Initializing in FIRST START MODE, press enter to start...")) print(time.strftime("[%Y/%m/%d %H:%M:%S] | Initializing in FIRST START MODE, press <Enter> to start..."))
else: else:
print(time.strftime("[%Y/%m/%d %H:%M:%S] | Initializing in IMPORT MODE, press enter to start...")) print(time.strftime("[%Y/%m/%d %H:%M:%S] | Initializing in IMPORT MODE, press <Enter> to start..."))
input() input()
#Load exchange config #Load exchange config

View File

@ -389,7 +389,8 @@ class StatusHandler:
def update_deal_order_history(self, new_deal: dict): def update_deal_order_history(self, new_deal: dict):
# if not isinstance(new_deal, dict): # if not isinstance(new_deal, dict):
# self.broker.logger.log_this(f"value provided is not a dict",1,self.get_pair()) # self.broker.logger.log_this(f"value provided is not a dict",1,self.get_pair())
self.status_dictionary["deal_order_history"].append(self.strip_order(new_deal)) if not self.broker.get_follow_order_history():
self.status_dictionary["deal_order_history"].append(self.strip_order(new_deal))
return 0 return 0
def strip_order(self, order): def strip_order(self, order):

203
trader.py
View File

@ -30,6 +30,12 @@ class trader:
self.status.set_start_time(int(time.time())) self.status.set_start_time(int(time.time()))
self.last_time_seen = time.time() self.last_time_seen = time.time()
#Status string caches
self.status_string_cache = ""
self.low_price_cache = None
self.mid_price_cache = None
self.high_price_cache = None
if self.config.get_is_short(): if self.config.get_is_short():
#Check if there is an old_long file. If so, load it. #Check if there is an old_long file. If so, load it.
try: try:
@ -71,6 +77,22 @@ class trader:
return self.status.get_status_string() return self.status.get_status_string()
def get_color(self, color):
'''
Returns white if color does not exist
'''
colors = {"yellow": "\033[0;33;40m",
"green": "\033[0;32;40m",
"red": "\033[0;31;40m",
"blue": "\033[0;34;40m",
"cyan": "\033[0;36;40m",
"bright_white": "\033[0;97;40m",
"bright_green": "\033[0;92;40m",
"white": "\033[0;37;40m"}
return colors[color] if color in colors else "\033[0;37;40m"
def get_status_dict(self): def get_status_dict(self):
return self.status.get_status() return self.status.get_status()
@ -1429,14 +1451,11 @@ class trader:
''' '''
Returns the status string properly formatted for screen output Returns the status string properly formatted for screen output
''' '''
yellow = "\033[0;33;40m"
green = "\033[0;32;40m" decimals = 11
red = "\033[0;31;40m" low_percentage = 1
blue = "\033[0;34;40m" mid_percentage = 10
cyan = "\033[0;36;40m" high_percentage = 20
bright_white = "\033[0;97;40m"
bright_green = "\033[0;92;40m"
white = "\033[0;37;40m"
def draw_line(price,min_value,max_value,break_even): def draw_line(price,min_value,max_value,break_even):
''' '''
@ -1452,98 +1471,108 @@ class trader:
self.broker.logger.log_this(f"{e}") self.broker.logger.log_this(f"{e}")
value = 1 value = 1
if min_value<max_value: if min_value<max_value:
color = green if price>=break_even else red color = self.get_color("green") if price>=break_even else self.get_color("red")
else: else:
color = red if price>=break_even else green color = self.get_color("red") if price>=break_even else self.get_color("green")
return f"{color}{'='*value}{white}{'='*max(0,(80-value))}"[:100] return f"{color}{'='*value}{self.get_color('white')}{'='*max(0,(80-value))}"[:100]
decimals = 11
low_percentage = 1
mid_percentage = 10
high_percentage = 20
safety_order_string = f"{self.status.get_so_amount()-1}/{self.config.get_no_of_safety_orders()}".rjust(5)
low_price = self.status.get_next_so_price() if self.status.get_next_so_price() is not None else 0 low_price = self.status.get_next_so_price() if self.status.get_next_so_price() is not None else 0
mid_price = self.status.get_price() if self.status.get_price() is not None else 0 mid_price = self.status.get_price() if self.status.get_price() is not None else 0
high_price = self.status.get_take_profit_price() if self.status.get_take_profit_price() is not None else 0 high_price = self.status.get_take_profit_price() if self.status.get_take_profit_price() is not None else 0
low_boundary = '{:.20f}'.format(low_price)[:decimals].center(decimals) if low_price==self.low_price_cache and mid_price==self.mid_price_cache and high_price==self.high_price_cache:
mid_boundary = '{:.20f}'.format(mid_price)[:decimals].center(decimals) #status_string = self.status_string_cache
high_boundary = '{:.20f}'.format(high_price)[:decimals].center(decimals) #Edit uptime
position = self.status_string_cache.find("Uptime")
new_uptime = self.seconds_to_time(self.status.get_deal_uptime())
status_string = self.status_string_cache[:position+8] + new_uptime + self.status_string_cache[position+8+len(new_uptime):]
else:
#Update caches
self.low_price_cache = low_price
self.mid_price_cache = mid_price
self.high_price_cache = high_price
percentage_to_profit = 100 #Formatting
pct_to_profit_str = "XX.XX" low_boundary = '{:.20f}'.format(low_price)[:decimals].center(decimals)
if mid_price!=0: mid_boundary = '{:.20f}'.format(mid_price)[:decimals].center(decimals)
diff = abs(high_price-mid_price) high_boundary = '{:.20f}'.format(high_price)[:decimals].center(decimals)
percentage_to_profit = diff/mid_price*100
#Formatting (on-screen percentage not longer than 4 digits) percentage_to_profit = 100
pct_to_profit_str = "{:.2f}".format(percentage_to_profit) pct_to_profit_str = "XX.XX"
if len(pct_to_profit_str)==4: if mid_price!=0:
pct_to_profit_str = f" {pct_to_profit_str}" diff = abs(high_price-mid_price)
elif len(pct_to_profit_str)==6: percentage_to_profit = diff/mid_price*100
pct_to_profit_str = pct_to_profit_str[:5]
line3 = "" #Formatting (on-screen percentage not longer than 4 digits)
if self.status.get_base_bought()!=0: pct_to_profit_str = "{:.2f}".format(percentage_to_profit)
line3 = draw_line(mid_price,low_price,high_price,self.status.get_quote_spent()/self.status.get_base_bought()) if len(pct_to_profit_str)==4:
p = "*PAUSED*" if self.pause==True else "" pct_to_profit_str = f" {pct_to_profit_str}"
low_boundary_color = red elif len(pct_to_profit_str)==6:
price_color = white pct_to_profit_str = pct_to_profit_str[:5]
target_price_color = green
pair_color = cyan
if self.config.get_is_short():
price_color = white
pair_color = yellow
if self.status.get_old_long()!={}:
if mid_price>self.status.get_old_long()["tp_price"]:
price_color = bright_green
if high_price>self.status.get_old_long()["tp_price"]:
target_price_color = bright_green
#Set percentage's color line3 = ""
pct_color = white if self.status.get_base_bought()!=0:
if percentage_to_profit<low_percentage: line3 = draw_line(mid_price,low_price,high_price,self.status.get_quote_spent()/self.status.get_base_bought())
pct_color = green p = "*PAUSED*" if self.pause==True else ""
if percentage_to_profit>mid_percentage: low_boundary_color = self.get_color("red")
pct_color = yellow price_color = self.get_color("white")
if percentage_to_profit>high_percentage: target_price_color = self.get_color("green")
pct_color = red pair_color = self.get_color("cyan")
if self.config.get_is_short():
price_color = self.get_color("white")
pair_color = self.get_color("yellow")
if self.status.get_old_long()!={}:
if mid_price>self.status.get_old_long()["tp_price"]:
price_color = self.get_color("bright_green")
if high_price>self.status.get_old_long()["tp_price"]:
target_price_color = self.get_color("bright_green")
multiplier = 0 #Set percentage's color
if self.config.get_is_short() and self.status.get_old_long()!={}: pct_color = self.get_color("white")
try: if percentage_to_profit<low_percentage:
#Logic to display switch price pct_color = self.get_color("green")
old_target = self.status.get_old_long()["tp_price"]*self.status.get_old_long()["tp_amount"] if percentage_to_profit>mid_percentage:
base_left = self.status.get_old_long()["tp_amount"]-self.status.get_base_bought() pct_color = self.get_color("yellow")
minimum_switch_price = (old_target - self.status.get_quote_spent())/base_left if percentage_to_profit>high_percentage:
if old_target-self.status.get_quote_spent()>0 and base_left>0 and minimum_switch_price<low_price: pct_color = self.get_color("red")
low_boundary_color = bright_green
low_boundary = '{:.20f}'.format(minimum_switch_price)[:decimals].center(decimals)
if mid_price!=0:
multiplier = int(self.status.get_old_long()["tp_price"]/self.status.get_price())
except Exception as e:
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}" multiplier = 0
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.config.get_is_short() and self.status.get_old_long()!={}:
if self.status.get_is_boosted(): try:
line1 = f"{line1} | BOOSTED" #Logic to display switch price
if self.config.get_autoswitch(): old_target = self.status.get_old_long()["tp_price"]*self.status.get_old_long()["tp_amount"]
auto_color = white base_left = self.status.get_old_long()["tp_amount"]-self.status.get_base_bought()
if self.config.get_liquidate_after_switch(): minimum_switch_price = (old_target - self.status.get_quote_spent())/base_left
auto_color = red if old_target-self.status.get_quote_spent()>0 and base_left>0 and minimum_switch_price<low_price:
line1 = f"{line1} | {auto_color}AUTO{white}" low_boundary_color = self.get_color("bright_green")
if multiplier>1: low_boundary = '{:.20f}'.format(minimum_switch_price)[:decimals].center(decimals)
#Only displays the multiplier if autoswitch is enabled. if mid_price!=0:
line1 = f"{line1}{auto_color}x{multiplier}{white}" multiplier = int(self.status.get_old_long()["tp_price"]/self.status.get_price())
if self.config.get_programmed_stop() and time.time()<=self.config.get_programmed_stop_time(): except Exception as e:
line1 = f"{line1} | PROGRAMMED LAST DEAL" print(e)
if self.status.get_stop_when_profit():
line1 = f"{line1} | LAST DEAL"
return f"{white}{line1}\n{line3}{white}" safety_order_string = f"{self.status.get_so_amount()-1}/{self.config.get_no_of_safety_orders()}".rjust(5)
prices = f"{low_boundary_color}{low_boundary}{self.get_color('white')}|{price_color}{mid_boundary}{self.get_color('white')}|{target_price_color}{high_boundary}{self.get_color('white')}|{pct_color}{pct_to_profit_str}%{self.get_color('white')}"
line1 = f"{p}{pair_color}{self.config.get_pair().center(13)}{self.get_color('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():
auto_color = self.get_color("white")
if self.config.get_liquidate_after_switch():
auto_color = self.get_color("red")
line1 = f"{line1} | {auto_color}AUTO{self.get_color('white')}"
if multiplier>1:
#Only displays the multiplier if autoswitch is enabled.
line1 = f"{line1}{auto_color}x{multiplier}{self.get_color('white')}"
if self.config.get_programmed_stop() and time.time()<=self.config.get_programmed_stop_time():
line1 = f"{line1} | PROGRAMMED LAST DEAL"
if self.status.get_stop_when_profit():
line1 = f"{line1} | LAST DEAL"
status_string = f"{self.get_color('white')}{line1}\n{line3}{self.get_color('white')}"
self.status_string_cache = status_string
return status_string
def load_imported_trader(self, forced_tp_order_id = None, forced_safety_order_id = None) -> int: def load_imported_trader(self, forced_tp_order_id = None, forced_safety_order_id = None) -> int: