/mod_concurrent_safety_orders endpoint added
This commit is contained in:
parent
069cff2402
commit
3daca5336e
55
main.py
55
main.py
|
|
@ -18,7 +18,7 @@ import exchange_wrapper
|
||||||
import trader
|
import trader
|
||||||
|
|
||||||
|
|
||||||
version = "2025.08.24"
|
version = "2025.08.25"
|
||||||
|
|
||||||
'''
|
'''
|
||||||
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
|
||||||
|
|
@ -849,6 +849,32 @@ def mod_order_size():
|
||||||
return jsonify({'Error': 'Halp'})
|
return jsonify({'Error': 'Halp'})
|
||||||
|
|
||||||
|
|
||||||
|
@base_api.route("/mod_concurrent_safety_orders", methods=['POST'])
|
||||||
|
def mod_concurrent_safety_orders():
|
||||||
|
'''
|
||||||
|
POST request
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
base: str
|
||||||
|
quote: str
|
||||||
|
amount: int
|
||||||
|
'''
|
||||||
|
|
||||||
|
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
|
||||||
|
try:
|
||||||
|
if request.json is None:
|
||||||
|
return jsonify({'Error': 'request.json is None'})
|
||||||
|
data = request.json
|
||||||
|
base = data["base"]
|
||||||
|
quote = data["quote"]
|
||||||
|
amount = data["amount"]
|
||||||
|
return unwrapped_mod_concurrent_safety_orders(base,quote,amount)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return jsonify({'Error': 'Halp'})
|
||||||
|
|
||||||
|
|
||||||
@base_api.route("/mod_default_order_size", methods=['POST'])
|
@base_api.route("/mod_default_order_size", methods=['POST'])
|
||||||
def mod_default_order_size():
|
def mod_default_order_size():
|
||||||
'''
|
'''
|
||||||
|
|
@ -1784,6 +1810,7 @@ def unwrapped_mod_order_size(base,quote,amount):
|
||||||
for instance in running_traders:
|
for instance in running_traders:
|
||||||
if symbol==instance.config.get_pair():
|
if symbol==instance.config.get_pair():
|
||||||
instance.config.set_order_size(float(amount))
|
instance.config.set_order_size(float(amount))
|
||||||
|
instance.config.save_to_file()
|
||||||
broker.logger.log_this("Done. The change will take effect when the next deal is started",2,symbol)
|
broker.logger.log_this("Done. The change will take effect when the next deal is started",2,symbol)
|
||||||
return jsonify({"Success": "Success. The change will take effect when the next deal is started"})
|
return jsonify({"Success": "Success. The change will take effect when the next deal is started"})
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -1791,6 +1818,32 @@ def unwrapped_mod_order_size(base,quote,amount):
|
||||||
return jsonify({"Error": "Error changing order size"})
|
return jsonify({"Error": "Error changing order size"})
|
||||||
|
|
||||||
|
|
||||||
|
def unwrapped_mod_concurrent_safety_orders(base,quote,amount):
|
||||||
|
'''
|
||||||
|
Modifies the amount of safety orders that a trader keeps opened at the same time.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
base (str): The base currency of the pair.
|
||||||
|
quote (str): The quote currency of the pair.
|
||||||
|
amount (str): The new amount.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
jsonify: A jsonified dictionary detailing the outcome of the operation
|
||||||
|
'''
|
||||||
|
|
||||||
|
try:
|
||||||
|
symbol = f"{base}/{quote}"
|
||||||
|
for instance in running_traders:
|
||||||
|
if symbol==instance.config.get_pair():
|
||||||
|
instance.config.set_concurrent_safety_orders(int(amount))
|
||||||
|
instance.config.save_to_file()
|
||||||
|
broker.logger.log_this("Done. The change will take effect as new safety orders are sent or filled",2,symbol)
|
||||||
|
return jsonify({"Success": "Success. The change will take effect as new safety orders are sent or filled"})
|
||||||
|
except Exception:
|
||||||
|
broker.logger.log_this("Error changing safety orders amount. Ignoring...",2,symbol)
|
||||||
|
return jsonify({"Error": "Error changing safety orders amount"})
|
||||||
|
|
||||||
|
|
||||||
def unwrapped_mod_default_order_size(amount):
|
def unwrapped_mod_default_order_size(amount):
|
||||||
'''
|
'''
|
||||||
Modifies the default order size of a broker.
|
Modifies the default order size of a broker.
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,10 @@ class StatusHandler:
|
||||||
def get_status_file_path(self):
|
def get_status_file_path(self):
|
||||||
return self.status_file_path
|
return self.status_file_path
|
||||||
|
|
||||||
|
def set_pair(self, trading_pair):
|
||||||
|
self.pair = trading_pair
|
||||||
|
return 0
|
||||||
|
|
||||||
def set_status_file_path(self, new_file_path: str):
|
def set_status_file_path(self, new_file_path: str):
|
||||||
# if not isinstance(new_file_path, str):
|
# if not isinstance(new_file_path, str):
|
||||||
# self.broker.logger.log_this(f"File path provided is not a string",1,self.get_pair())
|
# self.broker.logger.log_this(f"File path provided is not a string",1,self.get_pair())
|
||||||
|
|
|
||||||
3
todo.txt
3
todo.txt
|
|
@ -9,8 +9,7 @@ Mandatory:
|
||||||
5. Dockerize.
|
5. Dockerize.
|
||||||
6. Inspect orderbook liquidity prior to changing mode from short to long (big sell market order needs to have liquidity).
|
6. Inspect orderbook liquidity prior to changing mode from short to long (big sell market order needs to have liquidity).
|
||||||
7. API endpoint to modify the amount of concurrent safety orders
|
7. API endpoint to modify the amount of concurrent safety orders
|
||||||
8. Maybe when boosted, also increment the amount of concurrent safety orders?
|
8. Use create_orders ccxt method to send the batch of safety orders (Binance does not support it in spot trading)
|
||||||
9. Use create_orders ccxt method to send the batch of safety orders (Binance does not support it in spot trading)
|
|
||||||
|
|
||||||
|
|
||||||
Would be nice to have:
|
Would be nice to have:
|
||||||
|
|
|
||||||
382
trader.py
382
trader.py
|
|
@ -118,77 +118,77 @@ class trader:
|
||||||
self.status.set_safety_orders_filled(0)
|
self.status.set_safety_orders_filled(0)
|
||||||
|
|
||||||
#Reloads the market
|
#Reloads the market
|
||||||
new_market_data = self.broker.fetch_market(self.config.get_pair())
|
new_market_data = self.broker.fetch_market(self.status.get_pair())
|
||||||
if new_market_data is not None:
|
if new_market_data is not None:
|
||||||
self.market = new_market_data
|
self.market = new_market_data
|
||||||
|
|
||||||
self.pause = True
|
self.pause = True
|
||||||
self.status.set_pause_reason("start_trader")
|
self.status.set_pause_reason("start_trader")
|
||||||
|
|
||||||
if self.config.get_is_short():
|
if self.status.get_is_short():
|
||||||
self.broker.logger.log_this("Calculating optimal order size...",2,self.config.get_pair())
|
self.broker.logger.log_this("Calculating optimal order size...",2,self.status.get_pair())
|
||||||
|
|
||||||
#Get minimum order size from exchange
|
#Get minimum order size from exchange
|
||||||
self.broker.logger.log_this("Fetching minimum order size...",2,self.config.get_pair())
|
self.broker.logger.log_this("Fetching minimum order size...",2,self.status.get_pair())
|
||||||
min_base_size = self.broker.get_min_base_size(self.config.get_pair())
|
min_base_size = self.broker.get_min_base_size(self.status.get_pair())
|
||||||
if min_base_size is None:
|
if min_base_size is None:
|
||||||
self.broker.logger.log_this("Can't fetch the minimum order size",1,self.config.get_pair())
|
self.broker.logger.log_this("Can't fetch the minimum order size",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Fetch the amount of free base available on the exchange
|
#Fetch the amount of free base available on the exchange
|
||||||
self.broker.logger.log_this("Fetching free base currency on the exchange...",2,self.config.get_pair())
|
self.broker.logger.log_this("Fetching free base currency on the exchange...",2,self.status.get_pair())
|
||||||
free_base = self.fetch_free_base()
|
free_base = self.fetch_free_base()
|
||||||
if free_base is None:
|
if free_base is None:
|
||||||
self.broker.logger.log_this("Can't fetch the amount of base at the exchange",1,self.config.get_pair())
|
self.broker.logger.log_this("Can't fetch the amount of base at the exchange",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Buy missing base sold because of rounding errors (rare)
|
#Buy missing base sold because of rounding errors (rare)
|
||||||
if self.status.get_old_long()!={}:
|
if self.status.get_old_long()!={}:
|
||||||
diff = self.broker.amount_to_precision(self.config.get_pair(), self.status.get_old_long()["tp_amount"] - free_base)
|
diff = self.broker.amount_to_precision(self.status.get_pair(), self.status.get_old_long()["tp_amount"] - free_base)
|
||||||
if diff>min_base_size:
|
if diff>min_base_size:
|
||||||
self.broker.logger.log_this(f"Buying missing {diff} {self.base}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Buying missing {diff} {self.base}",1,self.status.get_pair())
|
||||||
self.broker.new_market_order(self.config.get_pair(),diff,"buy",amount_in_base=True)
|
self.broker.new_market_order(self.status.get_pair(),diff,"buy",amount_in_base=True)
|
||||||
time.sleep(self.broker.get_wait_time()*2)
|
time.sleep(self.broker.get_wait_time()*2)
|
||||||
#Re-quering for the amount of base currency on the exchange
|
#Re-quering for the amount of base currency on the exchange
|
||||||
free_base = self.fetch_free_base()
|
free_base = self.fetch_free_base()
|
||||||
if free_base is None:
|
if free_base is None:
|
||||||
self.broker.logger.log_this("Can't fetch the amount of base at the exchange",1,self.config.get_pair())
|
self.broker.logger.log_this("Can't fetch the amount of base at the exchange",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Calculate order size and amount of safety orders
|
#Calculate order size and amount of safety orders
|
||||||
self.broker.logger.log_this("Calculating the order size...",2,self.config.get_pair())
|
self.broker.logger.log_this("Calculating the order size...",2,self.status.get_pair())
|
||||||
order_size,no_of_safety_orders = self.calculate_order_size(free_base,min_base_size,self.config.get_max_short_safety_orders())
|
order_size,no_of_safety_orders = self.calculate_order_size(free_base,min_base_size,self.config.get_max_short_safety_orders())
|
||||||
if order_size is None or no_of_safety_orders is None:
|
if order_size is None or no_of_safety_orders is None:
|
||||||
self.broker.logger.log_this("Can't calculate optimal size",1,self.config.get_pair())
|
self.broker.logger.log_this("Can't calculate optimal size",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
self.config.set_order_size(order_size)
|
self.status.set_order_size(order_size)
|
||||||
self.config.set_no_of_safety_orders(no_of_safety_orders)
|
self.status.set_no_of_safety_orders(no_of_safety_orders)
|
||||||
self.broker.logger.log_this(f"Order size: {self.broker.amount_to_precision(self.config.get_pair(),order_size)}. Amount of safety orders: {no_of_safety_orders}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Order size: {self.broker.amount_to_precision(self.status.get_pair(),order_size)}. Amount of safety orders: {no_of_safety_orders}",2,self.status.get_pair())
|
||||||
|
|
||||||
#Write the changes to the config file
|
#Write the changes to the config file
|
||||||
self.config.save_to_file()
|
self.config.save_to_file()
|
||||||
else:
|
else:
|
||||||
#Check order size
|
#Check order size
|
||||||
self.status.set_pause_reason("start_trader - checking order size")
|
self.status.set_pause_reason("start_trader - checking order size")
|
||||||
self.broker.logger.log_this("Checking for order size",2,self.config.get_pair())
|
self.broker.logger.log_this("Checking for order size",2,self.status.get_pair())
|
||||||
minimum_order_size_allowed = self.broker.get_min_quote_size(self.config.get_pair())
|
minimum_order_size_allowed = self.broker.get_min_quote_size(self.status.get_pair())
|
||||||
if minimum_order_size_allowed is not None and minimum_order_size_allowed>self.config.get_order_size():
|
if minimum_order_size_allowed is not None and minimum_order_size_allowed>self.config.get_order_size():
|
||||||
self.broker.logger.log_this(f"Order size too small. Minimum order size is {minimum_order_size_allowed} {self.quote}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Order size too small. Minimum order size is {minimum_order_size_allowed} {self.quote}",1,self.status.get_pair())
|
||||||
if minimum_order_size_allowed<self.config.get_order_size()*2:
|
if minimum_order_size_allowed<self.config.get_order_size()*2:
|
||||||
#int(n)+1 is treated here as a simplified ceil function, since minimum_order_size_allowed will always be positive.
|
#int(n)+1 is treated here as a simplified ceil function, since minimum_order_size_allowed will always be positive.
|
||||||
self.broker.logger.log_this(f"Due to exchange limits, trader initial order size will be {float(int(minimum_order_size_allowed)+1)} {self.quote}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Due to exchange limits, trader initial order size will be {float(int(minimum_order_size_allowed)+1)} {self.quote}",1,self.status.get_pair())
|
||||||
self.config.set_order_size(float(int(minimum_order_size_allowed)+1))
|
self.config.set_order_size(float(int(minimum_order_size_allowed)+1))
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Limit difference is more than 2x the configured order size. Please adjust the order size in the trader config file and restart the trader.",1,self.config.get_pair())
|
self.broker.logger.log_this("Limit difference is more than 2x the configured order size. Please adjust the order size in the trader config file and restart the trader.",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#check slippage
|
#check slippage
|
||||||
if self.config.get_check_slippage():
|
if self.config.get_check_slippage():
|
||||||
self.broker.logger.log_this("Checking slippage...",2,self.config.get_pair())
|
self.broker.logger.log_this("Checking slippage...",2,self.status.get_pair())
|
||||||
self.status.set_pause_reason("start_trader - checking slippage")
|
self.status.set_pause_reason("start_trader - checking slippage")
|
||||||
if self.check_orderbook_depth(self.broker.get_slippage_default_threshold(),self.config.get_order_size()):
|
if self.check_orderbook_depth(self.broker.get_slippage_default_threshold(),self.config.get_order_size()):
|
||||||
#Slippage threshold exceeded
|
#Slippage threshold exceeded
|
||||||
self.broker.logger.log_this("Slippage threshold exceeded",1,self.config.get_pair())
|
self.broker.logger.log_this("Slippage threshold exceeded",1,self.status.get_pair())
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
self.status.set_pause_reason("start_trader - after slippage")
|
self.status.set_pause_reason("start_trader - after slippage")
|
||||||
|
|
@ -196,12 +196,12 @@ class trader:
|
||||||
|
|
||||||
#Sending initial order
|
#Sending initial order
|
||||||
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.config.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.config.get_pair(),self.config.get_order_size(),action)
|
first_order = self.broker.new_market_order(self.status.get_pair(),self.status.get_order_size(),action)
|
||||||
#self.broker.logger.log_this(f"First order id: {first_order}",1,self.config.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.config.get_pair())
|
self.broker.logger.log_this(f"Error sending the first order. Market order returned {first_order}",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
tries = self.broker.get_retries()*2 #This is really necessary, don't change it. Don't. DON'T.
|
tries = self.broker.get_retries()*2 #This is really necessary, don't change it. Don't. DON'T.
|
||||||
|
|
||||||
|
|
@ -212,22 +212,22 @@ class trader:
|
||||||
# When that happens, the amount of base taken into account by the trader is lower than the amount bought,
|
# When that happens, the amount of base taken into account by the trader is lower than the amount bought,
|
||||||
# which ends up misrepresenting the trade cost per unit of base, which causes the take profit price to skyrocket.
|
# which ends up misrepresenting the trade cost per unit of base, which causes the take profit price to skyrocket.
|
||||||
time.sleep(self.broker.get_wait_time())
|
time.sleep(self.broker.get_wait_time())
|
||||||
returned_order = self.broker.get_order(first_order["id"],self.config.get_pair())
|
returned_order = self.broker.get_order(first_order["id"],self.status.get_pair())
|
||||||
if returned_order==self.broker.get_empty_order():
|
if returned_order==self.broker.get_empty_order():
|
||||||
self.broker.logger.log_this("Problems with the initial order",1,self.config.get_pair())
|
self.broker.logger.log_this("Problems with the initial order",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
elif returned_order["status"]=="closed":
|
elif returned_order["status"]=="closed":
|
||||||
break
|
break
|
||||||
elif returned_order["status"]=="expired":
|
elif returned_order["status"]=="expired":
|
||||||
self.broker.logger.log_this(f"First order expired. Id: {returned_order['id']}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"First order expired. Id: {returned_order['id']}",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
tries-=1
|
tries-=1
|
||||||
self.broker.logger.log_this("Waiting for initial order to get filled...",2,self.config.get_pair())
|
self.broker.logger.log_this("Waiting for initial order to get filled...",2,self.status.get_pair())
|
||||||
self.broker.logger.log_this(f"Order ID: {returned_order['id']}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Order ID: {returned_order['id']}",2,self.status.get_pair())
|
||||||
if tries==0:
|
if tries==0:
|
||||||
self.broker.logger.log_this("Restart retries exhausted.",0,self.config.get_pair())
|
self.broker.logger.log_this("Restart retries exhausted.",0,self.status.get_pair())
|
||||||
self.broker.cancel_order(returned_order["id"],self.config.get_pair())
|
self.broker.cancel_order(returned_order["id"],self.status.get_pair())
|
||||||
#self.restart = True #This restart is tricky, it can end up in an endless loop of retries
|
#self.restart = True #This restart is tricky, it can end up in an endless loop of retries
|
||||||
#At this point, both the take_profit_routine initialization AND the subsequent restart attempt failed.
|
#At this point, both the take_profit_routine initialization AND the subsequent restart attempt failed.
|
||||||
#Since it only reaches this point very unfrequently, let we'll the trader get stuck in a pause state.
|
#Since it only reaches this point very unfrequently, let we'll the trader get stuck in a pause state.
|
||||||
|
|
@ -241,8 +241,8 @@ class trader:
|
||||||
# Reset the fee count and sum fees from the first order
|
# Reset the fee count and sum fees from the first order
|
||||||
self.status.set_fees_paid_in_base(self.parse_fees(returned_order)[0])
|
self.status.set_fees_paid_in_base(self.parse_fees(returned_order)[0])
|
||||||
self.status.set_fees_paid_in_quote(self.parse_fees(returned_order)[1])
|
self.status.set_fees_paid_in_quote(self.parse_fees(returned_order)[1])
|
||||||
self.broker.logger.log_this(f"Fees paid: {self.status.get_fees_paid_in_base()} {self.base}, {self.status.get_fees_paid_in_quote()} {self.quote}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Fees paid: {self.status.get_fees_paid_in_base()} {self.base}, {self.status.get_fees_paid_in_quote()} {self.quote}",2,self.status.get_pair())
|
||||||
self.broker.logger.log_this(f"Take profit order ID: {returned_order['id']}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Take profit order ID: {returned_order['id']}",2,self.status.get_pair())
|
||||||
|
|
||||||
# Sum total amount of quote and base
|
# Sum total amount of quote and base
|
||||||
if returned_order["filled"]!=None:
|
if returned_order["filled"]!=None:
|
||||||
|
|
@ -251,33 +251,33 @@ class trader:
|
||||||
self.status.set_base_bought(self.status.get_base_bought()-self.status.get_fees_paid_in_base())
|
self.status.set_base_bought(self.status.get_base_bought()-self.status.get_fees_paid_in_base())
|
||||||
self.status.set_quote_spent(returned_order["cost"])
|
self.status.set_quote_spent(returned_order["cost"])
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Error starting trader. Aborting.",1,self.config.get_pair())
|
self.broker.logger.log_this("Error starting trader. Aborting.",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Send the take profit order
|
# Send the take profit order
|
||||||
self.status.set_pause_reason("start_trader - sending tp order")
|
self.status.set_pause_reason("start_trader - sending tp order")
|
||||||
self.broker.logger.log_this("Sending take profit order...",2,self.config.get_pair())
|
self.broker.logger.log_this("Sending take profit order...",2,self.status.get_pair())
|
||||||
if self.send_new_tp_order()==0:
|
if self.send_new_tp_order()==0:
|
||||||
self.broker.logger.log_this("Take profit order sent",2,self.config.get_pair())
|
self.broker.logger.log_this("Take profit order sent",2,self.status.get_pair())
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Error sending take profit order. Aborting.",1,self.config.get_pair())
|
self.broker.logger.log_this("Error sending take profit order. Aborting.",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Generate the safety prices table
|
# Generate the safety prices table
|
||||||
self.status.set_start_price(self.broker.price_to_precision(self.config.get_pair(),self.status.get_quote_spent()/self.status.get_base_bought()))
|
self.status.set_start_price(self.broker.price_to_precision(self.status.get_pair(),self.status.get_quote_spent()/self.status.get_base_bought()))
|
||||||
self.status.set_safety_price_table(self.calculate_safety_prices(self.status.get_start_price(),self.config.get_no_of_safety_orders(),self.config.get_safety_order_deviance()))
|
self.status.set_safety_price_table(self.calculate_safety_prices(self.status.get_start_price(),self.status.get_no_of_safety_orders(),self.config.get_safety_order_deviance()))
|
||||||
|
|
||||||
# Send the initial batch of safety orders
|
# Send the initial batch of safety orders
|
||||||
self.status.set_pause_reason("start_trader - sending safety orders")
|
self.status.set_pause_reason("start_trader - sending safety orders")
|
||||||
self.broker.logger.log_this("Sending safety orders...",2,self.config.get_pair())
|
self.broker.logger.log_this("Sending safety orders...",2,self.status.get_pair())
|
||||||
amount_of_so = self.config.get_concurrent_safety_orders() if not self.status.get_is_boosted() else self.config.get_boosted_concurrent_safety_orders()
|
amount_of_so = self.config.get_concurrent_safety_orders() if not self.status.get_is_boosted() else self.config.get_boosted_concurrent_safety_orders()
|
||||||
max_initial_safety_orders = min(amount_of_so,self.config.get_no_of_safety_orders()) #To never send more than the max amount of safety orders
|
max_initial_safety_orders = min(amount_of_so,self.status.get_no_of_safety_orders()) #To never send more than the max amount of safety orders
|
||||||
orders_placed = self.send_new_safety_order_batch(max_initial_safety_orders)
|
orders_placed = self.send_new_safety_order_batch(max_initial_safety_orders)
|
||||||
if orders_placed is not None:
|
if orders_placed is not None:
|
||||||
self.broker.logger.log_this(f"{orders_placed}/{max_initial_safety_orders} safety orders placed",2,self.config.get_pair())
|
self.broker.logger.log_this(f"{orders_placed}/{max_initial_safety_orders} safety orders placed",2,self.status.get_pair())
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Error sending safety orders. Cancelling take profit order and aborting",1,self.config.get_pair())
|
self.broker.logger.log_this("Error sending safety orders. Cancelling take profit order and aborting",1,self.status.get_pair())
|
||||||
self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.config.get_pair())
|
self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Send cleanup order (if cleanup)
|
# Send cleanup order (if cleanup)
|
||||||
|
|
@ -308,7 +308,7 @@ class trader:
|
||||||
self.status.set_next_so_price(0)
|
self.status.set_next_so_price(0)
|
||||||
self.status.set_is_paused(self.pause)
|
self.status.set_is_paused(self.pause)
|
||||||
self.status.set_is_short(self.config.get_is_short())
|
self.status.set_is_short(self.config.get_is_short())
|
||||||
self.status.set_no_of_safety_orders(self.config.get_no_of_safety_orders())
|
#self.status.set_no_of_safety_orders(self.config.get_no_of_safety_orders())
|
||||||
self.status.set_deal_uptime(int(time.time()) - self.status.get_deal_start_time())
|
self.status.set_deal_uptime(int(time.time()) - self.status.get_deal_start_time())
|
||||||
self.status.set_total_uptime(int(time.time()) - self.status.get_start_time())
|
self.status.set_total_uptime(int(time.time()) - self.status.get_start_time())
|
||||||
self.status.set_tp_mode(self.config.get_tp_mode())
|
self.status.set_tp_mode(self.config.get_tp_mode())
|
||||||
|
|
@ -316,7 +316,7 @@ class trader:
|
||||||
self.status.set_autoswitch(self.config.get_autoswitch())
|
self.status.set_autoswitch(self.config.get_autoswitch())
|
||||||
self.status.set_liquidate_after_switch(self.config.get_liquidate_after_switch())
|
self.status.set_liquidate_after_switch(self.config.get_liquidate_after_switch())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Can't update status dictionary. Exception: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Can't update status dictionary. Exception: {e}",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if write_to_disk:
|
if write_to_disk:
|
||||||
|
|
@ -400,7 +400,7 @@ class trader:
|
||||||
# try:
|
# try:
|
||||||
# fee_rate = self.market["maker"] if order["type"]=="limit" else self.market["taker"]
|
# fee_rate = self.market["maker"] if order["type"]=="limit" else self.market["taker"]
|
||||||
# except Exception as e:
|
# except Exception as e:
|
||||||
# self.broker.logger.log_this(f"Exception fetching market information: {e}. Using default fee rate of 0.1%",1,self.config.get_pair())
|
# self.broker.logger.log_this(f"Exception fetching market information: {e}. Using default fee rate of 0.1%",1,self.status.get_pair())
|
||||||
# fee_rate = 0.001
|
# fee_rate = 0.001
|
||||||
#
|
#
|
||||||
# if order["side"]=="buy":
|
# if order["side"]=="buy":
|
||||||
|
|
@ -434,22 +434,22 @@ class trader:
|
||||||
|
|
||||||
balance_to_clean = self.fetch_free_base()
|
balance_to_clean = self.fetch_free_base()
|
||||||
if balance_to_clean is None:
|
if balance_to_clean is None:
|
||||||
self.broker.logger.log_this("Can't fetch free base",1,self.config.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.config.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-minimum_cleanup_size >= min_base_size:
|
||||||
self.broker.logger.log_this(f"Balance to clean: {balance_to_clean-minimum_cleanup_size} {self.base}",2,self.config.get_pair())
|
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("Sending cleanup order...",2,self.config.get_pair())
|
self.broker.logger.log_this("Sending cleanup order...",2,self.status.get_pair())
|
||||||
cleanup_order = self.broker.new_limit_order(self.config.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-minimum_cleanup_size,"sell",self.status.get_take_profit_price())
|
||||||
if cleanup_order not in [None,self.broker.get_empty_order()]:
|
if cleanup_order not in [None,self.broker.get_empty_order()]:
|
||||||
self.broker.logger.log_this("Cleanup successful",2,self.config.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.config.get_pair())
|
self.broker.logger.log_this("Problems with the cleanup order",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
self.broker.logger.log_this("No cleanup needed",2,self.config.get_pair())
|
self.broker.logger.log_this("No cleanup needed",2,self.status.get_pair())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -463,16 +463,16 @@ class trader:
|
||||||
while amount_of_so>minimum_amount_of_safety_orders:
|
while amount_of_so>minimum_amount_of_safety_orders:
|
||||||
optimal_order_size = self.return_optimal_order_size(free_base,min_base_size,amount_of_so,self.config.get_safety_order_scale()) #safety_order_scale: safety order growth factor
|
optimal_order_size = self.return_optimal_order_size(free_base,min_base_size,amount_of_so,self.config.get_safety_order_scale()) #safety_order_scale: safety order growth factor
|
||||||
if optimal_order_size!=0:
|
if optimal_order_size!=0:
|
||||||
self.broker.logger.log_this(f"Optimal order size is {optimal_order_size}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Optimal order size is {optimal_order_size}",2,self.status.get_pair())
|
||||||
break
|
break
|
||||||
amount_of_so-=1
|
amount_of_so-=1
|
||||||
if optimal_order_size==0:
|
if optimal_order_size==0:
|
||||||
self.broker.logger.log_this("Not enough base to switch. Order size would be too small",1,self.config.get_pair())
|
self.broker.logger.log_this("Not enough base to switch. Order size would be too small",1,self.status.get_pair())
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.status.set_pause_reason("")
|
self.status.set_pause_reason("")
|
||||||
return None,None
|
return None,None
|
||||||
if optimal_order_size<min_base_size: #Sometimes amount_to_precision rounds to a value less than the minimum
|
if optimal_order_size<min_base_size: #Sometimes amount_to_precision rounds to a value less than the minimum
|
||||||
self.broker.logger.log_this("Optimal order size is smaller than the minimum order size",1,self.config.get_pair())
|
self.broker.logger.log_this("Optimal order size is smaller than the minimum order size",1,self.status.get_pair())
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.status.set_pause_reason("")
|
self.status.set_pause_reason("")
|
||||||
return None,None
|
return None,None
|
||||||
|
|
@ -488,11 +488,11 @@ class trader:
|
||||||
currency = self.base
|
currency = self.base
|
||||||
balance = self.broker.get_coins_balance()
|
balance = self.broker.get_coins_balance()
|
||||||
if balance==[]:
|
if balance==[]:
|
||||||
self.broker.logger.log_this("Can't fetch free base from the exchange",1,self.config.get_pair())
|
self.broker.logger.log_this("Can't fetch free base from the exchange",1,self.status.get_pair())
|
||||||
return None
|
return None
|
||||||
if currency in balance["free"]:
|
if currency in balance["free"]:
|
||||||
return float(balance["free"][currency])
|
return float(balance["free"][currency])
|
||||||
self.broker.logger.log_this("Currency not present in balance",1,self.config.get_pair())
|
self.broker.logger.log_this("Currency not present in balance",1,self.status.get_pair())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -508,7 +508,7 @@ class trader:
|
||||||
|
|
||||||
#Let's do some type checking first
|
#Let's do some type checking first
|
||||||
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, can't switch to short",1,self.config.get_pair())
|
self.broker.logger.log_this("Take profit order is None, can't switch to short",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Pauses trader
|
#Pauses trader
|
||||||
|
|
@ -516,47 +516,47 @@ class trader:
|
||||||
self.status.set_pause_reason("switch_to_short")
|
self.status.set_pause_reason("switch_to_short")
|
||||||
|
|
||||||
#Fetch the real amount of available base
|
#Fetch the real amount of available base
|
||||||
self.broker.logger.log_this(f"Fetching available {self.base}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Fetching available {self.base}",2,self.status.get_pair())
|
||||||
free_base = self.fetch_free_base()
|
free_base = self.fetch_free_base()
|
||||||
if free_base is None:
|
if free_base is None:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Fetch the minimal order size
|
#Fetch the minimal order size
|
||||||
min_base_size = self.broker.get_min_base_size(self.config.get_pair())
|
min_base_size = self.broker.get_min_base_size(self.status.get_pair())
|
||||||
if min_base_size is None:
|
if min_base_size is None:
|
||||||
self.broker.logger.log_this("Error. Can't fetch market info from the exchange",1,self.config.get_pair())
|
self.broker.logger.log_this("Error. Can't fetch market info from the exchange",1,self.status.get_pair())
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.status.set_pause_reason("")
|
self.status.set_pause_reason("")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Check if there is enough base
|
#Check if there is enough base
|
||||||
if self.broker.amount_to_precision(self.config.get_pair(),free_base+self.status.get_take_profit_order()["amount"])<=min_base_size:
|
if self.broker.amount_to_precision(self.status.get_pair(),free_base+self.status.get_take_profit_order()["amount"])<=min_base_size:
|
||||||
self.broker.logger.log_this("Error. Not enough base currency",1,self.config.get_pair())
|
self.broker.logger.log_this("Error. Not enough base currency",1,self.status.get_pair())
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.status.set_pause_reason("")
|
self.status.set_pause_reason("")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Calculate order size
|
#Calculate order size
|
||||||
self.broker.logger.log_this("Calculating optimal order size",2,self.config.get_pair())
|
self.broker.logger.log_this("Calculating optimal order size",2,self.status.get_pair())
|
||||||
optimal_order_size,amount_of_so = self.calculate_order_size(free_base+self.status.get_take_profit_order()["amount"],min_base_size,amount_of_so=self.config.get_max_short_safety_orders())
|
optimal_order_size,amount_of_so = self.calculate_order_size(free_base+self.status.get_take_profit_order()["amount"],min_base_size,amount_of_so=self.config.get_max_short_safety_orders())
|
||||||
if optimal_order_size is None or amount_of_so is None:
|
if optimal_order_size is None or amount_of_so is None:
|
||||||
return 1
|
return 1
|
||||||
self.broker.logger.log_this(f"New order size: {optimal_order_size}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"New order size: {optimal_order_size}",2,self.status.get_pair())
|
||||||
self.broker.logger.log_this(f"Amount of safety orders: {amount_of_so}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Amount of safety orders: {amount_of_so}",2,self.status.get_pair())
|
||||||
|
|
||||||
#Close old orders
|
#Close old orders
|
||||||
self.broker.logger.log_this("Switching trader mode to short",2,self.config.get_pair())
|
self.broker.logger.log_this("Switching trader mode to short",2,self.status.get_pair())
|
||||||
self.broker.logger.log_this("Closing orders...",2,self.config.get_pair())
|
self.broker.logger.log_this("Closing orders...",2,self.status.get_pair())
|
||||||
if self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.config.get_pair())==1:
|
if self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.status.get_pair())==1:
|
||||||
self.broker.logger.log_this("Can't cancel the take profit order. Can't switch mode",1,self.config.get_pair())
|
self.broker.logger.log_this("Can't cancel the take profit order. Can't switch mode",1,self.status.get_pair())
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.status.set_pause_reason("")
|
self.status.set_pause_reason("")
|
||||||
return 1
|
return 1
|
||||||
if self.status.get_take_profit_order()["id"]!="":
|
if self.status.get_take_profit_order()["id"]!="":
|
||||||
self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.config.get_pair())
|
self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.status.get_pair())
|
||||||
|
|
||||||
#Save the old take profit order info for later use
|
#Save the old take profit order info for later use
|
||||||
self.broker.logger.log_this("Saving state in status_dict",2,self.config.get_pair())
|
self.broker.logger.log_this("Saving state in status_dict",2,self.status.get_pair())
|
||||||
self.status.set_old_long({"tp_price": self.status.get_take_profit_order()["price"],
|
self.status.set_old_long({"tp_price": self.status.get_take_profit_order()["price"],
|
||||||
"tp_amount": self.status.get_take_profit_order()["amount"],
|
"tp_amount": self.status.get_take_profit_order()["amount"],
|
||||||
"quote_spent": self.status.get_quote_spent(),
|
"quote_spent": self.status.get_quote_spent(),
|
||||||
|
|
@ -567,22 +567,22 @@ class trader:
|
||||||
with open(f"status/{self.base}{self.quote}.oldlong","w") as s:
|
with open(f"status/{self.base}{self.quote}.oldlong","w") as s:
|
||||||
s.write(dumps(self.status.get_old_long(),indent=4))
|
s.write(dumps(self.status.get_old_long(),indent=4))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Exception while saving old_long file: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Exception while saving old_long file: {e}",1,self.status.get_pair())
|
||||||
|
|
||||||
#Modify config file accordingly
|
#Modify config file accordingly
|
||||||
self.broker.logger.log_this("Modifying config file and saving a backup",2,self.config.get_pair())
|
self.broker.logger.log_this("Modifying config file and saving a backup",2,self.status.get_pair())
|
||||||
try:
|
try:
|
||||||
self.config.save_to_file(f"configs/{self.base}{self.quote}.bak")
|
self.config.save_to_file(f"configs/{self.base}{self.quote}.bak")
|
||||||
self.config.set_is_short(True)
|
self.config.set_is_short(True)
|
||||||
self.config.save_to_file()
|
self.config.save_to_file()
|
||||||
self.broker.logger.log_this("Config file updated",2,self.config.get_pair())
|
self.broker.logger.log_this("Config file updated",2,self.status.get_pair())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Error. Can't write the config file. Exception: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Error. Can't write the config file. Exception: {e}",1,self.status.get_pair())
|
||||||
#self.pause = False
|
#self.pause = False
|
||||||
return 1
|
return 1
|
||||||
self.status.set_stop_when_profit(False)
|
self.status.set_stop_when_profit(False)
|
||||||
#self.config.set_is_short(True)
|
#self.config.set_is_short(True)
|
||||||
self.broker.logger.log_this("Done configuring. Starting trader...",2,self.config.get_pair())
|
self.broker.logger.log_this("Done configuring. Starting trader...",2,self.status.get_pair())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -593,35 +593,35 @@ class trader:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if not self.config.get_is_short():
|
if not self.config.get_is_short():
|
||||||
self.broker.logger.log_this("Trader already in long mode, nothing to do",1,self.config.get_pair())
|
self.broker.logger.log_this("Trader already in long mode, nothing to do",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
self.broker.logger.log_this("Attempting to switch to long trader",0,self.config.get_pair())
|
self.broker.logger.log_this("Attempting to switch to long trader",0,self.status.get_pair())
|
||||||
|
|
||||||
#Check old_long data
|
#Check old_long data
|
||||||
if not ignore_old_long and self.status.get_old_long()=={}:
|
if not ignore_old_long and self.status.get_old_long()=={}:
|
||||||
self.broker.logger.log_this("Can't find old long info on status_dict, searching for oldlong file",1,self.config.get_pair())
|
self.broker.logger.log_this("Can't find old long info on status_dict, searching for oldlong file",1,self.status.get_pair())
|
||||||
try:
|
try:
|
||||||
with open(f"status/{self.base}{self.quote}.oldlong") as f:
|
with open(f"status/{self.base}{self.quote}.oldlong") as f:
|
||||||
self.status.set_old_long(load(f))
|
self.status.set_old_long(load(f))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
#self.write_to_log(time.strftime(f"[%Y/%m/%d %H:%M:%S] | {self.config.get_pair()} | Can't find old long file"))
|
#self.write_to_log(time.strftime(f"[%Y/%m/%d %H:%M:%S] | {self.status.get_pair()} | Can't find old long file"))
|
||||||
self.broker.logger.log_this(f"Can't file oldlong file. Exception: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Can't file oldlong file. Exception: {e}",1,self.status.get_pair())
|
||||||
self.quit = True
|
self.quit = True
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Cancel open orders
|
#Cancel open orders
|
||||||
try:
|
try:
|
||||||
for order in self.status.get_safety_orders():
|
for order in self.status.get_safety_orders():
|
||||||
self.broker.cancel_order(order["id"],self.config.get_pair())
|
self.broker.cancel_order(order["id"],self.status.get_pair())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Error in cancel_order while cancelling safety order. Exception: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Error in cancel_order while cancelling safety order. Exception: {e}",1,self.status.get_pair())
|
||||||
try:
|
try:
|
||||||
if self.status.get_take_profit_order() is not None:
|
if self.status.get_take_profit_order() is not None:
|
||||||
self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.config.get_pair())
|
self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.status.get_pair())
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Safety order is None",1,self.config.get_pair())
|
self.broker.logger.log_this("Safety order is None",1,self.status.get_pair())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Error in cancel_order while cancelling take profit order. Exception: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Error in cancel_order while cancelling take profit order. Exception: {e}",1,self.status.get_pair())
|
||||||
|
|
||||||
#Sell all base currency
|
#Sell all base currency
|
||||||
self.liquidate_base(ignore_profits=ignore_old_long, already_received_quote=already_received_quote)
|
self.liquidate_base(ignore_profits=ignore_old_long, already_received_quote=already_received_quote)
|
||||||
|
|
@ -639,13 +639,13 @@ class trader:
|
||||||
if self.config.load_from_file()==1:
|
if self.config.load_from_file()==1:
|
||||||
self.config.reset_to_default()
|
self.config.reset_to_default()
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Config/backup file does not exist",1,self.config.get_pair())
|
self.broker.logger.log_this("Config/backup file does not exist",1,self.status.get_pair())
|
||||||
self.config.reset_to_default()
|
self.config.reset_to_default()
|
||||||
self.config.save_to_file()
|
self.config.save_to_file()
|
||||||
|
|
||||||
#Remove old_long file (if it exists)
|
#Remove old_long file (if it exists)
|
||||||
if path.isfile(f"status/{self.base}{self.quote}.oldlong"):
|
if path.isfile(f"status/{self.base}{self.quote}.oldlong"):
|
||||||
self.broker.logger.log_this("Removing old_long file...",2,self.config.get_pair())
|
self.broker.logger.log_this("Removing old_long file...",2,self.status.get_pair())
|
||||||
remove(f"status/{self.base}{self.quote}.oldlong")
|
remove(f"status/{self.base}{self.quote}.oldlong")
|
||||||
|
|
||||||
#Set up a few variables
|
#Set up a few variables
|
||||||
|
|
@ -669,20 +669,20 @@ class trader:
|
||||||
#Find out the amount of free base
|
#Find out the amount of free base
|
||||||
free_base = self.fetch_free_base()
|
free_base = self.fetch_free_base()
|
||||||
if free_base is None:
|
if free_base is None:
|
||||||
self.broker.logger.log_this("Can't fetch free base",1,self.config.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.config.get_pair(),free_base,"sell")
|
order = self.broker.new_market_order(self.status.get_pair(),free_base,"sell")
|
||||||
tries = self.broker.get_retries()
|
tries = self.broker.get_retries()
|
||||||
while True:
|
while True:
|
||||||
time.sleep(self.broker.get_wait_time())
|
time.sleep(self.broker.get_wait_time())
|
||||||
market_tp_order = self.broker.get_order(order["id"],self.config.get_pair())
|
market_tp_order = self.broker.get_order(order["id"],self.status.get_pair())
|
||||||
if market_tp_order["status"]=="closed":
|
if market_tp_order["status"]=="closed":
|
||||||
_, fees_paid = self.parse_fees(market_tp_order)
|
_, fees_paid = self.parse_fees(market_tp_order)
|
||||||
break
|
break
|
||||||
tries-=1
|
tries-=1
|
||||||
if tries==0:
|
if tries==0:
|
||||||
self.broker.logger.log_this("Liquidation order not filling. Skipping base liquidation",1,self.config.get_pair())
|
self.broker.logger.log_this("Liquidation order not filling. Skipping base liquidation",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#calculate profits
|
#calculate profits
|
||||||
|
|
@ -691,9 +691,9 @@ class trader:
|
||||||
|
|
||||||
#Add profits to file and send telegram notifying profits
|
#Add profits to file and send telegram notifying profits
|
||||||
self.profit_to_db(profit,market_tp_order["id"],self.broker.get_write_order_history())
|
self.profit_to_db(profit,market_tp_order["id"],self.broker.get_write_order_history())
|
||||||
self.broker.logger.log_this(f"Switch successful. Profit: {round(profit,2)} {self.quote}",0,self.config.get_pair())
|
self.broker.logger.log_this(f"Switch successful. Profit: {round(profit,2)} {self.quote}",0,self.status.get_pair())
|
||||||
self.broker.logger.log_this(f"Sell price: {market_tp_order['price']} {self.quote}",0,self.config.get_pair())
|
self.broker.logger.log_this(f"Sell price: {market_tp_order['price']} {self.quote}",0,self.status.get_pair())
|
||||||
self.broker.logger.log_this(f"Order ID: {market_tp_order['id']}",0,self.config.get_pair())
|
self.broker.logger.log_this(f"Order ID: {market_tp_order['id']}",0,self.status.get_pair())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -713,8 +713,8 @@ class trader:
|
||||||
|
|
||||||
#Let's do some type checking first
|
#Let's do some type checking first
|
||||||
if self.status.get_take_profit_order() is None:
|
if self.status.get_take_profit_order() is None:
|
||||||
self.status.set_pause_reason(time.strftime(f"[%Y/%m/%d %H:%M:%S] | {self.config.get_pair()} | TP order is None"))
|
self.status.set_pause_reason(time.strftime(f"[%Y/%m/%d %H:%M:%S] | {self.status.get_pair()} | TP order is None"))
|
||||||
self.broker.logger.log_this("Error. Take profit order is None, trader will be restarted",0,self.config.get_pair())
|
self.broker.logger.log_this("Error. Take profit order is None, trader will be restarted",0,self.status.get_pair())
|
||||||
self.status.save_to_file(is_backup=True)
|
self.status.save_to_file(is_backup=True)
|
||||||
self.restart = True
|
self.restart = True
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -725,15 +725,15 @@ class trader:
|
||||||
|
|
||||||
#Cancel all the safety orders ASAP
|
#Cancel all the safety orders ASAP
|
||||||
for order in self.status.get_safety_orders():
|
for order in self.status.get_safety_orders():
|
||||||
self.broker.cancel_order(order["id"],self.config.get_pair())
|
self.broker.cancel_order(order["id"],self.status.get_pair())
|
||||||
#Check if some safety orders were filled
|
#Check if some safety orders were filled
|
||||||
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.config.get_pair())
|
closed_order = self.broker.get_order(order["id"],self.status.get_pair())
|
||||||
if closed_order["filled"]==0:
|
if closed_order["filled"]==0:
|
||||||
#If this order wasn't filled, it is safe to assume that no order coming after this one was.
|
#If this order wasn't filled, it is safe to assume that no order coming after this one was.
|
||||||
break
|
break
|
||||||
#Sum the filled amounts
|
#Sum the filled amounts
|
||||||
self.broker.logger.log_this(f"Old safety order is partially filled, ID: {closed_order['id']}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Old safety order is partially filled, ID: {closed_order['id']}",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
|
||||||
|
|
@ -762,14 +762,14 @@ class trader:
|
||||||
if profit>0: #Negative profits are not saved because the cleanup takes care of the unsold base currency (the notorious small change issue that plagues some exchanges)
|
if profit>0: #Negative profits are not saved because the cleanup takes care of the unsold base currency (the notorious small change issue that plagues some exchanges)
|
||||||
self.profit_to_db(profit,filled_order["id"],self.broker.get_write_order_history())
|
self.profit_to_db(profit,filled_order["id"],self.broker.get_write_order_history())
|
||||||
else: #For logging purposes
|
else: #For logging purposes
|
||||||
self.broker.logger.log_this(f"NEGATIVE PROFIT - Total amount of base: {self.status.get_base_bought()}, base in the order: {filled_order['amount']}, base filled: {filled_order['filled']}, base 'profit': {base_profit}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"NEGATIVE PROFIT - Total amount of base: {self.status.get_base_bought()}, base in the order: {filled_order['amount']}, base filled: {filled_order['filled']}, base 'profit': {base_profit}",1,self.status.get_pair())
|
||||||
self.telegram_bot_sendprofit(profit,filled_order,base_profit=base_profit)
|
self.telegram_bot_sendprofit(profit,filled_order,base_profit=base_profit)
|
||||||
|
|
||||||
# Print profit message on screen
|
# Print profit message on screen
|
||||||
extra = ' and {:.4f}'.format(base_profit) + f" {self.base}" if base_profit>0 else ""
|
extra = ' and {:.4f}'.format(base_profit) + f" {self.base}" if base_profit>0 else ""
|
||||||
self.broker.logger.log_this(f"Trader closed a deal. Profit: {'{:.4f}'.format(profit)} {self.quote}{extra}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Trader closed a deal. Profit: {'{:.4f}'.format(profit)} {self.quote}{extra}",2,self.status.get_pair())
|
||||||
self.broker.logger.log_this(f"Fill price: {filled_order['price']} {self.quote}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Fill price: {filled_order['price']} {self.quote}",2,self.status.get_pair())
|
||||||
self.broker.logger.log_this(f"Safety orders triggered: {self.status.get_safety_orders_filled()}",2,self.config.get_pair())
|
self.broker.logger.log_this(f"Safety orders triggered: {self.status.get_safety_orders_filled()}",2,self.status.get_pair())
|
||||||
|
|
||||||
self.status.set_pause_reason("take_profit_routine - check time limit")
|
self.status.set_pause_reason("take_profit_routine - check time limit")
|
||||||
#Checks if there is a time limit for the trader
|
#Checks if there is a time limit for the trader
|
||||||
|
|
@ -778,7 +778,7 @@ class trader:
|
||||||
|
|
||||||
self.status.set_pause_reason("take_profit_routine - if stop_when_profit")
|
self.status.set_pause_reason("take_profit_routine - if stop_when_profit")
|
||||||
if self.status.get_stop_when_profit(): #Signal to stop when trade is closed
|
if self.status.get_stop_when_profit(): #Signal to stop when trade is closed
|
||||||
self.broker.logger.log_this("Pair shutting down. So long and thanks for all the fish",0,self.config.get_pair())
|
self.broker.logger.log_this("Pair shutting down. So long and thanks for all the fish",0,self.status.get_pair())
|
||||||
self.quit = True
|
self.quit = True
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
@ -787,18 +787,18 @@ class trader:
|
||||||
|
|
||||||
self.status.set_pause_reason("Checking slippage")
|
self.status.set_pause_reason("Checking slippage")
|
||||||
if self.config.get_check_slippage():
|
if self.config.get_check_slippage():
|
||||||
self.broker.logger.log_this("Checking slippage...",2,self.config.get_pair())
|
self.broker.logger.log_this("Checking slippage...",2,self.status.get_pair())
|
||||||
price_to_compare = self.broker.get_top_bid_price(self.config.get_pair()) if self.config.get_is_short() else self.broker.get_top_ask_price(self.config.get_pair())
|
price_to_compare = self.broker.get_top_bid_price(self.status.get_pair()) if self.config.get_is_short() else self.broker.get_top_ask_price(self.status.get_pair())
|
||||||
if abs(filled_order["price"]-price_to_compare)/filled_order["price"]>self.broker.get_slippage_default_threshold():
|
if abs(filled_order["price"]-price_to_compare)/filled_order["price"]>self.broker.get_slippage_default_threshold():
|
||||||
self.broker.logger.log_this(f"Slippage threshold exceeded, waiting for cooldown and restarting trader",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Slippage threshold exceeded, waiting for cooldown and restarting trader",1,self.status.get_pair())
|
||||||
time.sleep(self.broker.get_wait_time()*self.broker.get_cooldown_multiplier())
|
time.sleep(self.broker.get_wait_time()*self.broker.get_cooldown_multiplier())
|
||||||
#The trader is restarted by the instance instead of by itself to allow a couple of more seconds for the price to return to normal.
|
#The trader is restarted by the instance instead of by itself to allow a couple of more seconds for the price to return to normal.
|
||||||
#This could also be the default behavior.
|
#This could also be the default behavior.
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.restart = True
|
self.restart = True
|
||||||
return 1
|
return 1
|
||||||
elif self.check_orderbook_depth(self.broker.get_slippage_default_threshold(),self.config.get_order_size(),filled_order["price"]):
|
elif self.check_orderbook_depth(self.broker.get_slippage_default_threshold(),self.status.get_order_size(),filled_order["price"]):
|
||||||
self.broker.logger.log_this(f"Orderbook depth not sufficient, waiting for cooldown and restarting trader",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Orderbook depth not sufficient, waiting for cooldown and restarting trader",1,self.status.get_pair())
|
||||||
time.sleep(self.broker.get_wait_time()*self.broker.get_cooldown_multiplier())
|
time.sleep(self.broker.get_wait_time()*self.broker.get_cooldown_multiplier())
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.restart = True
|
self.restart = True
|
||||||
|
|
@ -813,7 +813,7 @@ class trader:
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.restart = True
|
self.restart = True
|
||||||
self.status.save_to_file(is_backup=True)
|
self.status.save_to_file(is_backup=True)
|
||||||
self.broker.logger.log_this(self.trader_restart_errors[restart_trader],1,self.config.get_pair())
|
self.broker.logger.log_this(self.trader_restart_errors[restart_trader],1,self.status.get_pair())
|
||||||
return restart_trader
|
return restart_trader
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -827,22 +827,22 @@ class trader:
|
||||||
if amount<1:
|
if amount<1:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
orders_to_place = min(self.config.get_no_of_safety_orders()-self.status.get_so_amount(),amount)
|
orders_to_place = min(self.status.get_no_of_safety_orders()-self.status.get_so_amount(),amount)
|
||||||
if orders_to_place<1:
|
if orders_to_place<1:
|
||||||
return 0
|
return 0
|
||||||
orders_placed = 0
|
orders_placed = 0
|
||||||
for i in range(orders_to_place):
|
for i in range(orders_to_place):
|
||||||
self.broker.logger.log_this(f"Sending a new safety order ({i+1}/{orders_to_place})",2,self.config.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.config.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])
|
||||||
else:
|
else:
|
||||||
new_order = self.broker.new_limit_order(self.config.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])
|
||||||
if new_order==1:
|
if new_order==1:
|
||||||
self.broker.logger.log_this("Not enough balance to send a new safety order",1,self.config.get_pair())
|
self.broker.logger.log_this("Not enough balance to send a new safety order",1,self.status.get_pair())
|
||||||
return orders_placed
|
return orders_placed
|
||||||
elif new_order is None:
|
elif new_order is None:
|
||||||
self.broker.logger.log_this("new_limit_order returned None",1,self.config.get_pair())
|
self.broker.logger.log_this("new_limit_order returned None",1,self.status.get_pair())
|
||||||
return orders_placed
|
return orders_placed
|
||||||
orders_placed+=1
|
orders_placed+=1
|
||||||
self.status.add_safety_order(new_order)
|
self.status.add_safety_order(new_order)
|
||||||
|
|
@ -859,7 +859,7 @@ class trader:
|
||||||
|
|
||||||
#Check if current TP order is valid
|
#Check if current TP 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, can't send a new safety order",1,self.config.get_pair())
|
self.broker.logger.log_this("Take profit order is None, can't send a new safety order",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Pause the trader
|
#Pause the trader
|
||||||
|
|
@ -889,16 +889,16 @@ class trader:
|
||||||
self.status.set_safety_orders(new_order_list)
|
self.status.set_safety_orders(new_order_list)
|
||||||
|
|
||||||
#Cancel old TP order
|
#Cancel old TP order
|
||||||
if self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.config.get_pair())==1:
|
if self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.status.get_pair())==1:
|
||||||
error_string = f"{self.config.get_pair()} | {self.status.get_take_profit_order()['id']} | Old TP order probably filled. Can't cancel. This trader should be restarted"
|
error_string = f"{self.status.get_pair()} | {self.status.get_take_profit_order()['id']} | Old TP order probably filled. Can't cancel. This trader should be restarted"
|
||||||
self.broker.logger.log_this(f"Old take profit order is probably filled, can't cancel. This trader should be restarted. Order ID: {self.status.get_take_profit_order()['id']}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Old take profit order is probably filled, can't cancel. This trader should be restarted. Order ID: {self.status.get_take_profit_order()['id']}",1,self.status.get_pair())
|
||||||
self.status.set_pause_reason(error_string)
|
self.status.set_pause_reason(error_string)
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
#Check if old TP order was partially filled
|
#Check if old TP order was partially filled
|
||||||
old_tp_order = self.broker.get_order(self.status.get_take_profit_order()["id"],self.config.get_pair())
|
old_tp_order = self.broker.get_order(self.status.get_take_profit_order()["id"],self.status.get_pair())
|
||||||
if old_tp_order["filled"]>0:
|
if old_tp_order["filled"]>0:
|
||||||
self.broker.logger.log_this(f"Old take profit order is partially filled, id {old_tp_order['id']}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Old take profit order is partially filled, id {old_tp_order['id']}",1,self.status.get_pair())
|
||||||
if self.broker.get_follow_order_history():
|
if self.broker.get_follow_order_history():
|
||||||
self.status.update_deal_order_history(old_tp_order)
|
self.status.update_deal_order_history(old_tp_order)
|
||||||
#self.status.set_base_bought(old_tp_order["remaining"])
|
#self.status.set_base_bought(old_tp_order["remaining"])
|
||||||
|
|
@ -922,12 +922,12 @@ class trader:
|
||||||
if len(self.status.get_safety_orders())<max_orders:
|
if len(self.status.get_safety_orders())<max_orders:
|
||||||
self.send_new_safety_order_batch(len(filled_safety_orders))
|
self.send_new_safety_order_batch(len(filled_safety_orders))
|
||||||
#Cooldown
|
#Cooldown
|
||||||
time.sleep(self.broker.get_wait_time())
|
time.sleep(self.broker.get_wait_time())
|
||||||
|
|
||||||
#Send new TP order
|
#Send new TP order
|
||||||
if self.send_new_tp_order()==1:
|
if self.send_new_tp_order()==1:
|
||||||
error_string = "Problems sending the new take profit order"
|
error_string = "Problems sending the new take profit order"
|
||||||
self.broker.logger.log_this("Problems sending the new take profit order",1,self.config.get_pair())
|
self.broker.logger.log_this("Problems sending the new take profit order",1,self.status.get_pair())
|
||||||
self.status.set_pause_reason(error_string)
|
self.status.set_pause_reason(error_string)
|
||||||
return 4
|
return 4
|
||||||
|
|
||||||
|
|
@ -959,7 +959,7 @@ class trader:
|
||||||
self.warnings["speol_notified"] = True
|
self.warnings["speol_notified"] = True
|
||||||
if not self.config.get_autoswitch():
|
if not self.config.get_autoswitch():
|
||||||
message = f"{self.base}@{self.status.get_price()} ({str(self.broker.exchange)}), exceeds old long price of {self.status.get_old_long()['tp_price']}"
|
message = f"{self.base}@{self.status.get_price()} ({str(self.broker.exchange)}), exceeds old long price of {self.status.get_old_long()['tp_price']}"
|
||||||
self.broker.logger.log_this(message,0,self.config.get_pair())
|
self.broker.logger.log_this(message,0,self.status.get_pair())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -980,9 +980,9 @@ class trader:
|
||||||
if self.config.get_is_short(): #Do not check for slippage in short traders (Pending to be implemented)
|
if self.config.get_is_short(): #Do not check for slippage in short traders (Pending to be implemented)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
order_book = self.broker.get_order_book(self.config.get_pair(),no_retries=True)
|
order_book = self.broker.get_order_book(self.status.get_pair(),no_retries=True)
|
||||||
if order_book=={}:
|
if order_book=={}:
|
||||||
self.broker.logger.log_this("Can't fetch orderbook",1,self.config.get_pair())
|
self.broker.logger.log_this("Can't fetch orderbook",1,self.status.get_pair())
|
||||||
return False
|
return False
|
||||||
suma = 0
|
suma = 0
|
||||||
try:
|
try:
|
||||||
|
|
@ -1002,7 +1002,7 @@ class trader:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Exception in check_orderbook_depth: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Exception in check_orderbook_depth: {e}",1,self.status.get_pair())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1037,53 +1037,53 @@ class trader:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Extract ids from order list
|
#Extract ids from order list
|
||||||
open_orders_ids = [order["id"] for order in open_orders if order["symbol"]==self.config.get_pair()]
|
open_orders_ids = [order["id"] for order in open_orders if order["symbol"]==self.status.get_pair()]
|
||||||
|
|
||||||
#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.config.get_pair())
|
self.broker.logger.log_this("Take profit order is None",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
if self.status.get_take_profit_order()["id"]=="":
|
if self.status.get_take_profit_order()["id"]=="":
|
||||||
self.broker.logger.log_this(f"Take profit order missing. Stopping trader. No order ID was provided.",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Take profit order missing. Stopping trader. No order ID was provided.",1,self.status.get_pair())
|
||||||
#Cancelling safety orders
|
#Cancelling safety orders
|
||||||
for item in self.status.get_safety_orders():
|
for item in self.status.get_safety_orders():
|
||||||
self.broker.cancel_order(item["id"],self.config.get_pair())
|
self.broker.cancel_order(item["id"],self.status.get_pair())
|
||||||
if self.config.get_attempt_restart():
|
if self.config.get_attempt_restart():
|
||||||
self.status.save_to_file(is_backup=True)
|
self.status.save_to_file(is_backup=True)
|
||||||
self.restart = True
|
self.restart = True
|
||||||
self.broker.logger.log_this("Raising restart flag: take profit order missing, trader will be restarted",0,self.config.get_pair())
|
self.broker.logger.log_this("Raising restart flag: take profit order missing, trader will be restarted",0,self.status.get_pair())
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Take profit order missing. Trader restart disabled.",2,self.config.get_pair())
|
self.broker.logger.log_this("Take profit order missing. Trader restart disabled.",2,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#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:
|
||||||
tp_status = self.broker.get_order(self.status.get_take_profit_order()["id"],self.config.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":
|
||||||
if tp_status["filled"]>0:
|
if tp_status["filled"]>0:
|
||||||
return self.take_profit_routine(tp_status)
|
return self.take_profit_routine(tp_status)
|
||||||
self.broker.logger.log_this(f"Take profit order closed but not filled, 0 filled. Stopping trader. Order ID: {self.status.get_take_profit_order()['id']}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Take profit order closed but not filled, 0 filled. Stopping trader. Order ID: {self.status.get_take_profit_order()['id']}",1,self.status.get_pair())
|
||||||
#Cancelling safety orders
|
#Cancelling safety orders
|
||||||
for item in self.status.get_safety_orders():
|
for item in self.status.get_safety_orders():
|
||||||
self.broker.cancel_order(item["id"],self.config.get_pair())
|
self.broker.cancel_order(item["id"],self.status.get_pair())
|
||||||
if self.config.get_attempt_restart():
|
if self.config.get_attempt_restart():
|
||||||
self.status.save_to_file(is_backup=True)
|
self.status.save_to_file(is_backup=True)
|
||||||
self.restart = True
|
self.restart = True
|
||||||
self.broker.logger.log_this("Take profit order closed but not filled, trader will be restarted.",0,self.config.get_pair())
|
self.broker.logger.log_this("Take profit order closed but not filled, trader will be restarted.",0,self.status.get_pair())
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Take profit order closed but not filled, trader restart disabled.",1,self.config.get_pair())
|
self.broker.logger.log_this("Take profit order closed but not filled, trader restart disabled.",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
elif tp_status["status"]=="canceled":
|
elif tp_status["status"]=="canceled":
|
||||||
#TODO: Here, if the safety order is still open, we could resend the tp order.
|
#TODO: Here, if the safety order is still open, we could resend the tp order.
|
||||||
if self.config.get_attempt_restart():
|
if self.config.get_attempt_restart():
|
||||||
self.broker.logger.log_this("Take profit order canceled. Restarting the trader.",1,self.config.get_pair())
|
self.broker.logger.log_this("Take profit order canceled. Restarting the trader.",1,self.status.get_pair())
|
||||||
self.status.save_to_file(is_backup=True)
|
self.status.save_to_file(is_backup=True)
|
||||||
self.restart = True
|
self.restart = True
|
||||||
else:
|
else:
|
||||||
self.broker.logger.log_this("Take profit order canceled. Trader restart disabled.",1,self.config.get_pair())
|
self.broker.logger.log_this("Take profit order canceled. Trader restart disabled.",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
elif tp_status["status"]=="":
|
elif tp_status["status"]=="":
|
||||||
self.broker.logger.log_this(f"Take profit order search returned empty order. Order ID: {tp_status['id']}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Take profit order search returned empty order. Order ID: {tp_status['id']}",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Check if any safety order is filled
|
# Check if any safety order is filled
|
||||||
|
|
@ -1093,26 +1093,26 @@ class trader:
|
||||||
filled_ids.append(order["id"])
|
filled_ids.append(order["id"])
|
||||||
|
|
||||||
if filled_ids!=[]:
|
if filled_ids!=[]:
|
||||||
closed_orders = self.broker.get_closed_orders(self.config.get_pair())
|
closed_orders = self.broker.get_closed_orders(self.status.get_pair())
|
||||||
filled_orders = [item for item in closed_orders if item["id"] in filled_ids and item["status"]=="closed"] #maybe item["status"] in ["closed", "canceled", ""]?
|
filled_orders = [item for item in closed_orders if item["id"] in filled_ids and item["status"]=="closed"] #maybe item["status"] in ["closed", "canceled", ""]?
|
||||||
self.status.set_safety_orders_filled(self.status.get_safety_orders_filled()+len(filled_orders))
|
self.status.set_safety_orders_filled(self.status.get_safety_orders_filled()+len(filled_orders))
|
||||||
renew_outcome = self.renew_tp_and_so_routine(filled_orders)
|
renew_outcome = self.renew_tp_and_so_routine(filled_orders)
|
||||||
#0 OK, 1 take profit order is None, 2 not enough funds, 3 can't cancel TP (filled?), 4 can't send new TP
|
#0 OK, 1 take profit order is None, 2 not enough funds, 3 can't cancel TP (filled?), 4 can't send new TP
|
||||||
if renew_outcome==1:
|
if renew_outcome==1:
|
||||||
self.broker.logger.log_this(f"Error in trader: TP order is None. Restart will be attempted. renew_tp_and_so_routine returned 1",0,self.config.get_pair())
|
self.broker.logger.log_this(f"Error in trader: TP order is None. Restart will be attempted. renew_tp_and_so_routine returned 1",0,self.status.get_pair())
|
||||||
if self.config.get_attempt_restart():
|
if self.config.get_attempt_restart():
|
||||||
self.status.save_to_file(is_backup=True)
|
self.status.save_to_file(is_backup=True)
|
||||||
self.restart = True
|
self.restart = True
|
||||||
return 1
|
return 1
|
||||||
elif renew_outcome==2:
|
elif renew_outcome==2:
|
||||||
#Not enough funds?
|
#Not enough funds?
|
||||||
self.broker.logger.log_this(f"Can't send new safety order. Not enough funds? renew_tp_and_so_routine returned 2",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Can't send new safety order. Not enough funds? renew_tp_and_so_routine returned 2",1,self.status.get_pair())
|
||||||
#Set no_of_safety_orders to the same amount of orders open so the script does not try to send new safety orders
|
#Set no_of_safety_orders to the same amount of orders open so the script does not try to send new safety orders
|
||||||
#This can be improved
|
#This can be improved
|
||||||
self.config.set_no_of_safety_orders(self.status.get_so_amount())
|
self.status.set_no_of_safety_orders(self.status.get_so_amount())
|
||||||
return 1
|
return 1
|
||||||
elif renew_outcome==3:
|
elif renew_outcome==3:
|
||||||
self.broker.logger.log_this(f"Can't cancel old take profit order. renew_tp_and_so_routine returned 3",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Can't cancel old take profit order. renew_tp_and_so_routine returned 3",1,self.status.get_pair())
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.status.set_pause_reason("")
|
self.status.set_pause_reason("")
|
||||||
if self.config.get_attempt_restart():
|
if self.config.get_attempt_restart():
|
||||||
|
|
@ -1120,7 +1120,7 @@ class trader:
|
||||||
self.restart = True
|
self.restart = True
|
||||||
return 1
|
return 1
|
||||||
elif renew_outcome==4:
|
elif renew_outcome==4:
|
||||||
self.broker.logger.log_this(f"Error in trader: Can't send new take profit order. Restart will be attempted. renew_tp_and_so_routine returned 4",0,self.config.get_pair())
|
self.broker.logger.log_this(f"Error in trader: Can't send new take profit order. Restart will be attempted. renew_tp_and_so_routine returned 4",0,self.status.get_pair())
|
||||||
if self.config.get_attempt_restart():
|
if self.config.get_attempt_restart():
|
||||||
self.status.save_to_file(is_backup=True)
|
self.status.save_to_file(is_backup=True)
|
||||||
self.restart = True
|
self.restart = True
|
||||||
|
|
@ -1128,7 +1128,7 @@ class trader:
|
||||||
|
|
||||||
#Check for autoswitch (long->short)
|
#Check for autoswitch (long->short)
|
||||||
#Commented out because i'm not sure where this should go
|
#Commented out because i'm not sure where this should go
|
||||||
#if not self.config.get_is_short() and self.status.get_so_amount()==self.config.get_no_of_safety_orders() and self.config.get_autoswitch():
|
#if not self.config.get_is_short() and self.status.get_so_amount()==self.status.get_no_of_safety_orders() and self.config.get_autoswitch():
|
||||||
# self.switch_to_short()
|
# self.switch_to_short()
|
||||||
# self.status.save_to_file(is_backup=True)
|
# self.status.save_to_file(is_backup=True)
|
||||||
# self.restart = True
|
# self.restart = True
|
||||||
|
|
@ -1169,7 +1169,7 @@ class trader:
|
||||||
if self.config.get_is_short() or self.config.get_tp_mode()==0: #Fixed take profit percentage
|
if self.config.get_is_short() or self.config.get_tp_mode()==0: #Fixed take profit percentage
|
||||||
tp_level = self.config.get_tp_level()
|
tp_level = self.config.get_tp_level()
|
||||||
elif self.config.get_tp_mode()==1: #Variable percentage
|
elif self.config.get_tp_mode()==1: #Variable percentage
|
||||||
limit = self.config.get_no_of_safety_orders()/3
|
limit = self.status.get_no_of_safety_orders()/3
|
||||||
if order_index<=1:
|
if order_index<=1:
|
||||||
tp_level = self.config.get_tp_level()+0.005
|
tp_level = self.config.get_tp_level()+0.005
|
||||||
elif order_index<=limit:
|
elif order_index<=limit:
|
||||||
|
|
@ -1185,7 +1185,7 @@ class trader:
|
||||||
tp_level = self.config.get_tp_table()[-1]
|
tp_level = self.config.get_tp_table()[-1]
|
||||||
tp_level = self.config.get_tp_level()
|
tp_level = self.config.get_tp_level()
|
||||||
elif self.config.get_tp_mode()==3: #Linear percentage table
|
elif self.config.get_tp_mode()==3: #Linear percentage table
|
||||||
profit_table = self.linear_space(self.config.get_tp_level()+0.005,self.config.get_tp_level()-0.005,self.config.get_no_of_safety_orders())
|
profit_table = self.linear_space(self.config.get_tp_level()+0.005,self.config.get_tp_level()-0.005,self.status.get_no_of_safety_orders())
|
||||||
tp_level = profit_table[-1]
|
tp_level = profit_table[-1]
|
||||||
if order_index<len(profit_table): #If more safety orders were added, instead of recalculating the whole table
|
if order_index<len(profit_table): #If more safety orders were added, instead of recalculating the whole table
|
||||||
tp_level = profit_table[order_index] #it just returns the last value. Otherwise, the percentage gets very small.
|
tp_level = profit_table[order_index] #it just returns the last value. Otherwise, the percentage gets very small.
|
||||||
|
|
@ -1211,7 +1211,7 @@ class trader:
|
||||||
time.sleep(self.broker.get_wait_time())
|
time.sleep(self.broker.get_wait_time())
|
||||||
new_balance = self.broker.get_coins_balance()
|
new_balance = self.broker.get_coins_balance()
|
||||||
if bool(new_balance):
|
if bool(new_balance):
|
||||||
self.broker.logger.log_this(f"Adjusting base amount to {new_balance['free'][self.base]}, total balance: {new_balance['total'][self.base]}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Adjusting base amount to {new_balance['free'][self.base]}, total balance: {new_balance['total'][self.base]}",1,self.status.get_pair())
|
||||||
return new_balance["free"][self.base]
|
return new_balance["free"][self.base]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -1223,14 +1223,14 @@ class trader:
|
||||||
tries = self.broker.get_retries()
|
tries = self.broker.get_retries()
|
||||||
while tries>0:
|
while tries>0:
|
||||||
if self.status.get_base_bought()==0:
|
if self.status.get_base_bought()==0:
|
||||||
self.broker.logger.log_this("Amount of base equals 0, can't send take profit order",1,self.config.get_pair())
|
self.broker.logger.log_this("Amount of base equals 0, can't send take profit order",1,self.status.get_pair())
|
||||||
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.config.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()))
|
||||||
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.config.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()))
|
||||||
if self.status.get_take_profit_order()==1: #This means that there was a miscalculation of base currency amount, let's correct it.
|
if self.status.get_take_profit_order()==1: #This means that there was a miscalculation of base currency amount, let's correct it.
|
||||||
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
|
||||||
|
|
@ -1242,7 +1242,7 @@ class trader:
|
||||||
return 0
|
return 0
|
||||||
tries-=1
|
tries-=1
|
||||||
time.sleep(self.broker.get_wait_time())
|
time.sleep(self.broker.get_wait_time())
|
||||||
self.broker.logger.log_this("Problems sending take profit order",1,self.config.get_pair())
|
self.broker.logger.log_this("Problems sending take profit order",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1254,12 +1254,12 @@ class trader:
|
||||||
while retries>0:
|
while retries>0:
|
||||||
try:
|
try:
|
||||||
order_history = dumps(self.status.get_deal_order_history()) if write_deal_order_history else ""
|
order_history = dumps(self.status.get_deal_order_history()) if write_deal_order_history else ""
|
||||||
dataset = (time.time(),self.config.get_pair(),amount,self.broker.get_exchange_name(),str(orderid),order_history)
|
dataset = (time.time(),self.status.get_pair(),amount,self.broker.get_exchange_name(),str(orderid),order_history)
|
||||||
#Write profit to cache
|
#Write profit to cache
|
||||||
self.broker.write_profit_to_cache(dataset)
|
self.broker.write_profit_to_cache(dataset)
|
||||||
return self.broker.write_profit_to_db(dataset)
|
return self.broker.write_profit_to_db(dataset)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Exception while writing profit: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Exception while writing profit: {e}",1,self.status.get_pair())
|
||||||
retries-=1
|
retries-=1
|
||||||
time.sleep(.1) #Shorter wait time since it's not an API call
|
time.sleep(.1) #Shorter wait time since it's not an API call
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -1271,11 +1271,11 @@ class trader:
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
extra = f" and {round(base_profit,6)} {self.base}" if base_profit>0 else ""
|
extra = f" and {round(base_profit,6)} {self.base}" if base_profit>0 else ""
|
||||||
message = f"{self.config.get_pair()} closed a {'short' if self.config.get_is_short() else 'long'} trade.\nProfit: {round(profit,6)} {self.quote}{extra}\nSafety orders triggered: {self.status.get_safety_orders_filled()}\nTake profit price: {order['price']} {self.quote}\nTrade size: {round(order['cost'],2)} {self.quote}\nDeal uptime: {self.seconds_to_time(self.status.get_deal_uptime())}\nOrder ID: {order['id']}\nExchange: {self.broker.get_exchange_name().capitalize()}\n"
|
message = f"{self.status.get_pair()} closed a {'short' if self.config.get_is_short() else 'long'} trade.\nProfit: {round(profit,6)} {self.quote}{extra}\nSafety orders triggered: {self.status.get_safety_orders_filled()}\nTake profit price: {order['price']} {self.quote}\nTrade size: {round(order['cost'],2)} {self.quote}\nDeal uptime: {self.seconds_to_time(self.status.get_deal_uptime())}\nOrder ID: {order['id']}\nExchange: {self.broker.get_exchange_name().capitalize()}\n"
|
||||||
self.broker.logger.send_tg_message(message)
|
self.broker.logger.send_tg_message(message)
|
||||||
return 0
|
return 0
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Exception in telegram_bot_sendprofit: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Exception in telegram_bot_sendprofit: {e}",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1341,17 +1341,17 @@ class trader:
|
||||||
#First let's check if the market exists
|
#First let's check if the market exists
|
||||||
market = self.broker.fetch_market(f"{self.base}/{new_quote}")
|
market = self.broker.fetch_market(f"{self.base}/{new_quote}")
|
||||||
if market is None:
|
if market is None:
|
||||||
self.broker.logger.log_this("Market might not exist",1,self.config.get_pair())
|
self.broker.logger.log_this("Market might not exist",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
if "active" in market and not market["active"]:
|
if "active" in market and not market["active"]:
|
||||||
self.broker.logger.log_this("Market is closed",1,self.config.get_pair())
|
self.broker.logger.log_this("Market is closed",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
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.config.get_pair())
|
self.broker.logger.log_this("Take profit order is None",1,self.status.get_pair())
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#Replace the current take profit order with a new one with new quote currency
|
#Replace the current take profit order with a new one with new quote currency
|
||||||
self.broker.logger.log_this("Replacing take profit order",2,self.config.get_pair())
|
self.broker.logger.log_this("Replacing take profit order",2,self.status.get_pair())
|
||||||
self.status.set_take_profit_order(self.quote_currency_replace_order(self.status.get_take_profit_order(),new_quote))
|
self.status.set_take_profit_order(self.quote_currency_replace_order(self.status.get_take_profit_order(),new_quote))
|
||||||
if self.status.get_take_profit_order()==self.broker.get_empty_order():
|
if self.status.get_take_profit_order()==self.broker.get_empty_order():
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -1360,21 +1360,21 @@ class trader:
|
||||||
#This is WRONG: We need to build a list of the newly sent orders and assign them with self.status.set_safety_orders()
|
#This is WRONG: We need to build a list of the newly sent orders and assign them with self.status.set_safety_orders()
|
||||||
new_order_list = []
|
new_order_list = []
|
||||||
for order in self.status.get_safety_orders():
|
for order in self.status.get_safety_orders():
|
||||||
self.broker.logger.log_this("Replacing safety order",2,self.config.get_pair())
|
self.broker.logger.log_this("Replacing safety order",2,self.status.get_pair())
|
||||||
new_order_list.append(self.quote_currency_replace_order(order,new_quote))
|
new_order_list.append(self.quote_currency_replace_order(order,new_quote))
|
||||||
self.status.set_safety_orders(new_order_list)
|
self.status.set_safety_orders(new_order_list)
|
||||||
|
|
||||||
#Calls switch_quote_currency_config
|
#Calls switch_quote_currency_config
|
||||||
self.broker.logger.log_this("Modifying config file",2,self.config.get_pair())
|
self.broker.logger.log_this("Modifying config file",2,self.status.get_pair())
|
||||||
self.quote_currency_switch_configs(new_quote)
|
self.quote_currency_switch_configs(new_quote)
|
||||||
|
|
||||||
#Updates status_dict
|
#Updates status_dict
|
||||||
self.broker.logger.log_this("Updating status file",2,self.config.get_pair())
|
self.broker.logger.log_this("Updating status file",2,self.status.get_pair())
|
||||||
self.status.set_status_file_path(f"status/{self.base}{self.quote}.status")
|
self.status.set_status_file_path(f"status/{self.base}{self.quote}.status")
|
||||||
self.update_status(True)
|
self.update_status(True)
|
||||||
|
|
||||||
#Done
|
#Done
|
||||||
self.broker.logger.log_this("Quote swap successful",2,self.config.get_pair())
|
self.broker.logger.log_this("Quote swap successful",2,self.status.get_pair())
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1383,8 +1383,8 @@ class trader:
|
||||||
Cancels the order and returns the new updated order
|
Cancels the order and returns the new updated order
|
||||||
'''
|
'''
|
||||||
#Cancels the old order
|
#Cancels the old order
|
||||||
if self.broker.cancel_order(old_order["id"],self.config.get_pair())==1:
|
if self.broker.cancel_order(old_order["id"],self.status.get_pair())==1:
|
||||||
self.broker.logger.log_this(f"Can't cancel old order {old_order['id']}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Can't cancel old order {old_order['id']}",1,self.status.get_pair())
|
||||||
return self.broker.get_empty_order()
|
return self.broker.get_empty_order()
|
||||||
|
|
||||||
#Sends the new order
|
#Sends the new order
|
||||||
|
|
@ -1400,7 +1400,7 @@ class trader:
|
||||||
self.broker.add_pair_to_config(f"{self.base}{new_quote}")
|
self.broker.add_pair_to_config(f"{self.base}{new_quote}")
|
||||||
if self.broker.rewrite_config_file()==1:
|
if self.broker.rewrite_config_file()==1:
|
||||||
#Error writing broker config file, undoing changes
|
#Error writing broker config file, undoing changes
|
||||||
self.broker.logger.log_this("Error writing new broker config file",1,self.config.get_pair())
|
self.broker.logger.log_this("Error writing new broker config file",1,self.status.get_pair())
|
||||||
self.quote_currency_undo_changes(new_quote,self.quote,False)
|
self.quote_currency_undo_changes(new_quote,self.quote,False)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
@ -1408,6 +1408,7 @@ class trader:
|
||||||
old_quote = self.quote
|
old_quote = self.quote
|
||||||
self.quote = new_quote
|
self.quote = new_quote
|
||||||
self.config.set_pair(f"{self.base}/{self.quote}")
|
self.config.set_pair(f"{self.base}/{self.quote}")
|
||||||
|
self.status.set_pair(f"{self.base}/{self.quote}")
|
||||||
self.profit_filename = f"profits/{self.base}{self.quote}.profits"
|
self.profit_filename = f"profits/{self.base}{self.quote}.profits"
|
||||||
self.log_filename = f"logs/{self.base}{self.quote}.log"
|
self.log_filename = f"logs/{self.base}{self.quote}.log"
|
||||||
|
|
||||||
|
|
@ -1417,12 +1418,12 @@ class trader:
|
||||||
with open(f"status/{self.base}{self.quote}.oldlong","w") as c:
|
with open(f"status/{self.base}{self.quote}.oldlong","w") as c:
|
||||||
c.write(dumps(self.status.get_old_long(), indent=4))
|
c.write(dumps(self.status.get_old_long(), indent=4))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.broker.logger.log_this(f"Exception while writing new old_long file: {e}",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Exception while writing new old_long file: {e}",1,self.status.get_pair())
|
||||||
|
|
||||||
#Write the new config file
|
#Write the new config file
|
||||||
self.config.set_config_file_path(f"configs/{self.base}{self.quote}.json")
|
self.config.set_config_file_path(f"configs/{self.base}{self.quote}.json")
|
||||||
if self.config.save_to_file()==1:
|
if self.config.save_to_file()==1:
|
||||||
self.broker.logger.log_this(f"Error while writing the new trader config file",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Error while writing the new trader config file",1,self.status.get_pair())
|
||||||
#Undoing changes
|
#Undoing changes
|
||||||
self.quote_currency_undo_changes(new_quote,old_quote,True)
|
self.quote_currency_undo_changes(new_quote,old_quote,True)
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -1441,12 +1442,13 @@ class trader:
|
||||||
self.broker.add_pair_to_config(f"{self.base}{self.quote}")
|
self.broker.add_pair_to_config(f"{self.base}{self.quote}")
|
||||||
|
|
||||||
self.config.set_pair(f"{self.base}/{self.quote}")
|
self.config.set_pair(f"{self.base}/{self.quote}")
|
||||||
|
self.status.set_pair(f"{self.base}/{self.quote}")
|
||||||
self.profit_filename = f"profits/{self.base}{self.quote}.profits"
|
self.profit_filename = f"profits/{self.base}{self.quote}.profits"
|
||||||
self.log_filename = f"logs/{self.base}{self.quote}.log"
|
self.log_filename = f"logs/{self.base}{self.quote}.log"
|
||||||
|
|
||||||
#Writing config file
|
#Writing config file
|
||||||
if write_broker_file and self.broker.rewrite_config_file()==1:
|
if write_broker_file and self.broker.rewrite_config_file()==1:
|
||||||
self.broker.logger.log_this("Error in quote_currency_undo_changed: error writing new broker config file",1,self.config.get_pair())
|
self.broker.logger.log_this("Error in quote_currency_undo_changed: error writing new broker config file",1,self.status.get_pair())
|
||||||
|
|
||||||
#Done
|
#Done
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -1555,9 +1557,9 @@ class trader:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
safety_order_string = f"{self.status.get_safety_orders_filled()}/{self.get_color('cyan')}{len(self.status.get_safety_orders())}{self.get_color('white')}/{self.config.get_no_of_safety_orders()}".rjust(27)
|
safety_order_string = f"{self.status.get_safety_orders_filled()}/{self.get_color('cyan')}{len(self.status.get_safety_orders())}{self.get_color('white')}/{self.status.get_no_of_safety_orders()}".rjust(27)
|
||||||
prices = f"{low_boundary_color}{low_boundary}{self.get_color('white')}|{price_color}{mid_boundary}{self.get_color('white')}|{target_price_color}{high_boundary}{self.get_color('white')}|{pct_color}{pct_to_profit_str}%{self.get_color('white')}"
|
prices = f"{low_boundary_color}{low_boundary}{self.get_color('white')}|{price_color}{mid_boundary}{self.get_color('white')}|{target_price_color}{high_boundary}{self.get_color('white')}|{pct_color}{pct_to_profit_str}%{self.get_color('white')}"
|
||||||
line1 = f"{p}{pair_color}{self.config.get_pair().center(13)}{self.get_color('white')}| {safety_order_string} |{prices}| Uptime: {self.seconds_to_time(self.status.get_deal_uptime())}"
|
line1 = f"{p}{pair_color}{self.status.get_pair().center(13)}{self.get_color('white')}| {safety_order_string} |{prices}| Uptime: {self.seconds_to_time(self.status.get_deal_uptime())}"
|
||||||
if self.status.get_is_boosted():
|
if self.status.get_is_boosted():
|
||||||
line1 = f"{line1} | BOOSTED"
|
line1 = f"{line1} | BOOSTED"
|
||||||
if self.config.get_autoswitch():
|
if self.config.get_autoswitch():
|
||||||
|
|
@ -1584,18 +1586,18 @@ class trader:
|
||||||
'''
|
'''
|
||||||
#Load status dict
|
#Load status dict
|
||||||
if self.status.load_from_file()==1:
|
if self.status.load_from_file()==1:
|
||||||
self.broker.logger.log_this(f"Error: Couldn't load status dict. Aborting",1,self.config.get_pair())
|
self.broker.logger.log_this(f"Error: Couldn't load status dict. Aborting",1,self.status.get_pair())
|
||||||
self.quit = True
|
self.quit = True
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
self.status.set_pause_reason("Importing trader")
|
self.status.set_pause_reason("Importing trader")
|
||||||
self.config.set_no_of_safety_orders(self.status.get_no_of_safety_orders()) #If this is not loaded from status_dict, it will ignore if safety orders were added at runtime
|
#self.config.set_no_of_safety_orders(self.status.get_no_of_safety_orders()) #If this is not loaded from status_dict, it will ignore if safety orders were added at runtime
|
||||||
|
|
||||||
#Refresh take profit order
|
#Refresh take profit order
|
||||||
order_id = self.status.get_take_profit_order()["id"]
|
order_id = self.status.get_take_profit_order()["id"]
|
||||||
self.status.set_take_profit_order(self.broker.get_order(order_id,self.config.get_pair()))
|
self.status.set_take_profit_order(self.broker.get_order(order_id,self.status.get_pair()))
|
||||||
if self.status.get_take_profit_order()==self.broker.get_empty_order():
|
if self.status.get_take_profit_order()==self.broker.get_empty_order():
|
||||||
self.broker.logger.log_this("Couldn't load take profit order (broker returned empty order). Aborting.",1,self.config.get_pair())
|
self.broker.logger.log_this("Couldn't load take profit order (broker returned empty order). Aborting.",1,self.status.get_pair())
|
||||||
self.quit = True
|
self.quit = True
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
@ -1604,7 +1606,7 @@ class trader:
|
||||||
#Refresh safety orders
|
#Refresh safety orders
|
||||||
#new_order_list = []
|
#new_order_list = []
|
||||||
#for order in self.status.get_safety_orders():
|
#for order in self.status.get_safety_orders():
|
||||||
# new_order_list.append(self.broker.get_order(order["id"],self.config.get_pair()))
|
# new_order_list.append(self.broker.get_order(order["id"],self.status.get_pair()))
|
||||||
# time.sleep(self.broker.get_wait_time())
|
# time.sleep(self.broker.get_wait_time())
|
||||||
#self.status.set_safety_orders(new_order_list)
|
#self.status.set_safety_orders(new_order_list)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ try:
|
||||||
api_key = credentials.get_credentials("testnet_api_key")["key"]
|
api_key = credentials.get_credentials("testnet_api_key")["key"]
|
||||||
base_url = credentials.get_url("testnet") #type: ignore
|
base_url = credentials.get_url("testnet") #type: ignore
|
||||||
exchanges = {"Binance":"/binance"}
|
exchanges = {"Binance":"/binance"}
|
||||||
if sys.argv[1]=="--local_testnet":
|
elif sys.argv[1]=="--local_testnet":
|
||||||
is_testnet = True
|
is_testnet = True
|
||||||
string_to_add = "LOCAL TESTNET "
|
string_to_add = "LOCAL TESTNET "
|
||||||
api_key = credentials.get_credentials("local_testnet_api_key")["key"]
|
api_key = credentials.get_credentials("local_testnet_api_key")["key"]
|
||||||
|
|
@ -64,6 +64,7 @@ TRADERS
|
||||||
68) toggle_check_old_long_price 69) switch_quote_currency
|
68) toggle_check_old_long_price 69) switch_quote_currency
|
||||||
70) view_old_long 71) switch_price 72) reload_trader_config
|
70) view_old_long 71) switch_price 72) reload_trader_config
|
||||||
73) toggle_liquidate_after_switch 74) base_add_calculation
|
73) toggle_liquidate_after_switch 74) base_add_calculation
|
||||||
|
75) mod_concurrent_safety_orders
|
||||||
|
|
||||||
98) Change broker 99) Exit
|
98) Change broker 99) Exit
|
||||||
'''
|
'''
|
||||||
|
|
@ -860,4 +861,23 @@ if __name__=="__main__":
|
||||||
base,quote = trading_pair.split("/")
|
base,quote = trading_pair.split("/")
|
||||||
url = f"{base_url}{port}/base_add_so_calculation?base={base}"e={quote}"
|
url = f"{base_url}{port}/base_add_so_calculation?base={base}"e={quote}"
|
||||||
print(json.loads(requests.get(url,headers=headers).content))
|
print(json.loads(requests.get(url,headers=headers).content))
|
||||||
input("Press ENTER to continue ")
|
input("Press ENTER to continue ")
|
||||||
|
|
||||||
|
elif command==75:
|
||||||
|
print("mod_concurrent_safety_orders modifies the amount of safety orders opened at the same time")
|
||||||
|
trading_pair = input("Input trader in the format BASE/QUOTE: ").upper()
|
||||||
|
new_amount = input("Desired amount of orders: ")
|
||||||
|
if not validate_pair(trading_pair):
|
||||||
|
print("The input is invalid")
|
||||||
|
break
|
||||||
|
if not validate_int(new_amount):
|
||||||
|
print("The amount entered is invalid")
|
||||||
|
break
|
||||||
|
if input("Proceed? (Y/n) ") in ["Y","y",""]:
|
||||||
|
url = f"{base_url}{port}/mod_concurrent_safety_orders"
|
||||||
|
base,quote = trading_pair.split("/")
|
||||||
|
parameters = {"base": base,
|
||||||
|
"quote": quote,
|
||||||
|
"amount": new_amount}
|
||||||
|
print(json.loads(requests.post(url, headers=headers, json=parameters).content))
|
||||||
|
input("Press ENTER to continue ")
|
||||||
Loading…
Reference in New Issue