2025.10.03

This commit is contained in:
Nicolás Sánchez 2025-10-03 15:44:59 -03:00
parent c42a505e49
commit 2823dff56a
5 changed files with 76 additions and 19 deletions

View File

@ -1,3 +1,7 @@
2025.10.03:
. New broker config option: log_orders. If set to True, the orders will be logged in orders.log under logs directory.
. New API endpoint: /toggle_log_orders.
2025.10.01: 2025.10.01:
. Fixed base fees not being taken into account. . Fixed base fees not being taken into account.

View File

@ -26,6 +26,7 @@ class Broker:
self.follow_order_history = self.broker_config.get("follow_order_history",False) self.follow_order_history = self.broker_config.get("follow_order_history",False)
self.write_order_history = self.broker_config.get("write_order_history", False) self.write_order_history = self.broker_config.get("write_order_history", False)
self.logger = Logger(self.broker_config) self.logger = Logger(self.broker_config)
self.log_orders = self.broker_config.get("log_orders",False)
#Initialize database #Initialize database
self.profits_database_filename = "profits/profits_database.db" self.profits_database_filename = "profits/profits_database.db"
@ -81,6 +82,16 @@ class Broker:
def get_deals_cache(self): def get_deals_cache(self):
return self.deals_list return self.deals_list
def get_log_orders(self):
return self.log_orders
def set_log_orders(self,log_orders:bool):
self.log_orders = log_orders
return 0
def get_symbol(self,pair): def get_symbol(self,pair):
if "/" in pair: if "/" in pair:
return pair return pair
@ -652,7 +663,7 @@ class Broker:
return amount return amount
def new_simulated_market_order(self,symbol,size,side,amount_in_base=False,no_retries=False): def new_simulated_market_order(self,symbol,size,side,amount_in_base=False,no_retries=False,log=""):
''' '''
TODO: Emulating Market Orders With Limit Orders TODO: Emulating Market Orders With Limit Orders
@ -682,7 +693,7 @@ class Broker:
while retries>0: while retries>0:
try: try:
if self.get_exchange_name()=="gateio" and side=="buy" and not amount_in_base: if self.get_exchange_name()=="gateio" and side=="buy" and not amount_in_base:
new_order = self.exchange.create_market_buy_order_with_cost(symbol, size) new_order = self.exchange.create_market_buy_order_with_cost(symbol, size)
else: else:
order_book = self.get_order_book(symbol) order_book = self.get_order_book(symbol)
if order_book=={}: if order_book=={}:
@ -696,6 +707,8 @@ class Broker:
price = self.find_minimum_viable_price(order_book,base_amount,side) price = self.find_minimum_viable_price(order_book,base_amount,side)
#Maybe check for slippage here instead of within the trader itself? idk #Maybe check for slippage here instead of within the trader itself? idk
new_order = self.exchange.create_order(symbol,"limit",side,base_amount,price) new_order = self.exchange.create_order(symbol,"limit",side,base_amount,price)
if self.log_orders:
self.logger.log_order(f"New simulated market order: Symbol: {symbol} - Side: {side} - Size: {size} - Price: {price} - ID: {new_order['id']} - Origin: {log}")
time.sleep(self.wait_time) time.sleep(self.wait_time)
return self.get_order(new_order["id"],symbol) return self.get_order(new_order["id"],symbol)
except Exception as e: except Exception as e:
@ -742,7 +755,7 @@ class Broker:
return None return None
def new_market_order(self,symbol,size,side,amount_in_base=False,no_retries=False): #It should send a new market order to the exchange def new_market_order(self,symbol,size,side,amount_in_base=False,no_retries=False, log=""): #It should send a new market order to the exchange
''' '''
Sends a new market order to the exchange. Sends a new market order to the exchange.
@ -767,6 +780,8 @@ class Broker:
amount = self.amount_to_precision(symbol,size) #Market sell orders are always nominated in base currency amount = self.amount_to_precision(symbol,size) #Market sell orders are always nominated in base currency
order_to_send = self.exchange.create_order(symbol,"market",side,amount) order_to_send = self.exchange.create_order(symbol,"market",side,amount)
if self.log_orders:
self.logger.log_order(f"New market order: Symbol: {symbol} - Side: {side} - Size: {size} - ID: {order_to_send['id']} - Origin: {log}")
time.sleep(self.wait_time) time.sleep(self.wait_time)
return self.get_order(order_to_send["id"],symbol) return self.get_order(order_to_send["id"],symbol)
@ -853,7 +868,7 @@ class Broker:
# return returned_orders # return returned_orders
def new_limit_order(self,symbol,size,side,price,no_retries=False): def new_limit_order(self,symbol,size,side,price,no_retries=False,log=""):
''' '''
Sends a new limit order. Sends a new limit order.
@ -869,6 +884,8 @@ class Broker:
try: try:
order_to_send = self.exchange.create_order(symbol,"limit",side,self.amount_to_precision(symbol,size),price) order_to_send = self.exchange.create_order(symbol,"limit",side,self.amount_to_precision(symbol,size),price)
time.sleep(self.wait_time) time.sleep(self.wait_time)
if self.log_orders:
self.logger.log_order(f"New limit order: Symbol: {symbol} - Side: {side} - Size: {size} - Price: {price} - ID: {order_to_send['id']} - Notes: {log}")
return self.get_order(order_to_send["id"],symbol) return self.get_order(order_to_send["id"],symbol)
except Exception as e: except Exception as e:
self.logger.log_this(f"Exception in new_limit_order - Side: {side} - Size: {size} - {self.amount_to_precision(symbol,size)} - Exception: {e}",1,symbol) self.logger.log_this(f"Exception in new_limit_order - Side: {side} - Size: {size} - {self.amount_to_precision(symbol,size)} - Exception: {e}",1,symbol)
@ -1084,6 +1101,9 @@ class Logger:
self.log_this(f"Error in send_tg_message: {e}",1) self.log_this(f"Error in send_tg_message: {e}",1)
return 1 return 1
def log_order(self,message):
with open(f"logs/orders.log","a") as log_file:
log_file.write(time.strftime(f"[%Y/%m/%d %H:%M:%S] | {message}\n"))
def log_this(self,message,level=2,pair=None): def log_this(self,message,level=2,pair=None):
''' '''
@ -1105,8 +1125,6 @@ class Logger:
#Write to log file #Write to log file
with open(f"logs/{self.exchange_name}.log","a") as log_file: with open(f"logs/{self.exchange_name}.log","a") as log_file:
log_file.write(text+"\n") log_file.write(text+"\n")
log_file.close()
#Append to log list #Append to log list
self.log_list.append(text) self.log_list.append(text)
except Exception as e: except Exception as e:

30
main.py
View File

@ -18,7 +18,7 @@ import exchange_wrapper
import trader import trader
version = "2025.10.01" version = "2025.10.03"
''' '''
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
@ -1238,6 +1238,20 @@ def switch_quote_currency():
return jsonify({'Error': 'Halp'}) return jsonify({'Error': 'Halp'})
@base_api.route("/toggle_log_orders", methods=['POST'])
def toggle_log_orders():
'''
POST request
Parameters:
None
'''
if not "X-API-KEY" in request.headers or not request.headers.get("X-API-KEY") in valid_keys:
return jsonify({'Error': 'API key invalid'}), 401
return unwrapped_toggle_log_orders()
@base_api.route("/toggle_restart", methods=['POST']) @base_api.route("/toggle_restart", methods=['POST'])
def toggle_restart(): def toggle_restart():
''' '''
@ -2360,6 +2374,20 @@ def unwrapped_toggle_restart():
return jsonify({"Success": "attempt_to_restart disabled"}) return jsonify({"Success": "attempt_to_restart disabled"})
def unwrapped_toggle_log_orders():
'''
Toggles on or off the logging of orders.
Returns:
jsonify: A jsonified dictionary detailing the outcome of the operation.
'''
broker.set_log_orders(not broker.get_log_orders())
if broker.get_log_orders():
return jsonify({"Success": "log_orders enabled"})
return jsonify({"Success": "log_orders disabled"})
def unwrapped_toggle_telegram(): def unwrapped_toggle_telegram():
''' '''
Switches on or off the Telegram notifications Switches on or off the Telegram notifications

View File

@ -155,7 +155,7 @@ class trader:
if self.status.get_old_long()["tp_amount"]-free_base>min_base_size: if self.status.get_old_long()["tp_amount"]-free_base>min_base_size:
amount_to_buy = self.broker.amount_to_precision(self.status.get_pair(),self.status.get_old_long()["tp_amount"]-free_base) amount_to_buy = self.broker.amount_to_precision(self.status.get_pair(),self.status.get_old_long()["tp_amount"]-free_base)
self.broker.logger.log_this(f"Buying missing {amount_to_buy} {self.base}",1,self.status.get_pair()) self.broker.logger.log_this(f"Buying missing {amount_to_buy} {self.base}",1,self.status.get_pair())
self.broker.new_market_order(self.status.get_pair(),amount_to_buy,"buy",amount_in_base=True) self.broker.new_market_order(self.status.get_pair(),amount_to_buy,"buy",amount_in_base=True,log="start_trader-missing_base")
time.sleep(self.broker.get_wait_time()*2) time.sleep(self.broker.get_wait_time()*2)
#Re-querying for the amount of base currency on the exchange #Re-querying for the amount of base currency on the exchange
free_base = self.fetch_free_base() free_base = self.fetch_free_base()
@ -211,7 +211,7 @@ class trader:
self.status.set_pause_reason("start_trader - sending first order") self.status.set_pause_reason("start_trader - sending first order")
self.broker.logger.log_this("Sending first order...",2,self.status.get_pair()) self.broker.logger.log_this("Sending first order...",2,self.status.get_pair())
action = "sell" if self.config.get_is_short() else "buy" action = "sell" if self.config.get_is_short() else "buy"
first_order = self.broker.new_market_order(self.status.get_pair(),self.status.get_order_size(),action) first_order = self.broker.new_market_order(self.status.get_pair(),self.status.get_order_size(),action,log="start_trader")
#self.broker.logger.log_this(f"First order id: {first_order}",1,self.status.get_pair()) #self.broker.logger.log_this(f"First order id: {first_order}",1,self.status.get_pair())
if first_order in [None,self.broker.get_empty_order()]: if first_order in [None,self.broker.get_empty_order()]:
self.broker.logger.log_this(f"Error sending the first order. Market order returned {first_order}",1,self.status.get_pair()) self.broker.logger.log_this(f"Error sending the first order. Market order returned {first_order}",1,self.status.get_pair())
@ -456,7 +456,7 @@ class trader:
if (balance_in_account-min_size)*self.status.get_start_price()>self.broker.get_min_quote_size(self.status.get_pair()): if (balance_in_account-min_size)*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_in_account-min_size} {self.base}",2,self.status.get_pair()) self.broker.logger.log_this(f"Balance to clean: {balance_in_account-min_size} {self.base}",2,self.status.get_pair())
self.broker.logger.log_this("Sending cleanup order...",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_in_account-min_size,"sell",self.status.get_take_profit_price(),no_retries=True) cleanup_order = self.broker.new_limit_order(self.status.get_pair(),balance_in_account-min_size,"sell",self.status.get_take_profit_price(),no_retries=True,log="cleanup")
if cleanup_order is None: if cleanup_order is None:
self.broker.logger.log_this("Problems with the cleanup order, new_limit_order returned None",1,self.status.get_pair()) self.broker.logger.log_this("Problems with the cleanup order, new_limit_order returned None",1,self.status.get_pair())
return 1 return 1
@ -683,7 +683,7 @@ class trader:
self.broker.logger.log_this("Can't fetch free base",1,self.status.get_pair()) self.broker.logger.log_this("Can't fetch free base",1,self.status.get_pair())
return 1 return 1
#send market order selling the total amount of base in the last take profit short order #send market order selling the total amount of base in the last take profit short order
order = self.broker.new_market_order(self.status.get_pair(),free_base,"sell") order = self.broker.new_market_order(self.status.get_pair(),free_base,"sell",log="liquidate_base")
time.sleep(self.broker.get_wait_time()*2) time.sleep(self.broker.get_wait_time()*2)
tries = self.broker.get_retries() tries = self.broker.get_retries()
while True: while True:
@ -723,7 +723,7 @@ class trader:
#Send the market order #Send the market order
amount = self.status.get_take_profit_order()["amount"] amount = self.status.get_take_profit_order()["amount"]
market_order = self.broker.new_market_order(self.status.get_pair(),amount,"sell",amount_in_base=True) market_order = self.broker.new_market_order(self.status.get_pair(),amount,"sell",amount_in_base=True,log="force_close")
time.sleep(self.broker.get_wait_time()*2) time.sleep(self.broker.get_wait_time()*2)
#Wait for it to be filled #Wait for it to be filled
@ -794,7 +794,7 @@ class trader:
if partial_filled_amount!=0 and len(partial_filled_price)>0 and partial_filled_amount>self.broker.get_min_base_size(self.status.get_pair()): if partial_filled_amount!=0 and len(partial_filled_price)>0 and partial_filled_amount>self.broker.get_min_base_size(self.status.get_pair()):
#send a market order and sum the profits and wait for it to be filled #send a market order and sum the profits and wait for it to be filled
self.broker.logger.log_this("Sending partial fill sell order...",1,self.status.get_pair()) self.broker.logger.log_this("Sending partial fill sell order...",1,self.status.get_pair())
market_order = self.broker.new_market_order(self.status.get_pair(),partial_filled_amount,"sell",amount_in_base=True) market_order = self.broker.new_market_order(self.status.get_pair(),partial_filled_amount,"sell",amount_in_base=True,log="take_profit_routine-partial_fill")
time.sleep(self.broker.get_wait_time()*2) time.sleep(self.broker.get_wait_time()*2)
tries = self.broker.get_retries() tries = self.broker.get_retries()
while True: while True:
@ -925,9 +925,9 @@ class trader:
self.broker.logger.log_this(f"Sending a new safety order ({i+1}/{orders_to_place})",2,self.status.get_pair()) self.broker.logger.log_this(f"Sending a new safety order ({i+1}/{orders_to_place})",2,self.status.get_pair())
so_size = self.gib_so_size(self.status.get_order_size(),self.status.get_so_amount()+1,self.config.get_safety_order_scale()) so_size = self.gib_so_size(self.status.get_order_size(),self.status.get_so_amount()+1,self.config.get_safety_order_scale())
if self.config.get_is_short(): if self.config.get_is_short():
new_order = self.broker.new_limit_order(self.status.get_pair(),so_size,"sell",self.status.get_safety_price_table()[self.status.get_so_amount()+1]) new_order = self.broker.new_limit_order(self.status.get_pair(),so_size,"sell",self.status.get_safety_price_table()[self.status.get_so_amount()+1], log="send_new_safety_order_batch")
else: else:
new_order = self.broker.new_limit_order(self.status.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]) new_order = self.broker.new_limit_order(self.status.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],log="send_new_safety_order_batch")
if new_order==1: if new_order==1:
self.broker.logger.log_this("Not enough balance to send a new safety order",1,self.status.get_pair()) self.broker.logger.log_this("Not enough balance to send a new safety order",1,self.status.get_pair())
@ -1348,10 +1348,10 @@ class trader:
return 1 return 1
if self.config.get_is_short(): 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_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.status.get_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.status.get_pair(),self.status.get_base_bought(),"buy",self.status.get_take_profit_price(),log="new_tp_order"))
else: 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_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.status.get_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.status.get_pair(),self.status.get_base_bought(),"sell",self.status.get_take_profit_price(),log="new_tp_order"))
if self.status.get_take_profit_order()==1: #This means that there was a miscalculation of base currency amount if self.status.get_take_profit_order()==1: #This means that there was a miscalculation of base currency amount
if self.config.get_is_short(): #If in short mode, we don't recalculate anything. if self.config.get_is_short(): #If in short mode, we don't recalculate anything.
return 1 return 1
@ -1515,7 +1515,7 @@ class trader:
return self.broker.get_empty_order() return self.broker.get_empty_order()
#Sends the new order #Sends the new order
return self.broker.new_limit_order(f"{self.base}/{new_quote}",old_order["amount"],old_order["side"],old_order["price"]) return self.broker.new_limit_order(f"{self.base}/{new_quote}",old_order["amount"],old_order["side"],old_order["price"],log="quote_currency_replace_order")
def quote_currency_switch_configs(self, new_quote: str) -> int: def quote_currency_switch_configs(self, new_quote: str) -> int:

View File

@ -43,7 +43,7 @@ INSTANCE
10) edit_call_wait_time 11) reload_markets 12) fetch_full_log 10) edit_call_wait_time 11) reload_markets 12) fetch_full_log
13) paused_traders 14) fetch_log 15) edit_cooldown_multiplier 13) paused_traders 14) fetch_log 15) edit_cooldown_multiplier
16) get_balance 17) cancel_global_last_call 16) get_balance 17) cancel_global_last_call
18) mod_default_order_size 18) mod_default_order_size 19) toggle_log_orders
EARN EARN
31) toggle_pause 32) get_step_size 33) set_step_size 31) toggle_pause 32) get_step_size 33) set_step_size
@ -341,6 +341,13 @@ if __name__=="__main__":
print(json.loads(requests.post(url, headers=headers, json=parameters).content)) print(json.loads(requests.post(url, headers=headers, json=parameters).content))
input("Press ENTER to continue ") input("Press ENTER to continue ")
elif command==19:
print("toggle_log_orders turns on or off the logging of orders")
if input("Proceed? (Y/n) ") in ["Y","y",""]:
url = f"{base_url}{port}/toggle_log_orders"
print(json.loads(requests.post(url, headers=headers).content))
input("Press ENTER to continue ")
###################### ######################
######## EARN ######## ######## EARN ########