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 = []
pairs_to_fetch = []
online_pairs = []
open_orders_dict = {}
for instance in running_traders:
pairs_to_fetch.append(instance.status.get_pair())
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)
open_orders = broker.fetch_open_orders(pairs_to_fetch)
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)
online_pairs.append(f"{instance.base}{instance.quote}")

View File

@ -770,6 +770,7 @@ class trader:
#Check if some safety orders were filled
partial_filled_amount = 0
partial_filled_price = []
for order in self.status.get_safety_orders():
closed_order = self.broker.get_order(order["id"],self.status.get_pair())
if closed_order["filled"]==0:
@ -777,10 +778,11 @@ class trader:
break
#Sum the filled amounts
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.
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_quote_spent(self.status.get_quote_spent() + closed_order["cost"])
#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"])
#Save the order
if self.broker.get_follow_order_history():
self.status.update_deal_order_history(closed_order)
@ -790,23 +792,26 @@ class trader:
#Now we can clear the safety order list
self.status.set_safety_orders([])
# if partial_filled_amount!=0 and partial_filled_amount>self.broker.get_min_base_size(self.status.get_pair()):
# #send a sell market order and sum the profits
# market_order = self.broker.new_market_order(self.status.get_pair(),partial_filled_amount,"sell",amount_in_base=True)
# #Wait for it to be filled
# tries = self.broker.get_retries()
# while True:
# time.sleep(self.broker.get_wait_time())
# partial_fill_order = self.broker.get_order(market_order["id"],self.status.get_pair())
# if partial_fill_order["status"]=="closed":
# break
# tries-=1
# if tries==0:
# self.broker.logger.log_this("Partial fill sell order not filling.",1,self.status.get_pair())
# break
# #Sum the profit
#Handle the partial fills
if not self.status.get_is_short():
#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)
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
market_order = self.broker.new_market_order(self.status.get_pair(),partial_filled_amount,"sell",amount_in_base=True)
#Wait for it to be filled
tries = self.broker.get_retries()
while True:
time.sleep(self.broker.get_wait_time())
partial_fill_order = self.broker.get_order(market_order["id"],self.status.get_pair())
if partial_fill_order["status"]=="closed":
avg_buy_price = sum(partial_filled_price)/len(partial_filled_price)
partial_profit = market_order["cost"]-(avg_buy_price*partial_filled_amount)-self.parse_fees(market_order)[1]
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):
self.status.set_pause_reason("calculating profit")
@ -1138,9 +1143,10 @@ class trader:
#Extract ids from order list
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
if self.status.get_take_profit_order() is None:
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.
# 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.
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"]:
#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())