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:
|
||||
. 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.write_order_history = self.broker_config.get("write_order_history", False)
|
||||
self.logger = Logger(self.broker_config)
|
||||
self.log_orders = self.broker_config.get("log_orders",False)
|
||||
|
||||
#Initialize database
|
||||
self.profits_database_filename = "profits/profits_database.db"
|
||||
|
|
@ -81,6 +82,16 @@ class Broker:
|
|||
def get_deals_cache(self):
|
||||
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):
|
||||
if "/" in pair:
|
||||
return pair
|
||||
|
|
@ -652,7 +663,7 @@ class Broker:
|
|||
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
|
||||
|
||||
|
|
@ -682,7 +693,7 @@ class Broker:
|
|||
while retries>0:
|
||||
try:
|
||||
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:
|
||||
order_book = self.get_order_book(symbol)
|
||||
if order_book=={}:
|
||||
|
|
@ -696,6 +707,8 @@ class Broker:
|
|||
price = self.find_minimum_viable_price(order_book,base_amount,side)
|
||||
#Maybe check for slippage here instead of within the trader itself? idk
|
||||
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)
|
||||
return self.get_order(new_order["id"],symbol)
|
||||
except Exception as e:
|
||||
|
|
@ -742,7 +755,7 @@ class Broker:
|
|||
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.
|
||||
|
||||
|
|
@ -767,6 +780,8 @@ class Broker:
|
|||
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)
|
||||
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)
|
||||
|
||||
return self.get_order(order_to_send["id"],symbol)
|
||||
|
|
@ -853,7 +868,7 @@ class Broker:
|
|||
# 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.
|
||||
|
||||
|
|
@ -869,6 +884,8 @@ class Broker:
|
|||
try:
|
||||
order_to_send = self.exchange.create_order(symbol,"limit",side,self.amount_to_precision(symbol,size),price)
|
||||
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)
|
||||
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)
|
||||
|
|
@ -1084,6 +1101,9 @@ class Logger:
|
|||
self.log_this(f"Error in send_tg_message: {e}",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):
|
||||
'''
|
||||
|
|
@ -1105,8 +1125,6 @@ class Logger:
|
|||
#Write to log file
|
||||
with open(f"logs/{self.exchange_name}.log","a") as log_file:
|
||||
log_file.write(text+"\n")
|
||||
log_file.close()
|
||||
|
||||
#Append to log list
|
||||
self.log_list.append(text)
|
||||
except Exception as e:
|
||||
|
|
|
|||
30
main.py
30
main.py
|
|
@ -18,7 +18,7 @@ import exchange_wrapper
|
|||
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
|
||||
|
|
@ -1238,6 +1238,20 @@ def switch_quote_currency():
|
|||
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'])
|
||||
def toggle_restart():
|
||||
'''
|
||||
|
|
@ -2360,6 +2374,20 @@ def unwrapped_toggle_restart():
|
|||
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():
|
||||
'''
|
||||
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:
|
||||
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.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)
|
||||
#Re-querying for the amount of base currency on the exchange
|
||||
free_base = self.fetch_free_base()
|
||||
|
|
@ -211,7 +211,7 @@ class trader:
|
|||
self.status.set_pause_reason("start_trader - sending first order")
|
||||
self.broker.logger.log_this("Sending first order...",2,self.status.get_pair())
|
||||
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())
|
||||
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())
|
||||
|
|
@ -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()):
|
||||
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())
|
||||
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:
|
||||
self.broker.logger.log_this("Problems with the cleanup order, new_limit_order returned None",1,self.status.get_pair())
|
||||
return 1
|
||||
|
|
@ -683,7 +683,7 @@ class trader:
|
|||
self.broker.logger.log_this("Can't fetch free base",1,self.status.get_pair())
|
||||
return 1
|
||||
#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)
|
||||
tries = self.broker.get_retries()
|
||||
while True:
|
||||
|
|
@ -723,7 +723,7 @@ class trader:
|
|||
|
||||
#Send the market order
|
||||
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)
|
||||
|
||||
#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()):
|
||||
#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())
|
||||
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)
|
||||
tries = self.broker.get_retries()
|
||||
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())
|
||||
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():
|
||||
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:
|
||||
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:
|
||||
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
|
||||
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.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:
|
||||
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.config.get_is_short(): #If in short mode, we don't recalculate anything.
|
||||
return 1
|
||||
|
|
@ -1515,7 +1515,7 @@ class trader:
|
|||
return self.broker.get_empty_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:
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ INSTANCE
|
|||
10) edit_call_wait_time 11) reload_markets 12) fetch_full_log
|
||||
13) paused_traders 14) fetch_log 15) edit_cooldown_multiplier
|
||||
16) get_balance 17) cancel_global_last_call
|
||||
18) mod_default_order_size
|
||||
18) mod_default_order_size 19) toggle_log_orders
|
||||
|
||||
EARN
|
||||
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))
|
||||
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 ########
|
||||
|
|
|
|||
Loading…
Reference in New Issue