2025.10.03
This commit is contained in:
parent
c42a505e49
commit
2823dff56a
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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
30
main.py
|
|
@ -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
|
||||||
|
|
|
||||||
22
trader.py
22
trader.py
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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 ########
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue