Merge branch 'concurrent_trading_orders'
This commit is contained in:
commit
05b46203ab
|
|
@ -1,9 +1,11 @@
|
||||||
2025.09.04:
|
2025.09.05:
|
||||||
. Fixed bug in unwrapped_last_call().
|
|
||||||
. Now the trader supports multiple safety orders at the same time.
|
. Now the trader supports multiple safety orders at the same time.
|
||||||
. Removed forcing orders when importing a trader. Maybe it will be reinstated at a later date.
|
. Removed forcing orders when importing a trader. Maybe it will be reinstated at a later date.
|
||||||
. Removed endpoint /reload_safety_orders.
|
. Removed endpoint /reload_safety_orders.
|
||||||
. New endpoints: /mod_concurrent_safety orders, /mod_boosted_concurrent_safety_orders and /force_trader_close.
|
. New endpoints: /mod_concurrent_safety orders, /mod_boosted_concurrent_safety_orders and /force_trader_close.
|
||||||
|
. Modified cleanup routine.
|
||||||
|
. Default wait_time back to 0.5 seconds.
|
||||||
|
. General optimizations.
|
||||||
|
|
||||||
2025.08.19:
|
2025.08.19:
|
||||||
. Improved log trimming.
|
. Improved log trimming.
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ class Broker:
|
||||||
self.broker_config = broker_config
|
self.broker_config = broker_config
|
||||||
self.exchange = exchange
|
self.exchange = exchange
|
||||||
self.last_price = 0
|
self.last_price = 0
|
||||||
self.wait_time = 1 #Default wait time for API breathing room
|
self.wait_time = .5 #Default wait time for API breathing room
|
||||||
self.cooldown_multiplier = 2 #Default cooldown multiplier value
|
self.cooldown_multiplier = 2 #Default cooldown multiplier value
|
||||||
if "cooldown_multiplier" in self.broker_config:
|
if "cooldown_multiplier" in self.broker_config:
|
||||||
self.cooldown_multiplier = self.broker_config["cooldown_multiplier"]
|
self.cooldown_multiplier = self.broker_config["cooldown_multiplier"]
|
||||||
|
|
@ -869,38 +869,38 @@ class Broker:
|
||||||
return "the lowest price limit for sell orders is" in str(error_object).lower()
|
return "the lowest price limit for sell orders is" in str(error_object).lower()
|
||||||
|
|
||||||
|
|
||||||
def new_limit_orders(self, orders: list) -> list:
|
# def new_limit_orders(self, orders: list) -> list:
|
||||||
sent_orders = []
|
# sent_orders = []
|
||||||
#Send the orders
|
# #Send the orders
|
||||||
tries = self.retries
|
# tries = self.retries
|
||||||
while tries>=0:
|
# while tries>=0:
|
||||||
try:
|
# try:
|
||||||
sent_orders = self.exchange.create_orders(orders)
|
# sent_orders = self.exchange.create_orders(orders)
|
||||||
except Exception as e:
|
# except Exception as e:
|
||||||
self.logger.log_this(f"Exception while sending safety orders: {e}",1)
|
# self.logger.log_this(f"Exception while sending safety orders: {e}",1)
|
||||||
tries-=1
|
# tries-=1
|
||||||
time.sleep(self.wait_time)
|
# time.sleep(self.wait_time)
|
||||||
if tries==0:
|
# if tries==0:
|
||||||
return []
|
# return []
|
||||||
|
|
||||||
#Retrieve the orders from the exchange by id to confirm that they were sent
|
# #Retrieve the orders from the exchange by id to confirm that they were sent
|
||||||
#Specially for OKX, since the orders that create_orders return are empty (only id is present)
|
# #Specially for OKX, since the orders that create_orders return are empty (only id is present)
|
||||||
returned_orders = []
|
# returned_orders = []
|
||||||
for order in sent_orders:
|
# for order in sent_orders:
|
||||||
tries = self.retries
|
# tries = self.retries
|
||||||
while tries>=0:
|
# while tries>=0:
|
||||||
try:
|
# try:
|
||||||
returned_orders.append(self.get_order(order["id"],order["symbol"]))
|
# returned_orders.append(self.get_order(order["id"],order["symbol"]))
|
||||||
time.sleep(self.wait_time)
|
# time.sleep(self.wait_time)
|
||||||
except Exception as e:
|
# except Exception as e:
|
||||||
self.logger.log_this(f"Exception while retrieving safety orders: {e}",1)
|
# self.logger.log_this(f"Exception while retrieving safety orders: {e}",1)
|
||||||
tries-=1
|
# tries-=1
|
||||||
if tries==0:
|
# if tries==0:
|
||||||
if self.get_exchange_name()=="okex":
|
# if self.get_exchange_name()=="okex":
|
||||||
return returned_orders
|
# return returned_orders
|
||||||
returned_orders.append(order) #In the case of the other exchanges, we just assume that the order was sent and append it.
|
# returned_orders.append(order) #In the case of the other exchanges, we just assume that the order was sent and append it.
|
||||||
time.sleep(self.wait_time)
|
# time.sleep(self.wait_time)
|
||||||
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):
|
||||||
|
|
|
||||||
11
main.py
11
main.py
|
|
@ -18,7 +18,7 @@ import exchange_wrapper
|
||||||
import trader
|
import trader
|
||||||
|
|
||||||
|
|
||||||
version = "2025.09.04"
|
version = "2025.09.05"
|
||||||
|
|
||||||
'''
|
'''
|
||||||
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
|
||||||
|
|
@ -311,14 +311,19 @@ def main_routine():
|
||||||
futures = []
|
futures = []
|
||||||
pairs_to_fetch = []
|
pairs_to_fetch = []
|
||||||
online_pairs = []
|
online_pairs = []
|
||||||
|
open_orders_dict = {}
|
||||||
|
|
||||||
for instance in running_traders:
|
for instance in running_traders:
|
||||||
pairs_to_fetch.append(instance.status.get_pair())
|
pairs_to_fetch.append(instance.status.get_pair())
|
||||||
|
|
||||||
open_orders = broker.fetch_open_orders(pairs_to_fetch)
|
for item in broker.fetch_open_orders(pairs_to_fetch):
|
||||||
|
if item["symbol"] not in open_orders_dict:
|
||||||
|
open_orders_dict[item["symbol"]] = [item]
|
||||||
|
else:
|
||||||
|
open_orders_dict[item["symbol"]].append(item)
|
||||||
|
|
||||||
for instance in running_traders:
|
for instance in running_traders:
|
||||||
future = executor.submit(instance.check_status, open_orders)
|
future = executor.submit(instance.check_status, open_orders_dict[instance.status.get_pair()])
|
||||||
futures.append(future)
|
futures.append(future)
|
||||||
online_pairs.append(f"{instance.base}{instance.quote}")
|
online_pairs.append(f"{instance.base}{instance.quote}")
|
||||||
|
|
||||||
|
|
|
||||||
41
trader.py
41
trader.py
|
|
@ -441,19 +441,23 @@ class trader:
|
||||||
if balance_to_clean is None:
|
if balance_to_clean is None:
|
||||||
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
|
||||||
#balance_to_clean /= 2 #Maybe it's a good idea, sort of DCAing the dust.
|
balance_to_clean /= 2 #Maybe it's a good idea, sort of DCAing the dust.
|
||||||
min_base_size = self.broker.get_min_base_size(self.status.get_pair())
|
min_base_size = self.broker.get_min_base_size(self.status.get_pair())
|
||||||
minimum_cleanup_size = self.status.get_safety_orders()[0]["amount"]*2
|
#minimum_cleanup_size = self.status.get_safety_orders()[0]["amount"]*2
|
||||||
|
|
||||||
if balance_to_clean-minimum_cleanup_size >= min_base_size:
|
if balance_to_clean >= min_base_size:
|
||||||
self.broker.logger.log_this(f"Balance to clean: {balance_to_clean-minimum_cleanup_size} {self.base}",2,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())
|
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-minimum_cleanup_size,"sell",self.status.get_take_profit_price())
|
cleanup_order = self.broker.new_limit_order(self.status.get_pair(),balance_to_clean,"sell",self.status.get_take_profit_price())
|
||||||
if cleanup_order not in [None,self.broker.get_empty_order()]:
|
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
|
||||||
|
elif cleanup_order==self.broker.get_empty_order():
|
||||||
|
self.broker.logger.log_this("Problems with the cleanup order, new_limit_order returned an empty order",1,self.status.get_pair())
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
self.broker.logger.log_this("Cleanup successful",2,self.status.get_pair())
|
self.broker.logger.log_this("Cleanup successful",2,self.status.get_pair())
|
||||||
return 0
|
return 0
|
||||||
self.broker.logger.log_this("Problems with the cleanup order",1,self.status.get_pair())
|
|
||||||
return 1
|
|
||||||
self.broker.logger.log_this("No cleanup needed",2,self.status.get_pair())
|
self.broker.logger.log_this("No cleanup needed",2,self.status.get_pair())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
@ -1134,8 +1138,7 @@ class trader:
|
||||||
|
|
||||||
#Extract ids from order list
|
#Extract ids from order list
|
||||||
self.status.set_pause_reason("filtering open orders")
|
self.status.set_pause_reason("filtering open orders")
|
||||||
open_orders_list = [order for order in open_orders if order["symbol"]==self.status.get_pair()]
|
open_orders_ids = [order["id"] for order in open_orders]
|
||||||
open_orders_ids = [order["id"] for order in open_orders_list]
|
|
||||||
|
|
||||||
self.status.set_pause_reason("check for tp_order is valid")
|
self.status.set_pause_reason("check for tp_order is valid")
|
||||||
#Checks if the take profit order is valid
|
#Checks if the take profit order is valid
|
||||||
|
|
@ -1158,15 +1161,15 @@ class trader:
|
||||||
self.status.set_pause_reason("check if tp_order is filled")
|
self.status.set_pause_reason("check if tp_order is filled")
|
||||||
#Checks if the take profit order is filled
|
#Checks if the take profit order is filled
|
||||||
if self.status.get_take_profit_order()["id"] not in open_orders_ids:
|
if self.status.get_take_profit_order()["id"] not in open_orders_ids:
|
||||||
# I hate Kucoin:
|
# # I hate Kucoin:
|
||||||
# Check if the order has a wrong id. If so, update the order.
|
# # Check if the order has a wrong id. If so, update the order.
|
||||||
for order in open_orders_list:
|
# for order in open_orders:
|
||||||
if order["amount"]==self.status.get_take_profit_order()["amount"] and order["price"]==self.status.get_take_profit_order()["price"] and order["side"]==self.status.get_take_profit_order()["side"]:
|
# if order["amount"]==self.status.get_take_profit_order()["amount"] and order["price"]==self.status.get_take_profit_order()["price"] and order["side"]==self.status.get_take_profit_order()["side"]:
|
||||||
#Right order, wrong id. Update order
|
# #Right order, wrong id. Update order
|
||||||
self.broker.logger.log_this(f"Updating take profit order for {self.status.get_pair()}")
|
# self.broker.logger.log_this(f"Updating take profit order for {self.status.get_pair()}",1,self.status.get_pair())
|
||||||
self.status.set_take_profit_order(order)
|
# self.status.set_take_profit_order(order)
|
||||||
self.update_status(True)
|
# self.update_status(True)
|
||||||
return 0
|
# return 0
|
||||||
|
|
||||||
tp_status = self.broker.get_order(self.status.get_take_profit_order()["id"],self.status.get_pair())
|
tp_status = self.broker.get_order(self.status.get_take_profit_order()["id"],self.status.get_pair())
|
||||||
if tp_status["status"]=="closed":
|
if tp_status["status"]=="closed":
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue