2025.09.18

This commit is contained in:
Nicolás Sánchez 2025-09-19 10:29:32 -03:00
parent 0d753aa3cd
commit 733f6efbff
4 changed files with 45 additions and 53 deletions

View File

@ -1,3 +1,8 @@
2025.09.18:
. do_cleanup now uses get_min_quote_size.
. Added an extra price check to switch_to_long.
. Removed old check_old_long_price method.
2025.09.14:
. Refactored full order list fetching.
. Minor refactor of restart_pair_no_json.

View File

@ -458,7 +458,7 @@ class Broker:
try:
return orderbook["bids"][0][0]
except Exception as e:
self.logger.log_this(f"Exception getting top mid price: {e}",1,symbol)
self.logger.log_this(f"Exception getting top bid price: {e}",1,symbol)
return self.get_ticker_price(symbol)
@ -537,7 +537,7 @@ class Broker:
pairs = []
try:
if self.get_exchange_name() in ["binance","kucoin"]:
if "unified_order_query" in self.broker_config and self.broker_config["unified_order_query"] is True:
if self.broker_config.get("unified_order_query"):
return self.exchange.fetch_open_orders()
result = []
for pair in pairs:
@ -642,7 +642,7 @@ class Broker:
'''
try:
if "unified_order_query" in self.broker_config and self.broker_config["unified_order_query"] is True:
if self.broker_config.get("unified_order_query"):
return self.exchange.fetch_closed_orders()
result = []
for pair in pairs:

View File

@ -18,7 +18,7 @@ import exchange_wrapper
import trader
version = "2025.09.14"
version = "2025.09.18"
'''
Color definitions. If you want to change them, check the reference at https://en.wikipedia.org/wiki/ANSI_escape_code#Colors

View File

@ -11,14 +11,16 @@ class trader:
self.pause = True
self.quit = False
self.restart = False
self.warnings = {
"short_price_exceeds_old_long": False,
"speol_notified": False
}
self.trader_restart_errors = {1: "start_trader returned error #1. Trader will be restarted",
2: "start_trader returned error #2: Initial order never got filled. Trader will be restarted",
3: "start_trader returned error #3: Slippage threshold exceeded. Trader will be restarted"}
#Status string caches
self.low_price_cache = None
self.mid_price_cache = None
self.high_price_cache = None
self.concurrent_so_amount_cache = None
self.broker = broker
self.config = ConfigHandler(pair,broker)
base_quote = self.config.get_pair()
@ -29,12 +31,6 @@ class trader:
self.market_reload_period = 86400 #Market reload period in seconds
self.status.set_start_time(int(time.time()))
self.last_time_seen = time.time()
#Status string caches
self.low_price_cache = None
self.mid_price_cache = None
self.high_price_cache = None
self.concurrent_so_amount_cache = None
if self.config.get_is_short():
#Check if there is an old_long file. If so, load it.
@ -442,7 +438,7 @@ class trader:
return 1
balance_to_clean /= 2 #Maybe it's a good idea, sort of DCAing the dust.
if balance_to_clean >= self.broker.get_min_base_size(self.status.get_pair()):
if balance_to_clean*self.status.get_start_price()>self.broker.get_min_quote_size(self.status.get_pair()):
self.broker.logger.log_this(f"Balance to clean: {balance_to_clean} {self.base}",2,self.status.get_pair())
self.broker.logger.log_this("Sending cleanup order...",2,self.status.get_pair())
cleanup_order = self.broker.new_limit_order(self.status.get_pair(),balance_to_clean,"sell",self.status.get_take_profit_price(),no_retries=True)
@ -585,7 +581,7 @@ class trader:
return 0
def switch_to_long(self, ignore_old_long: bool = False, already_received_quote: float = 0) -> int:
def switch_to_long(self, ignore_old_long: bool = False, already_received_quote: float = 0, double_check_price: bool = True) -> int:
'''
Takes a short trader and changes the mode to long.
Only does it if the current trader was previously a long one.
@ -595,7 +591,14 @@ class trader:
self.broker.logger.log_this("Trader already in long mode, nothing to do",1,self.status.get_pair())
return 1
self.broker.logger.log_this("Attempting to switch to long trader",0,self.status.get_pair())
if double_check_price:
#Waits a moment to see if the price has moved too much
time.sleep(self.broker.get_wait_time()*4)
if not self.check_old_long(True):
self.broker.logger.log_this("False positive. Nothing to do.",1,self.status.get_pair())
return 2
#Check old_long data
if not ignore_old_long and self.status.get_old_long()=={}:
self.broker.logger.log_this("Can't find old long info on status_dict, searching for oldlong file",1,self.status.get_pair())
@ -1018,28 +1021,6 @@ class trader:
#Done
return 0
def check_old_long_price(self) -> int:
'''
Checks if short price exceeds old long price. If so, send a Telegram message
'''
price_exceeds = False
if self.status.get_old_long()!={}:
price_exceeds = self.status.get_price()>float(self.status.get_old_long()["tp_price"])
if price_exceeds:
self.warnings["short_price_exceeds_old_long"] = True
else:
self.warnings["short_price_exceeds_old_long"] = False
self.warnings["speol_notified"] = False
if not self.warnings["speol_notified"] and price_exceeds:
#Only notify one time AND if autoswitch is off
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.status.get_pair())
return 0
def check_orderbook_depth(self, threshold: float, order_size: float, old_price: float = 0, size_in_quote = True) -> bool:
'''
@ -1084,6 +1065,21 @@ class trader:
return False
def check_old_long(self, fetch_price=False):
'''
Check if it is profitable to switch to back to long.
Returns True if it is profitable, False otherwise.
If selling the base currency left at the current market price plus the quote already received turns out to be more than the old long deal target,
it means that we already are in profit territory, switch back to long.
A more conservative approach would be old_target = self.status.get_old_long()["quote_spent"], just breaking even.
'''
price = self.status.get_price() if not fetch_price else self.broker.get_top_bid_price(self.status.get_pair())
old_target = self.status.get_old_long()["tp_price"]*self.status.get_old_long()["tp_amount"]
base_left = self.status.get_old_long()["tp_amount"]-self.status.get_base_bought()
return (base_left*price)+self.status.get_quote_spent()>=old_target
def check_status(self,open_orders: list) -> int: #Should I change the order? Check the SO first?
'''
Main routine. It checks for closed orders and proceeds accordingly.
@ -1094,25 +1090,16 @@ class trader:
self.update_status(False)
return 0
#Check if short price exceeds old long price. If so, send a Telegram message
if self.config.get_is_short() and self.status.get_old_long()!={} and self.config.get_check_old_long_price():
self.check_old_long_price()
self.status.set_pause_reason("check for autoswitch")
#If it's a short trader that used to be long AND autoswitch is enabled
if self.config.get_is_short() and self.config.get_autoswitch() and self.status.get_old_long()!={}:
#If selling the base currency left at the current market price plus the quote already received turns out to be more than the old long deal target,
# it means that we already are in profit territory, switch back to long.
#A more conservative approach would be old_target = self.status.get_old_long()["quote_spent"], just breaking even.
old_target = self.status.get_old_long()["tp_price"]*self.status.get_old_long()["tp_amount"]
base_left = self.status.get_old_long()["tp_amount"]-self.status.get_base_bought()
if (base_left*self.status.get_price())+self.status.get_quote_spent()>=old_target:
if self.check_old_long():
#Sell all base (market), report the profits and restart the trader
self.status.set_pause_reason("automatic_switch")
self.switch_to_long(already_received_quote=self.status.get_quote_spent())
if not self.config.get_liquidate_after_switch():
self.restart = True
return 1
if self.switch_to_long(already_received_quote=self.status.get_quote_spent())!=2:
if not self.config.get_liquidate_after_switch():
self.restart = True
return 1
#Check for autoswitch (long->short)
if not self.config.get_is_short() and self.status.get_so_amount()==self.status.get_no_of_safety_orders() and self.config.get_autoswitch():
self.switch_to_short()