first draft
This commit is contained in:
parent
f5e5f4eb77
commit
ca85e454f9
|
|
@ -1,3 +1,9 @@
|
|||
next:
|
||||
. Default wait time now 0.5 seconds.
|
||||
. Now the trader supports multiple safety orders at the same time.
|
||||
. Removed endpoint /reload_safety_orders.
|
||||
. Removed forcing orders when importing a trader. Maybe it will be reinstated at a later date.
|
||||
|
||||
2025.08.19:
|
||||
. Improved log trimming.
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class ConfigHandler:
|
|||
"order_size": self.broker.get_default_order_size(),
|
||||
"no_of_safety_orders": 30,
|
||||
"max_short_safety_orders": 45,
|
||||
"max_concurrent_safety_orders": 5,
|
||||
"safety_order_deviance": 2,
|
||||
"safety_order_scale": 0.0105,
|
||||
"dynamic_so_deviance": True,
|
||||
|
|
@ -68,6 +69,9 @@ class ConfigHandler:
|
|||
def get_max_short_safety_orders(self):
|
||||
return self.config_dictionary["max_short_safety_orders"]
|
||||
|
||||
def get_max_concurrent_safety_orders(self):
|
||||
return self.config_dictionary["max_concurrent_safety_orders"]
|
||||
|
||||
def get_safety_order_deviance(self):
|
||||
return self.config_dictionary["safety_order_deviance"]
|
||||
|
||||
|
|
@ -173,6 +177,13 @@ class ConfigHandler:
|
|||
self.config_dictionary["max_short_safety_orders"] = max_short_safety_orders
|
||||
return 0
|
||||
|
||||
def set_max_concurrent_safety_orders(self, max_concurrent_safety_orders: int):
|
||||
# if not isinstance(max_concurrent_safety_orders, int):
|
||||
# self.broker.logger.log_this(f"Max concurrent safety orders provided is not an integer",1,self.get_pair())
|
||||
# return 1
|
||||
self.config_dictionary["max_concurrent_safety_orders"] = max_concurrent_safety_orders
|
||||
return 0
|
||||
|
||||
def set_safety_order_deviance(self, safety_order_deviance: int):
|
||||
# if not isinstance(safety_order_deviance, int):
|
||||
# self.broker.logger.log_this(f"Safety order deviance provided is not an integer",1,self.get_pair())
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class Broker:
|
|||
self.broker_config = broker_config
|
||||
self.exchange = exchange
|
||||
self.last_price = 0
|
||||
self.wait_time = 1 #Default wait time for API breathing room
|
||||
self.wait_time = .5 #Default wait time for API breathing room
|
||||
self.cooldown_multiplier = 2 #Default cooldown multiplier value
|
||||
if "cooldown_multiplier" in self.broker_config:
|
||||
self.cooldown_multiplier = self.broker_config["cooldown_multiplier"]
|
||||
|
|
@ -581,7 +581,7 @@ class Broker:
|
|||
return []
|
||||
|
||||
|
||||
def get_closed_orders(self,no_retries=False): #It should return a list of all opened orders
|
||||
def get_closed_orders(self,pair=None,no_retries=False): #It should return a list of all opened orders
|
||||
'''
|
||||
Returns a list of all the open orders on the exchange
|
||||
|
||||
|
|
@ -592,7 +592,7 @@ class Broker:
|
|||
retries = self.retries
|
||||
while retries>0:
|
||||
try:
|
||||
return self.exchange.fetch_closed_orders()
|
||||
return self.exchange.fetch_closed_orders(pair)
|
||||
except Exception as e:
|
||||
self.logger.log_this(f"Exception in get_closed_orders: {e}",1)
|
||||
if no_retries:
|
||||
|
|
|
|||
74
main.py
74
main.py
|
|
@ -39,6 +39,7 @@ worker_threads_overprovisioning = 3 #Number of worker threads to create over
|
|||
#Only use 0 if you are sure that you won't be adding any.
|
||||
executor = None
|
||||
|
||||
#Shutdown handler
|
||||
def shutdown_handler(signum, _):
|
||||
broker.logger.log_this(f"Received signal {signum}, shutting down as gracefully as possible...", 2)
|
||||
if executor:
|
||||
|
|
@ -86,7 +87,7 @@ def time_to_unix(year: str, month: str, day: str) -> int:
|
|||
return 0
|
||||
|
||||
|
||||
def import_instance(base: str, quote: str, forced_tp_id = None, forced_so_id = None) -> int:
|
||||
def import_instance(base: str, quote: str) -> int:
|
||||
'''
|
||||
Imports an previously running trader instance from the status file.
|
||||
|
||||
|
|
@ -98,7 +99,7 @@ def import_instance(base: str, quote: str, forced_tp_id = None, forced_so_id = N
|
|||
int: 0 if successful
|
||||
'''
|
||||
broker.logger.log_this(f"Importing {base}/{quote}")
|
||||
instances_to_add.append(trader.trader(broker,f"{base}/{quote}",is_import=True,forced_tp_id=forced_tp_id,forced_so_id=forced_so_id))
|
||||
instances_to_add.append(trader.trader(broker,f"{base}/{quote}",is_import=True))
|
||||
if f"{base}{quote}" not in tickers:
|
||||
tickers.append(f"{base}{quote}")
|
||||
return 0
|
||||
|
|
@ -690,9 +691,7 @@ def import_pair():
|
|||
data = request.json
|
||||
base = data["base"]
|
||||
quote = data["quote"]
|
||||
forced_tp_id = data["forced_tp_id"] if "forced_tp_id" in data else None
|
||||
forced_so_id = data["forced_so_id"] if "forced_so_id" in data else None
|
||||
return unwrapped_import_pair(base,quote,forced_tp_id,forced_so_id)
|
||||
return unwrapped_import_pair(base,quote)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return jsonify({'Error': 'Halp'})
|
||||
|
|
@ -1060,7 +1059,7 @@ def toggle_cleanup():
|
|||
return jsonify({'Error': 'Halp'})
|
||||
|
||||
|
||||
@base_api.route("/toggle_autoswitch", methods=['POST']) #type:ignore
|
||||
@base_api.route("/toggle_autoswitch", methods=['POST'])
|
||||
def toggle_autoswitch():
|
||||
'''
|
||||
POST request
|
||||
|
|
@ -1084,8 +1083,8 @@ def toggle_autoswitch():
|
|||
return jsonify({'Error': 'Halp'})
|
||||
|
||||
|
||||
@base_api.route("/toggle_liquidate_after_switch", methods=['POST']) #type:ignore
|
||||
def toggle_liquidate_after_switch(): #type:ignore
|
||||
@base_api.route("/toggle_liquidate_after_switch", methods=['POST'])
|
||||
def toggle_liquidate_after_switch():
|
||||
'''
|
||||
POST request
|
||||
|
||||
|
|
@ -1108,7 +1107,7 @@ def toggle_liquidate_after_switch(): #type:ignore
|
|||
return jsonify({'Error': 'Halp'})
|
||||
|
||||
|
||||
@base_api.route("/toggle_check_old_long_price", methods=['POST'])#type:ignore
|
||||
@base_api.route("/toggle_check_old_long_price", methods=['POST'])
|
||||
def toggle_check_old_long_price():
|
||||
'''
|
||||
POST request
|
||||
|
|
@ -1338,30 +1337,7 @@ def reload_markets():
|
|||
return unwrapped_reload_markets()
|
||||
|
||||
|
||||
@base_api.route("/reload_safety_order", methods=['POST'])
|
||||
def reload_safety_order():
|
||||
'''
|
||||
POST request
|
||||
|
||||
Parameters:
|
||||
None
|
||||
'''
|
||||
|
||||
if not "X-API-KEY" in request.headers or not request.headers.get("X-API-KEY") in valid_keys:
|
||||
return jsonify({'Error': 'API key invalid'}), 401
|
||||
try:
|
||||
if request.json is None:
|
||||
return jsonify({'Error': 'request.json is None'})
|
||||
data = request.json
|
||||
base = data["base"]
|
||||
quote = data["quote"]
|
||||
return unwrapped_reload_safety_order(base,quote)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return jsonify({'Error': 'Halp'})
|
||||
|
||||
|
||||
@base_api.route("/reload_trader_config", methods=['POST'])#type:ignore
|
||||
@base_api.route("/reload_trader_config", methods=['POST'])
|
||||
def reload_trader_config():
|
||||
'''
|
||||
POST request
|
||||
|
|
@ -1512,15 +1488,13 @@ def unwrapped_restart_pair(base,quote):
|
|||
return jsonify({"Error": "Halp"})
|
||||
|
||||
|
||||
def unwrapped_import_pair(base,quote,forced_tp_id = None, forced_so_id = None):
|
||||
def unwrapped_import_pair(base,quote):
|
||||
'''
|
||||
Imports a previously running pair
|
||||
|
||||
Parameters:
|
||||
base (str): The base currency of the pair
|
||||
quote (str): The quote currency of the pair
|
||||
forced_tp_id (str): The ID of the take profit order to use
|
||||
forced_so_id (str): The ID of the stop order to use
|
||||
|
||||
Returns:
|
||||
jsonified dictionary detailing the outcome of the operation.
|
||||
|
|
@ -1528,7 +1502,7 @@ def unwrapped_import_pair(base,quote,forced_tp_id = None, forced_so_id = None):
|
|||
|
||||
try:
|
||||
symbol = f"{base}/{quote}"
|
||||
import_instance(base,quote,forced_tp_id,forced_so_id)
|
||||
import_instance(base,quote)
|
||||
broker.add_pair_to_config(f"{base}{quote}")
|
||||
broker.rewrite_config_file()
|
||||
broker.logger.log_this(f"Done",2,symbol)
|
||||
|
|
@ -2120,6 +2094,7 @@ def unwrapped_toggle_autoswitch(base,quote):
|
|||
broker.logger.log_this("Autoswitch turned ON",1,symbol)
|
||||
instance.config.set_autoswitch(True)
|
||||
return jsonify({"Success": "Autoswitch is now ON"})
|
||||
return jsonify({"Error": "Trader not running"})
|
||||
except Exception as e:
|
||||
broker.logger.log_this(f"Exception while toggling autoswitch: {e}",1,symbol)
|
||||
return jsonify({"Error": "Halp"})
|
||||
|
|
@ -2148,6 +2123,7 @@ def unwrapped_toggle_liquidate_after_switch(base,quote):
|
|||
broker.logger.log_this("Liquidate after switch turned ON",1,symbol)
|
||||
instance.config.set_liquidate_after_switch(True)
|
||||
return jsonify({"Success": "Liquidate after switch is now ON"})
|
||||
return jsonify({"Error": "Trader not running"})
|
||||
except Exception as e:
|
||||
broker.logger.log_this(f"Exception while toggling liquidate after switch: {e}",1,symbol)
|
||||
return jsonify({"Error": "Halp"})
|
||||
|
|
@ -2176,6 +2152,7 @@ def unwrapped_toggle_check_old_long_price(base,quote):
|
|||
broker.logger.log_this("Check ON",1,symbol)
|
||||
instance.config.set_check_old_long_price(True)
|
||||
return jsonify({"Success": "Old long price check turned ON"})
|
||||
return jsonify({"Error": "Trader not running"})
|
||||
except Exception as e:
|
||||
broker.logger.log_this(f"Exception while toggling check_old_long_price: {e}",1,symbol)
|
||||
return jsonify({"Error": "Halp"})
|
||||
|
|
@ -2363,29 +2340,6 @@ def unwrapped_reload_markets():
|
|||
return jsonify({"Error": "Markets couldn't be reloaded"})
|
||||
|
||||
|
||||
def unwrapped_reload_safety_order(base,quote):
|
||||
'''
|
||||
Reloads the safety order of a trader.
|
||||
|
||||
Parameters:
|
||||
base (str): The base currency of the trader.
|
||||
quote (str): The quote currency of the trader.
|
||||
|
||||
Returns:
|
||||
jsonify: A jsonified dictionary detailing the outcome of the operation.
|
||||
'''
|
||||
try:
|
||||
symbol = f"{base}/{quote}"
|
||||
for trader in running_traders:
|
||||
if trader.config.get_pair()==symbol:
|
||||
trader.config.load_from_file()
|
||||
return jsonify({"Success": "Safety order reloaded successfully"})
|
||||
return jsonify({"Error": "Trader not found"})
|
||||
except Exception as e:
|
||||
broker.logger.log_this(f"Exception while reloading safety order: {e}",1,symbol)
|
||||
return jsonify({"Error": "Safety order couldn't be reloaded"})
|
||||
|
||||
|
||||
def unwrapped_get_balance(coin):
|
||||
'''
|
||||
Returns the balance of a given coin.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class StatusHandler:
|
|||
"pair": f"{base}/{quote}",
|
||||
"take_profit_order": broker.get_empty_order(),
|
||||
"take_profit_price": 0.0,
|
||||
"safety_order": broker.get_empty_order(),
|
||||
"safety_orders": [],
|
||||
"next_so_price": 0.0,
|
||||
"order_size": 0.0,
|
||||
"partial_profit": 0.0,
|
||||
|
|
@ -58,8 +58,11 @@ class StatusHandler:
|
|||
def get_take_profit_price(self):
|
||||
return self.status_dictionary["take_profit_price"]
|
||||
|
||||
def get_safety_order(self):
|
||||
return self.status_dictionary["safety_order"]
|
||||
def get_safety_orders(self):
|
||||
"""
|
||||
Returns the list of open safety orders
|
||||
"""
|
||||
return self.status_dictionary["safety_orders"]
|
||||
|
||||
def get_next_so_price(self):
|
||||
return self.status_dictionary["next_so_price"]
|
||||
|
|
@ -181,8 +184,11 @@ class StatusHandler:
|
|||
self.status_dictionary["so_order_id"] = order_id
|
||||
return 0
|
||||
|
||||
def set_safety_order(self, order):
|
||||
self.status_dictionary["safety_order"] = order
|
||||
def set_safety_orders(self, orders: list):
|
||||
"""
|
||||
Replaces the whole safety orders list
|
||||
"""
|
||||
self.status_dictionary["safety_orders"] = orders
|
||||
return 0
|
||||
|
||||
def set_next_so_price(self, price: float):
|
||||
|
|
@ -381,6 +387,21 @@ class StatusHandler:
|
|||
self.status_dictionary["deal_order_history"] = deal_history
|
||||
return 0
|
||||
|
||||
def add_safety_order(self, order):
|
||||
"""
|
||||
Appends a newly-created safety order to the internal list
|
||||
"""
|
||||
self.status_dictionary["safety_orders"].append(order)
|
||||
return 0
|
||||
|
||||
def remove_safety_order_by_id(self, order_id: str):
|
||||
"""
|
||||
Removes an order from the list (mostly used when that order is filled or canceled)
|
||||
"""
|
||||
orders = self.get_safety_orders()
|
||||
self.status_dictionary["safety_orders"] = [order for order in orders if order["id"] != order_id]
|
||||
return 0
|
||||
|
||||
def clear_deal_order_history(self):
|
||||
self.status_dictionary["deal_order_history"] = []
|
||||
return 0
|
||||
|
|
|
|||
325
trader.py
325
trader.py
|
|
@ -50,7 +50,7 @@ class trader:
|
|||
|
||||
self.status.set_pause_reason("Initialization")
|
||||
if is_import:
|
||||
self.load_imported_trader(forced_tp_order_id=forced_tp_id, forced_safety_order_id=forced_so_id)
|
||||
self.load_imported_trader()
|
||||
return None
|
||||
|
||||
# An alternative would be to set up a variable like self.is_initalized to false and finish the initialization here.
|
||||
|
|
@ -105,15 +105,6 @@ class trader:
|
|||
return self.market_reload_period
|
||||
|
||||
|
||||
def reload_safety_order(self) -> int:
|
||||
'''
|
||||
Reloads the safety order.
|
||||
'''
|
||||
|
||||
self.status.set_safety_order(self.broker.get_order(self.status.get_safety_order()["id"],self.config.get_pair()))
|
||||
return 0
|
||||
|
||||
|
||||
def start_trader(self) -> int:
|
||||
'''
|
||||
Initializes the trader.
|
||||
|
|
@ -124,7 +115,7 @@ class trader:
|
|||
self.status.set_so_amount(0)
|
||||
self.status.clear_deal_order_history()
|
||||
self.status.set_take_profit_order(self.broker.get_empty_order())
|
||||
self.status.set_safety_order(self.broker.get_empty_order())
|
||||
self.status.set_safety_orders([])
|
||||
|
||||
#Reloads the market
|
||||
new_market_data = self.broker.fetch_market(self.config.get_pair())
|
||||
|
|
@ -217,11 +208,9 @@ class trader:
|
|||
#Wait until the first order gets filled
|
||||
self.status.set_pause_reason("start_trader - waiting for the first order to get filled")
|
||||
while True:
|
||||
#Wait a bit longer, to catch a bug:
|
||||
#Sometimes the amount of base taken into account by the trader is lower than the amount bought,
|
||||
#Wait a bit longer, sometimes a recently filled market order is not updated quickly enough.
|
||||
# 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.
|
||||
# Maybe is the first market order getting "closed" before is fully filled?
|
||||
# Or is there an error later in the trader?
|
||||
time.sleep(self.broker.get_wait_time())
|
||||
returned_order = self.broker.get_order(first_order["id"],self.config.get_pair())
|
||||
if returned_order==self.broker.get_empty_order():
|
||||
|
|
@ -278,13 +267,15 @@ class trader:
|
|||
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_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()))
|
||||
|
||||
# Send the first safety order
|
||||
self.status.set_pause_reason("start_trader - sending safety order")
|
||||
self.broker.logger.log_this("Sending safety order...",2,self.config.get_pair())
|
||||
if self.send_new_safety_order(self.status.get_order_size())==0:
|
||||
self.broker.logger.log_this("Safety order sent",2,self.config.get_pair())
|
||||
# Send the initial batch of 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())
|
||||
max_initial_safety_orders = min(self.config.get_max_concurrent_safety_orders(),self.config.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)
|
||||
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())
|
||||
else:
|
||||
self.broker.logger.log_this("Error sending safety order. 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.config.get_pair())
|
||||
self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.config.get_pair())
|
||||
return 1
|
||||
|
||||
|
|
@ -312,9 +303,8 @@ class trader:
|
|||
self.status.set_next_so_price(self.status.get_safety_price_table()[self.status.get_so_amount()])
|
||||
except Exception as e:
|
||||
self.broker.logger.log_this(f"Is safety_price_table populated? Exception: {e} | Safety price table: {self.status.get_safety_price_table()} | Safety order index: {self.status.get_so_amount()}",1,self.config.get_pair())
|
||||
if self.status.get_safety_order() is not None and self.status.get_safety_order()["price"] is not None and self.status.get_safety_order()!=self.broker.get_empty_order():
|
||||
self.status.set_next_so_price(self.status.get_safety_order()["price"])
|
||||
|
||||
if self.status.get_safety_orders()!=[]:
|
||||
self.status.set_next_so_price(self.status.get_safety_orders()[0]["price"])
|
||||
self.status.set_is_paused(self.pause)
|
||||
self.status.set_is_short(self.config.get_is_short())
|
||||
self.status.set_no_of_safety_orders(self.config.get_no_of_safety_orders())
|
||||
|
|
@ -519,9 +509,6 @@ class trader:
|
|||
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())
|
||||
return 1
|
||||
if self.status.get_safety_order() is None:
|
||||
self.broker.logger.log_this("Safety order is None, can't switch to short",1,self.config.get_pair())
|
||||
return 1
|
||||
|
||||
#Pauses trader
|
||||
self.pause = True
|
||||
|
|
@ -623,10 +610,8 @@ class trader:
|
|||
|
||||
#Cancel open orders
|
||||
try:
|
||||
if self.status.get_safety_order() is not None:
|
||||
self.broker.cancel_order(self.status.get_safety_order()["id"],self.config.get_pair())
|
||||
else:
|
||||
self.broker.logger.log_this("Take profit order is None",1,self.config.get_pair())
|
||||
for order in self.status.get_safety_orders():
|
||||
self.broker.cancel_order(order["id"],self.config.get_pair())
|
||||
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())
|
||||
try:
|
||||
|
|
@ -666,7 +651,7 @@ class trader:
|
|||
self.status.set_fees_paid_in_quote(0)
|
||||
self.status.set_fees_paid_in_base(0)
|
||||
self.status.set_take_profit_order(self.broker.get_empty_order())
|
||||
self.status.set_safety_order(self.broker.get_empty_order())
|
||||
self.status.set_safety_orders([])
|
||||
self.status.set_safety_price_table([])
|
||||
self.status.set_so_amount(0)
|
||||
|
||||
|
|
@ -732,39 +717,33 @@ class trader:
|
|||
self.status.save_to_file(is_backup=True)
|
||||
self.restart = True
|
||||
return 1
|
||||
if self.status.get_safety_order() is None:
|
||||
self.status.set_pause_reason(time.strftime(f"[%Y/%m/%d %H:%M:%S] | {self.config.get_pair()} | Safety order is None"))
|
||||
self.broker.logger.log_this("Error. Safety order is None",1,self.config.get_pair())
|
||||
self.status.set_safety_order(self.broker.get_empty_order())
|
||||
|
||||
#Save the order in history.
|
||||
if self.broker.get_follow_order_history():
|
||||
self.status.update_deal_order_history(filled_order)
|
||||
|
||||
# Cancel the current safety order (first check if there is something to cancel)
|
||||
already_counted = False
|
||||
if self.status.get_safety_order()["id"]=="":
|
||||
self.broker.logger.log_this("There is no safety order to cancel",2,self.config.get_pair())
|
||||
elif self.broker.cancel_order(self.status.get_safety_order()["id"],self.config.get_pair())==1:
|
||||
self.broker.logger.log_this("Old safety order probably filled. Can't cancel.",1,self.config.get_pair())
|
||||
closed_order = self.broker.get_order(self.status.get_safety_order()["id"],self.config.get_pair())
|
||||
if closed_order!=self.broker.get_empty_order() and closed_order["status"]=="closed":
|
||||
self.status.set_base_bought(self.status.get_base_bought() + closed_order["filled"])
|
||||
#Cancel all the safety orders ASAP
|
||||
for order in self.status.get_safety_orders():
|
||||
self.broker.cancel_order(order["id"])
|
||||
#Check if some safety orders were filled
|
||||
for order in self.status.get_safety_orders():
|
||||
closed_order = self.broker.get_order(order["id"],self.config.get_pair())
|
||||
if closed_order["filled"]==0:
|
||||
#If this order wasn't filled, it is safe to assume that no order coming after this one was.
|
||||
break
|
||||
#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.status.set_base_bought(self.status.get_base_bought() + closed_order["filled"] - self.parse_fees(closed_order)[0])
|
||||
self.status.set_quote_spent(self.status.get_quote_spent() + closed_order["cost"])
|
||||
#Save the order
|
||||
if self.broker.get_follow_order_history():
|
||||
self.status.update_deal_order_history(closed_order)
|
||||
already_counted = True
|
||||
if closed_order["remaining"]!=0:
|
||||
#If this order is not completely filled, it is safe to assume that no order coming after this one was partially filled.
|
||||
break
|
||||
#Now we can clear the safety order list
|
||||
self.status.set_safety_orders([])
|
||||
|
||||
#IF NOT SHORT - Check if the SO was partially filled. If so, add the amounts to total_amount_of_base and total_amount_of_quote
|
||||
if not self.config.get_is_short() and self.status.get_safety_order()["id"]!="" and not already_counted:
|
||||
old_so_order = self.broker.get_order(self.status.get_safety_order()["id"],self.config.get_pair())
|
||||
if old_so_order["filled"]>0:
|
||||
self.broker.logger.log_this(f"Old safety order is partially filled, ID: {old_so_order['id']}",1,self.config.get_pair())
|
||||
if self.broker.get_follow_order_history():
|
||||
self.status.update_deal_order_history(old_so_order)
|
||||
self.status.set_base_bought(self.status.get_base_bought() + old_so_order["filled"] - self.parse_fees(old_so_order)[0])
|
||||
self.status.set_quote_spent(self.status.get_quote_spent() + old_so_order["cost"])
|
||||
|
||||
if not self.broker.check_for_duplicate_profit_in_db(filled_order):
|
||||
self.status.set_pause_reason("calculating profit")
|
||||
|
|
@ -837,58 +816,91 @@ class trader:
|
|||
return restart_trader
|
||||
|
||||
|
||||
def new_so_routine(self, filled_order: dict, send_new_so: bool) -> int:
|
||||
'''
|
||||
Handles all the bureaucracy prior and after sending a new safety order
|
||||
:param filled_order: dict
|
||||
:param send_new_so: bool
|
||||
:return: 0 OK, 1 not enough funds, if can't cancel old TP, can't send new TP
|
||||
'''
|
||||
def send_new_safety_order_batch(self, amount: int):
|
||||
"""
|
||||
Sends a new safety order batch to the broker
|
||||
:param amount: int - The amount of safety orders to send.
|
||||
:return: The amount of orders succesfully sent. None if an error occurs.
|
||||
|
||||
#Let's do some type checking first
|
||||
If the amount of orders returned is less than the amount expected, we should not try to send more safety orders.
|
||||
"""
|
||||
|
||||
if amount<1:
|
||||
return 0
|
||||
orders_to_place = min(self.config.get_no_of_safety_orders()-self.status.get_so_amount(),amount)
|
||||
if orders_to_place<1:
|
||||
return 0
|
||||
orders_placed = 0
|
||||
for _ in range(orders_to_place):
|
||||
so_size = self.gib_so_size(self.status.get_order_size(),self.status.get_so_amount()+1,self.config.get_safety_order_scale())
|
||||
if self.config.get_is_short():
|
||||
new_order = self.broker.new_limit_order(self.config.get_pair(),so_size,"sell",self.status.get_safety_price_table()[self.status.get_so_amount()+1])
|
||||
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])
|
||||
if new_order==1:
|
||||
self.broker.logger.log_this("Not enough balance to send a new safety order",1,self.config.get_pair())
|
||||
return orders_placed
|
||||
elif new_order is None:
|
||||
self.broker.logger.log_this("new_limit_order returned None",1,self.config.get_pair())
|
||||
return orders_placed
|
||||
orders_placed+=1
|
||||
self.status.add_safety_order(new_order)
|
||||
self.status.set_so_amount(self.status.get_so_amount()+1)
|
||||
return orders_placed
|
||||
|
||||
|
||||
def renew_tp_and_so_routine(self, filled_safety_orders: list):
|
||||
'''
|
||||
Modifies the current take profit order and sends a new safety order
|
||||
:return: 0 OK, 1 take profit order is None, 2 not enough funds, 3 can't cancel TP (filled?), 4 can't send new TP
|
||||
'''
|
||||
safety_orders_to_remove_by_id = []
|
||||
|
||||
#Check if current TP order is valid
|
||||
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())
|
||||
return 1
|
||||
if self.status.get_safety_order() is None: #I don't think this is necessary
|
||||
self.broker.logger.log_this("Safety order is None, can't send a new safety order",1,self.config.get_pair())
|
||||
return 1
|
||||
|
||||
#Pause the trader
|
||||
self.pause = True
|
||||
self.status.set_pause_reason("new_so_routine")
|
||||
self.status.set_pause_reason("renew_tp_and_so_routine")
|
||||
|
||||
# Save the order
|
||||
#Save the order
|
||||
if self.broker.get_follow_order_history():
|
||||
self.status.update_deal_order_history(filled_order)
|
||||
for item in filled_safety_orders:
|
||||
self.status.update_deal_order_history(item)
|
||||
|
||||
# Add the amount filled in the last safety order to the totals
|
||||
new_fees_base,new_fees_quote = self.parse_fees(filled_order)
|
||||
#Add the amount filled in the last safety orders to the totals
|
||||
for order in filled_safety_orders:
|
||||
safety_orders_to_remove_by_id.append(order["id"])
|
||||
new_fees_base,new_fees_quote = self.parse_fees(order)
|
||||
self.status.set_fees_paid_in_quote(self.status.get_fees_paid_in_quote() + new_fees_quote)
|
||||
self.status.set_base_bought(self.status.get_base_bought() + filled_order["filled"] - new_fees_base)
|
||||
self.status.set_quote_spent(self.status.get_quote_spent() + filled_order["cost"])
|
||||
self.status.set_base_bought(self.status.get_base_bought() + order["filled"] - new_fees_base)
|
||||
self.status.set_quote_spent(self.status.get_quote_spent() + order["cost"])
|
||||
|
||||
#Remove the filled safety orders from the list
|
||||
if safety_orders_to_remove_by_id!=[]:
|
||||
new_order_list = []
|
||||
#Remove filled orders from the list
|
||||
for order in self.status.get_safety_orders():
|
||||
if order["id"] not in safety_orders_to_remove_by_id:
|
||||
new_order_list.append(order)
|
||||
self.status.set_safety_orders(new_order_list)
|
||||
|
||||
#Cooldown
|
||||
time.sleep(self.broker.get_wait_before_new_safety_order())
|
||||
|
||||
# Send the new safety order. If all expected safety orders are filled, it assigns an empty order to self.status.get_safety_order()
|
||||
if send_new_so:
|
||||
self.broker.logger.log_this("Sending a new safety order",2,self.config.get_pair())
|
||||
if self.send_new_safety_order(self.status.get_order_size())==1:
|
||||
error_string = "Problems sending the new safety order. Maybe not enough funds?"
|
||||
self.broker.logger.log_this(error_string,1,self.config.get_pair())
|
||||
self.status.set_pause_reason(error_string)
|
||||
return 1
|
||||
else:
|
||||
self.status.set_safety_order(self.broker.get_empty_order())
|
||||
self.status.set_so_amount(self.status.get_so_amount()+1)
|
||||
#Send new SO(s)
|
||||
orders_sent = self.send_new_safety_order_batch(len(filled_safety_orders))
|
||||
|
||||
# Cancel the old tp order
|
||||
#Cancel old TP order
|
||||
if self.broker.cancel_order(self.status.get_take_profit_order()["id"],self.config.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"
|
||||
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.status.set_pause_reason(error_string)
|
||||
return 2
|
||||
|
||||
# Check if the old tp order was partially filled. If so, update the previous two variables accordingly
|
||||
#Check if old TP order was partially filled
|
||||
# TODO: This should also be taken into account for the profit calculation
|
||||
# Do the partial profit calculation and save it for later
|
||||
old_tp_order = self.broker.get_order(self.status.get_take_profit_order()["id"],self.config.get_pair())
|
||||
|
|
@ -903,8 +915,6 @@ class trader:
|
|||
# self.status.set_partial_profit(self.status.get_partial_profit()+old_tp_order["cost"]-(old_tp_order["filled"]*current_deal_price)-self.parse.fees(old_tp_order)[1])
|
||||
# self.update_status(True)
|
||||
#
|
||||
# Maybe here we shouldn't substract fees yet, but add them up to the check.
|
||||
#
|
||||
self.status.set_base_bought(self.status.get_base_bought() - old_tp_order["filled"] - self.parse_fees(old_tp_order)[0])
|
||||
self.status.set_quote_spent(self.status.get_quote_spent() - old_tp_order["cost"])
|
||||
self.status.set_fees_paid_in_quote(self.status.get_fees_paid_in_quote() + self.parse_fees(old_tp_order)[1])
|
||||
|
|
@ -913,17 +923,21 @@ class trader:
|
|||
#Cooldown
|
||||
time.sleep(self.broker.get_wait_time())
|
||||
|
||||
# Send the new take profit order
|
||||
#Send new TP order
|
||||
if self.send_new_tp_order()==1:
|
||||
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.status.set_pause_reason(error_string)
|
||||
return 3
|
||||
return 4
|
||||
|
||||
# Update the status_dict and that's it
|
||||
#Update status dict
|
||||
self.update_status(True)
|
||||
|
||||
#Toggle the pause flag
|
||||
self.pause = False
|
||||
self.status.set_pause_reason("")
|
||||
|
||||
#Done
|
||||
return 0
|
||||
|
||||
|
||||
|
|
@ -1024,18 +1038,15 @@ class trader:
|
|||
#Extract ids from order list
|
||||
open_orders_ids = [order["id"] for order in open_orders if order["symbol"]==self.config.get_pair()]
|
||||
|
||||
#Checks if the orders are valid
|
||||
#Checks if the take profit order is valid
|
||||
if self.status.get_take_profit_order() is None:
|
||||
self.broker.logger.log_this("Take profit order is None",1,self.config.get_pair())
|
||||
return 1
|
||||
if self.status.get_safety_order() is None:
|
||||
#Here, would it be wise to attempt to reload the safety order from the status dict?
|
||||
self.broker.logger.log_this("Safety order is None",1,self.config.get_pair())
|
||||
self.status.set_safety_order(self.broker.get_empty_order())
|
||||
#return 1
|
||||
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.cancel_order(self.status.get_safety_order()["id"],self.config.get_pair())
|
||||
#Cancelling safety orders
|
||||
for item in self.status.get_safety_orders():
|
||||
self.broker.cancel_order(item["id"],self.config.get_pair())
|
||||
if self.config.get_attempt_restart():
|
||||
self.status.save_to_file(is_backup=True)
|
||||
self.restart = True
|
||||
|
|
@ -1051,8 +1062,9 @@ class trader:
|
|||
if tp_status["filled"]>0:
|
||||
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())
|
||||
#Cancelling safety order and stopping trader
|
||||
self.broker.cancel_order(self.status.get_safety_order()["id"],self.config.get_pair())
|
||||
#Cancelling safety orders
|
||||
for item in self.status.get_safety_orders():
|
||||
self.broker.cancel_order(item["id"],self.config.get_pair())
|
||||
if self.config.get_attempt_restart():
|
||||
self.status.save_to_file(is_backup=True)
|
||||
self.restart = True
|
||||
|
|
@ -1073,46 +1085,52 @@ class trader:
|
|||
self.broker.logger.log_this(f"Take profit order search returned empty order. Order ID: {tp_status['id']}",1,self.config.get_pair())
|
||||
return 1
|
||||
|
||||
# Check if safety order is filled
|
||||
if self.status.get_safety_order()["id"] not in open_orders_ids and self.status.get_so_amount()<=self.config.get_no_of_safety_orders():
|
||||
so_status = self.broker.get_order(self.status.get_safety_order()["id"],self.config.get_pair())
|
||||
tp_order_status = self.broker.get_order(self.status.get_take_profit_order()["id"],self.config.get_pair())
|
||||
# Check if any safety order is filled
|
||||
filled_ids = []
|
||||
for order in self.status.get_safety_orders():
|
||||
if order["id"] not in open_orders_ids:
|
||||
filled_ids.append(order["id"])
|
||||
|
||||
#Now we check 2 things:
|
||||
#1. That the prior safety order status is indeed closed (or canceled)
|
||||
#2. That the take profit order is still opened (if not, the deal must have closed, both orders closing is quite common in high variance scenarios)
|
||||
if so_status["status"] in ["closed", "canceled", ""] and tp_order_status["status"]=="open":
|
||||
#Switch to short if all safety orders are sent and autoswitch is enabled.
|
||||
#May get into trouble if the trader is short of funds
|
||||
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():
|
||||
self.switch_to_short()
|
||||
if filled_ids!=[]:
|
||||
closed_orders = self.broker.get_closed_orders(self.config.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", ""]?
|
||||
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
|
||||
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())
|
||||
if self.config.get_attempt_restart():
|
||||
self.status.save_to_file(is_backup=True)
|
||||
self.restart = True
|
||||
return 0
|
||||
a = self.new_so_routine(so_status,self.status.get_so_amount()<self.config.get_no_of_safety_orders())
|
||||
#0 OK, 1 not enough funds, 2 can't cancel old TP, 3 can't send new TP
|
||||
if a==1:
|
||||
self.broker.logger.log_this(f"Can't send new safety order. Not enough funds? new_so_routine returned {a}",1,self.config.get_pair())
|
||||
#If there are not enough funds do not even try to send more safety orders
|
||||
#This way of doing it seems more practical than setting up yet another flag
|
||||
return 1
|
||||
elif renew_outcome==2:
|
||||
#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())
|
||||
#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
|
||||
self.config.set_no_of_safety_orders(self.status.get_so_amount())
|
||||
return 1
|
||||
elif a==2:
|
||||
self.broker.logger.log_this(f"Can't cancel old take profit order. new_so_routine returned {a}",1,self.config.get_pair())
|
||||
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.pause = False
|
||||
self.status.set_pause_reason("")
|
||||
if self.config.get_attempt_restart():
|
||||
self.status.save_to_file(is_backup=True)
|
||||
self.restart = True
|
||||
return 1
|
||||
elif a==3:
|
||||
#self.pause = False
|
||||
self.broker.logger.log_this(f"Error in trader: Can't send new take profit order. Restart will be attempted. new_so_routine returned {a}",0,self.config.get_pair())
|
||||
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())
|
||||
if self.config.get_attempt_restart():
|
||||
self.status.save_to_file(is_backup=True)
|
||||
self.restart = True
|
||||
return 1
|
||||
#else: check if the order is partially filled. If so, add the amounts to amount_of_quote and amount_of_base and update the take profit order.
|
||||
|
||||
#Check for autoswitch (long->short)
|
||||
#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():
|
||||
# self.switch_to_short()
|
||||
# self.status.save_to_file(is_backup=True)
|
||||
# self.restart = True
|
||||
# return 0
|
||||
|
||||
#Render status line(s)
|
||||
self.status.set_status_string(self.generate_status_strings())
|
||||
|
|
@ -1245,28 +1263,6 @@ class trader:
|
|||
return 1
|
||||
|
||||
|
||||
def send_new_safety_order(self, size: float) -> int:
|
||||
'''
|
||||
Sends a new safety order to the exchange
|
||||
'''
|
||||
so_size = self.gib_so_size(size,self.status.get_so_amount()+1,self.config.get_safety_order_scale()) #safety_order_scale: safety order growth factor
|
||||
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])
|
||||
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])
|
||||
if new_order==1:
|
||||
self.status.set_safety_order(self.broker.get_empty_order())
|
||||
self.broker.logger.log_this("Not enough balance to send a new safety order",1,self.config.get_pair())
|
||||
#elif new_order in [None,self.broker.get_empty_order()] #MAYUBE THIS CONDITIONAL IS BETTER
|
||||
elif new_order is None:
|
||||
self.status.set_safety_order(None)
|
||||
return 1
|
||||
else:
|
||||
self.status.set_safety_order(new_order)
|
||||
self.status.set_so_amount(self.status.get_so_amount()+1)
|
||||
return 0
|
||||
|
||||
|
||||
def telegram_bot_sendprofit(self,profit,order,base_profit=0) -> int:
|
||||
'''
|
||||
Sends the Telegram notification when profit is met
|
||||
|
|
@ -1351,9 +1347,6 @@ class trader:
|
|||
if self.status.get_take_profit_order() is None:
|
||||
self.broker.logger.log_this("Take profit order is None",1,self.config.get_pair())
|
||||
return 1
|
||||
if self.status.get_safety_order() is None:
|
||||
self.broker.logger.log_this("Safety order is None",1,self.config.get_pair())
|
||||
return 1
|
||||
|
||||
#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())
|
||||
|
|
@ -1361,12 +1354,13 @@ class trader:
|
|||
if self.status.get_take_profit_order()==self.broker.get_empty_order():
|
||||
return 1
|
||||
|
||||
#Replace the current safety order (if any) with a new one with the new quote currency
|
||||
if self.status.get_safety_order()!=self.broker.get_empty_order():
|
||||
#Replace the current safety orders (if any) with new ones with the new quote currency
|
||||
#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 = []
|
||||
for order in self.status.get_safety_orders():
|
||||
self.broker.logger.log_this("Replacing safety order",2,self.config.get_pair())
|
||||
self.status.set_safety_order(self.quote_currency_replace_order(self.status.get_safety_order(),new_quote))
|
||||
if self.status.get_safety_order()==self.broker.get_empty_order():
|
||||
return 1
|
||||
new_order_list.append(self.quote_currency_replace_order(order,new_quote))
|
||||
self.status.set_safety_orders(new_order_list)
|
||||
|
||||
#Calls switch_quote_currency_config
|
||||
self.broker.logger.log_this("Modifying config file",2,self.config.get_pair())
|
||||
|
|
@ -1582,7 +1576,7 @@ class trader:
|
|||
return status_string
|
||||
|
||||
|
||||
def load_imported_trader(self, forced_tp_order_id = None, forced_safety_order_id = None) -> int:
|
||||
def load_imported_trader(self) -> int:
|
||||
'''
|
||||
Loads status dictionary, orders and sets up variables
|
||||
'''
|
||||
|
|
@ -1596,22 +1590,21 @@ class 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
|
||||
|
||||
#Refresh take profit order
|
||||
order_id = self.status.get_take_profit_order()["id"] if forced_tp_order_id is None else forced_tp_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()))
|
||||
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.quit = True
|
||||
return 1
|
||||
|
||||
#Refresh safety order
|
||||
order_id = self.status.get_safety_order()["id"] if forced_safety_order_id is None else forced_safety_order_id
|
||||
self.status.set_safety_order(self.broker.get_order(order_id,self.config.get_pair()))
|
||||
if self.status.get_safety_order()==self.broker.get_empty_order() and self.status.get_so_amount()<self.config.get_no_of_safety_orders():
|
||||
#The second condition is important: it signals that the empty order returned was because of an error, not because the trader ran out of funds in the past.
|
||||
#When the trader runs out of funds, safety_order_index=config.get_no_of_safety_orders()
|
||||
self.broker.logger.log_this("Couldn't load safety order. Aborting.",2,self.config.get_pair())
|
||||
self.quit = True
|
||||
return 1
|
||||
#Safety order list does not need refreshing
|
||||
#Probably validation while migrating to the new version.
|
||||
#Refresh safety orders
|
||||
#new_order_list = []
|
||||
#for order in self.status.get_safety_orders():
|
||||
# new_order_list.append(self.broker.get_order(order["id"],self.config.get_pair()))
|
||||
# time.sleep(self.broker.get_wait_time())
|
||||
#self.status.set_safety_orders(new_order_list)
|
||||
|
||||
#Done
|
||||
self.pause = False
|
||||
|
|
|
|||
|
|
@ -56,9 +56,8 @@ TRADERS
|
|||
62) mod_tp_level 63) last_call 64) deferred_last_call
|
||||
65) toggle_pause 66) toggle_cleanup 67) toggle_autoswitch
|
||||
68) toggle_check_old_long_price 69) switch_quote_currency
|
||||
70) reload_safety_order 71) view_old_long 72) switch_price
|
||||
73) reload_trader_config 74) toggle_liquidate_after_switch
|
||||
75) base_add_calculation
|
||||
70) view_old_long 71) switch_price 72) reload_trader_config
|
||||
73) toggle_liquidate_after_switch 74) base_add_calculation
|
||||
|
||||
98) Change broker 99) Exit
|
||||
'''
|
||||
|
|
@ -561,10 +560,6 @@ if __name__=="__main__":
|
|||
print("In order for the importing to be successful, a status file must exist in the status directory ")
|
||||
print("and the take profit order must be open.")
|
||||
trading_pair = input("Input trader in the format BASE/QUOTE: ").upper()
|
||||
tp_id_input = input("Input take profit order id to use (if any)")
|
||||
forced_tp_id = None if tp_id_input=="" else tp_id_input
|
||||
so_id_input = input("Input safety order id to use (if any)")
|
||||
forced_so_id = None if so_id_input=="" else so_id_input
|
||||
|
||||
if not validate_pair(trading_pair):
|
||||
print("The input is invalid")
|
||||
|
|
@ -573,9 +568,7 @@ if __name__=="__main__":
|
|||
url = f"{base_url}{port}/import_pair"
|
||||
base,quote = trading_pair.split("/")
|
||||
parameters = {"base": base,
|
||||
"quote": quote,
|
||||
"forced_tp_id": forced_tp_id,
|
||||
"forced_so_id": forced_so_id}
|
||||
"quote": quote}
|
||||
print(json.loads(requests.post(url, headers=headers, json=parameters).content))
|
||||
input("Press ENTER to continue ")
|
||||
|
||||
|
|
@ -798,20 +791,6 @@ if __name__=="__main__":
|
|||
input("Press ENTER to continue ")
|
||||
|
||||
elif command==70:
|
||||
print("reload_safety_order reloads the safety order to the reader using the order id present in the status dictionary")
|
||||
trading_pair = input("Input trader in the format BASE/QUOTE: ").upper()
|
||||
if not validate_pair(trading_pair):
|
||||
print("The input is invalid")
|
||||
break
|
||||
if input("Proceed? (Y/n) ") in ["Y","y",""]:
|
||||
url = f"{base_url}{port}/reload_safety_order"
|
||||
base,quote = trading_pair.split("/")
|
||||
parameters = {"base": base,
|
||||
"quote": quote}
|
||||
print(json.loads(requests.post(url, headers=headers, json=parameters).content))
|
||||
input("Press ENTER to continue ")
|
||||
|
||||
elif command==71:
|
||||
print("Views the old_long information")
|
||||
trading_pair = input("Input trader in the format BASE/QUOTE: ").upper()
|
||||
if not validate_pair(trading_pair):
|
||||
|
|
@ -824,7 +803,7 @@ if __name__=="__main__":
|
|||
print(json.loads(requests.get(url,headers=headers).content))
|
||||
input("Press ENTER to continue ")
|
||||
|
||||
elif command==72:
|
||||
elif command==71:
|
||||
print("Returns the price target to reach to switch to long mode")
|
||||
trading_pair = input("Input trader in the format BASE/QUOTE: ").upper()
|
||||
if not validate_pair(trading_pair):
|
||||
|
|
@ -836,7 +815,7 @@ if __name__=="__main__":
|
|||
print(json.loads(requests.get(url,headers=headers).content))
|
||||
input("Press ENTER to continue ")
|
||||
|
||||
elif command==73:
|
||||
elif command==72:
|
||||
print("Reloads from disk the configuration file of a trader")
|
||||
trading_pair = input("Input trader in the format BASE/QUOTE: ").upper()
|
||||
if not validate_pair(trading_pair):
|
||||
|
|
@ -850,7 +829,7 @@ if __name__=="__main__":
|
|||
print(json.loads(requests.post(url, headers=headers, json=parameters).content))
|
||||
input("Press ENTER to continue ")
|
||||
|
||||
elif command==74:
|
||||
elif command==73:
|
||||
print("toggle_liquidate_after_switch enables or disables the liquidation after an automatic switch to long of a short trader")
|
||||
print("This is only valid in a short trader, of course.")
|
||||
trading_pair = input("Input trader in the format BASE/QUOTE: ").upper()
|
||||
|
|
@ -865,7 +844,7 @@ if __name__=="__main__":
|
|||
print(json.loads(requests.post(url, headers=headers, json=parameters).content))
|
||||
input("Press ENTER to continue ")
|
||||
|
||||
elif command==75:
|
||||
elif command==74:
|
||||
print("Returns the amount of safety orders that can be added to a short trader with the available funds")
|
||||
trading_pair = input("Input trader in the format BASE/QUOTE: ").upper()
|
||||
if not validate_pair(trading_pair):
|
||||
|
|
|
|||
Loading…
Reference in New Issue