partial profit support

This commit is contained in:
Nicolás Sánchez 2025-09-06 11:29:36 -03:00
parent 08ce7c65a0
commit 5cf2979f38
2 changed files with 30 additions and 30 deletions

10
main.py
View File

@ -311,19 +311,13 @@ 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())
for item in broker.fetch_open_orders(pairs_to_fetch): open_orders = 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_dict[instance.status.get_pair()]) future = executor.submit(instance.check_status, open_orders)
futures.append(future) futures.append(future)
online_pairs.append(f"{instance.base}{instance.quote}") online_pairs.append(f"{instance.base}{instance.quote}")

View File

@ -770,6 +770,7 @@ class trader:
#Check if some safety orders were filled #Check if some safety orders were filled
partial_filled_amount = 0 partial_filled_amount = 0
partial_filled_price = []
for order in self.status.get_safety_orders(): for order in self.status.get_safety_orders():
closed_order = self.broker.get_order(order["id"],self.status.get_pair()) closed_order = self.broker.get_order(order["id"],self.status.get_pair())
if closed_order["filled"]==0: if closed_order["filled"]==0:
@ -777,10 +778,11 @@ class trader:
break break
#Sum the filled amounts #Sum the filled amounts
partial_filled_amount+=closed_order["filled"] partial_filled_amount+=closed_order["filled"]
partial_filled_price.append(closed_order["average"])
#Better than this, the total filled and total cost can be used to send a sell market order of the partial filled amount, and add that to the profit. #Better than this, the total filled and total cost can be used to send a sell market order of the partial filled amount, and add that to the profit.
self.broker.logger.log_this(f"Old safety order is partially filled, ID: {closed_order['id']}, {closed_order['filled']}/{closed_order['amount']} {self.base} filled",1,self.status.get_pair()) self.broker.logger.log_this(f"Old safety order is partially filled, ID: {closed_order['id']}, {closed_order['filled']}/{closed_order['amount']} {self.base} filled",1,self.status.get_pair())
self.status.set_base_bought(self.status.get_base_bought() + closed_order["filled"] - self.parse_fees(closed_order)[0]) #self.status.set_base_bought(self.status.get_base_bought() + closed_order["filled"] - self.parse_fees(closed_order)[0])
self.status.set_quote_spent(self.status.get_quote_spent() + closed_order["cost"]) #self.status.set_quote_spent(self.status.get_quote_spent() + closed_order["cost"])
#Save the order #Save the order
if self.broker.get_follow_order_history(): if self.broker.get_follow_order_history():
self.status.update_deal_order_history(closed_order) self.status.update_deal_order_history(closed_order)
@ -790,23 +792,26 @@ class trader:
#Now we can clear the safety order list #Now we can clear the safety order list
self.status.set_safety_orders([]) self.status.set_safety_orders([])
# if partial_filled_amount!=0 and partial_filled_amount>self.broker.get_min_base_size(self.status.get_pair()): #Handle the partial fills
# #send a sell market order and sum the profits if not self.status.get_is_short():
# market_order = self.broker.new_market_order(self.status.get_pair(),partial_filled_amount,"sell",amount_in_base=True) #With short traders is just an accounting issue, since when the trader restarts it will be buying cheaper what it sold more expensive in the partially filled safety order(s)
# #Wait for it to be filled 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()):
# tries = self.broker.get_retries() #send a market order and sum the profits
# while True: market_order = self.broker.new_market_order(self.status.get_pair(),partial_filled_amount,"sell",amount_in_base=True)
# time.sleep(self.broker.get_wait_time()) #Wait for it to be filled
# partial_fill_order = self.broker.get_order(market_order["id"],self.status.get_pair()) tries = self.broker.get_retries()
# if partial_fill_order["status"]=="closed": while True:
# break time.sleep(self.broker.get_wait_time())
# tries-=1 partial_fill_order = self.broker.get_order(market_order["id"],self.status.get_pair())
# if tries==0: if partial_fill_order["status"]=="closed":
# self.broker.logger.log_this("Partial fill sell order not filling.",1,self.status.get_pair()) avg_buy_price = sum(partial_filled_price)/len(partial_filled_price)
# break partial_profit = market_order["cost"]-(avg_buy_price*partial_filled_amount)-self.parse_fees(market_order)[1]
# #Sum the profit self.status.set_partial_profit(self.status.get_partial_profit()+partial_profit)
break
tries-=1
if tries==0:
self.broker.logger.log_this("Partial fill sell order not filling.",1,self.status.get_pair())
break
if not self.broker.check_for_duplicate_profit_in_db(filled_order): if not self.broker.check_for_duplicate_profit_in_db(filled_order):
self.status.set_pause_reason("calculating profit") self.status.set_pause_reason("calculating profit")
@ -1138,9 +1143,10 @@ 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_ids = [order["id"] for order in 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_list]
self.status.set_pause_reason("check for tp_order is valid") self.status.set_pause_reason("check if tp_order is valid")
#Checks if the take profit order is valid #Checks if the take profit order is valid
if self.status.get_take_profit_order() is None: if self.status.get_take_profit_order() is None:
self.broker.logger.log_this("Take profit order is None",1,self.status.get_pair()) self.broker.logger.log_this("Take profit order is None",1,self.status.get_pair())
@ -1164,7 +1170,7 @@ class trader:
# 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.
# To cover a very rare case that happens if the trader sends a new take profit order but is interrupted before saving the status. # To cover a very rare case that happens if the trader sends a new take profit order but is interrupted before saving the status.
# Not sure if it is worth to keep this code. # Not sure if it is worth to keep this code.
for order in open_orders: for order in open_orders_list:
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()}",1,self.status.get_pair()) self.broker.logger.log_this(f"Updating take profit order for {self.status.get_pair()}",1,self.status.get_pair())