From c463ed34b867c0320bc3ad0a8889cb15cca7eee1 Mon Sep 17 00:00:00 2001 From: 4TT1L4 <2914096+4TT1L4@users.noreply.github.com> Date: Wed, 22 May 2024 09:57:40 +0200 Subject: [PATCH 1/5] [BB] Improve order management #34 --- strategies/bollinger_bands_strategy.py | 102 ++++++++++++++----------- 1 file changed, 58 insertions(+), 44 deletions(-) diff --git a/strategies/bollinger_bands_strategy.py b/strategies/bollinger_bands_strategy.py index dc985ab..3d9a4ac 100644 --- a/strategies/bollinger_bands_strategy.py +++ b/strategies/bollinger_bands_strategy.py @@ -8,7 +8,7 @@ class bollinger_bands_strategy: def __init__(self, api_client, CONFIG, logger): logger.info(" > init: bollinger_bands_strategy instance created.") - + logger.info("========================================================================") logger.info(" ") logger.info(" ⚠️ WARNING! ⚠️ ") @@ -25,13 +25,10 @@ def __init__(self, api_client, CONFIG, logger): self.start_time = datetime.now() self.counter = 0 self.last_execution_time = None - self.last_order_ref=None self._values = (None, None) - self.api_client=api_client - self.logger=logger + self.api_client : Api = api_client + self.logger = logger self.initialized = False - self.sell_order_ref = None - self.buy_order_ref = None self.last_candle = None # Strategy configuration: @@ -55,20 +52,10 @@ def __init__(self, api_client, CONFIG, logger): def place_buy_order(self, api_client, logger, price): logger.info(" ⚙️ Placing BUY order...") - if not self.buy_order_ref == None: - logger.info(f" > Already placed BUY order. Nothing to do.") - return - - if self.sell_order_ref == None: - logger.debug(f" > No SELL order. Nothing to cancel.") - else: - try: - response = api_client.cancel_order(self.sell_order_ref) - logger.info(f" > [OK] Canceled SELL order: {self.sell_order_ref}") - self.sell_order_ref = None - except: - logger.exception(f" > ⚠️ [FAILED] could not cancel order: {self.sell_order_ref} ⚠️") - logger.error(f" > Exception! ") + logger.info(" > Cancel all SELL orders...") + self.cancel_sell_orders() + logger.info(" > [OK] Canceled all SELL orders.") + try: balance_available = int(api_client.get_balances().get(self.base_asset, 0)) logger.debug(f" > balance_available : {balance_available}") @@ -89,29 +76,17 @@ def place_buy_order(self, api_client, logger, price): price_amount=f"{int(math.floor(offered_amount / price))}" ) logger.info(f" > [OK] PLACED NEW BUY ORDER: {response.order_ref}") - self.buy_order_ref=response.order_ref except: logger.error(" > ⚠️ [FAILED] Could not place BUY order. ⚠️") logger.exception(f" > Exception! ") def place_sell_order(self, api_client, logger, price): logger.info("Placing SELL order...") - - if not self.sell_order_ref == None: - logger.info(f" > Already placed SELL order. Nothing to do.") - return - if self.buy_order_ref == None: - logger.debug(f" > No BUY order placed. Nothing to cancel.") - else: - try: - logger.info(f" ⚙️ Canceling BUY order: {self.buy_order_ref}") - response = api_client.cancel_order(self.buy_order_ref) - logger.info(f" > [OK] Canceled BUY order: {self.buy_order_ref}") - self.buy_order_ref = None - except: - logger.error(f" > ⚠️ [FAILED] could not cancel order: {self.buy_order_ref} ⚠️") - logger.exception(f" > Exception! ") + logger.info(" > Cancel all BUY orders...") + self.cancel_buy_orders() + logger.info(" > [OK] Canceled all BUY orders.") + try: balance_available = int(api_client.get_balances().get(self.target_asset, 0)) logger.info(f" > balance_available : {balance_available}") @@ -130,11 +105,41 @@ def place_sell_order(self, api_client, logger, price): price_amount=f"{int(math.floor(order_size * price))}" ) logger.info(f" > [OK] PLACED NEW SELL ORDER: {response.order_ref}") - self.sell_order_ref=response.order_ref + self.sell_order_ref = response.order_ref except: logger.error(f" > ⚠️ [FAILED] Could not place SELL order. ⚠️") logger.exception(f" > Exception! ") + def cancel_buy_orders(self): + self.cancel_orders("bid") + + def cancel_sell_orders(self): + self.cancel_orders("ask") + + def cancel_orders(self, side): + + while True: + orders = [] + own_orders = self.api_client.get_own_orders(self.market) + if (side == "ask"): + orders = own_orders.asks + else: + orders = own_orders.bids + + if len(orders) == 0: + return + else: + self.logger.info(f" Remaining {side} orders: {len(orders)}.") + + order = orders[0] + try: + self.logger.info(f" ⚙️ Canceling order: {order.output_reference}") + self.api_client.cancel_order(order.output_reference) + self.logger.info(f" > [OK] Canceled order: {order.output_reference}") + except: + self.logger.error(f" > ⚠️ [FAILED] could not cancel order: {order.output_reference} ⚠️") + self.logger.exception(f" > Exception! ") + def process_candle(self, candle): self.logger.info(f"--------------------------------------------------------------------------------") self.logger.info(f" > processsing candle - timestamp: {candle.timestamp} - base_close: {candle.base_close}") @@ -158,9 +163,6 @@ def process_candle(self, candle): self.logger.info(f" Bollinger Bands: Initializing... ⚙️ ⏳ ") self.logger.info(f" > Upper band: Not available.") self.logger.info(f" > Lower band: Not available.") - self.logger.info(f" Orders: ") - self.logger.info(f" > On-Chain BUY order: {self.buy_order_ref} ") - self.logger.info(f" > On-Chain SELL order: {self.sell_order_ref} ") return self.logger.info(f" Bollinger Bands: ") @@ -179,11 +181,23 @@ def process_candle(self, candle): elif self._values[-2] <= self.bb[-2].ub and self._values[-1] > self.bb[-1].ub: self.logger.info(f" -> Price moved above the upper band -> SELL! 💲 💲 💲 ") self.place_sell_order(self.api_client, self.logger, candle.base_close) - - self.logger.info(f" Orders: ") - self.logger.info(f" > On-Chain BUY order: {self.buy_order_ref} ") - self.logger.info(f" > On-Chain SELL order: {self.sell_order_ref} ") + self.log_orders() + + def log_orders(self): + own_orders = self.api_client.get_own_orders(self.market) + + self.logger.info(" Orders:") + + if (len(own_orders.asks) + len(own_orders.bids)) == 0: + self.logger.info(f" > No orders.") + return + + for sell_order in own_orders.asks: + self.logger.info(f" > SELL: {sell_order.output_reference} ") + + for sell_order in own_orders.bids: + self.logger.info(f" > BUY: {sell_order.output_reference} ") def execute(self, api_client : Api, CONFIG, logger): current_time = datetime.now() From f8b1a92edaaafc8110838005cc12ef3281aeedda Mon Sep 17 00:00:00 2001 From: 4TT1L4 <2914096+4TT1L4@users.noreply.github.com> Date: Wed, 22 May 2024 10:30:39 +0200 Subject: [PATCH 2/5] [BB] Improve order management #34 --- strategies/bollinger_bands_strategy.py | 45 ++++++++++++-------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/strategies/bollinger_bands_strategy.py b/strategies/bollinger_bands_strategy.py index 3d9a4ac..c1d1006 100644 --- a/strategies/bollinger_bands_strategy.py +++ b/strategies/bollinger_bands_strategy.py @@ -1,6 +1,6 @@ from datetime import datetime import math -from api import Api +from api import Api, ApiException import time from talipp.indicators import BB @@ -22,8 +22,6 @@ def __init__(self, api_client, CONFIG, logger): logger.info("========================================================================") # Internal state: - self.start_time = datetime.now() - self.counter = 0 self.last_execution_time = None self._values = (None, None) self.api_client : Api = api_client @@ -52,9 +50,7 @@ def __init__(self, api_client, CONFIG, logger): def place_buy_order(self, api_client, logger, price): logger.info(" ⚙️ Placing BUY order...") - logger.info(" > Cancel all SELL orders...") self.cancel_sell_orders() - logger.info(" > [OK] Canceled all SELL orders.") try: balance_available = int(api_client.get_balances().get(self.base_asset, 0)) @@ -83,9 +79,7 @@ def place_buy_order(self, api_client, logger, price): def place_sell_order(self, api_client, logger, price): logger.info("Placing SELL order...") - logger.info(" > Cancel all BUY orders...") self.cancel_buy_orders() - logger.info(" > [OK] Canceled all BUY orders.") try: balance_available = int(api_client.get_balances().get(self.target_asset, 0)) @@ -111,10 +105,14 @@ def place_sell_order(self, api_client, logger, price): logger.exception(f" > Exception! ") def cancel_buy_orders(self): + self.logger.info(" > Cancel all BUY orders...") self.cancel_orders("bid") + self.logger.info(" > [OK] Canceled all BUY orders.") def cancel_sell_orders(self): + self.logger.info(" > Cancel all SELL orders...") self.cancel_orders("ask") + self.logger.info(" > [OK] Canceled all SELL orders.") def cancel_orders(self, side): @@ -136,13 +134,15 @@ def cancel_orders(self, side): self.logger.info(f" ⚙️ Canceling order: {order.output_reference}") self.api_client.cancel_order(order.output_reference) self.logger.info(f" > [OK] Canceled order: {order.output_reference}") - except: + except ApiException: self.logger.error(f" > ⚠️ [FAILED] could not cancel order: {order.output_reference} ⚠️") self.logger.exception(f" > Exception! ") def process_candle(self, candle): - self.logger.info(f"--------------------------------------------------------------------------------") - self.logger.info(f" > processsing candle - timestamp: {candle.timestamp} - base_close: {candle.base_close}") + if self.initialized: + self.logger.info(f" > processsing candle - timestamp: {candle.timestamp} - base_close: {candle.base_close}") + else: + self.logger.info(f" > processsing init candle - timestamp: {candle.timestamp} - base_close: {candle.base_close}") if (not self.last_candle == None) and (self.last_candle.timestamp == candle.timestamp): self.logger.info(f" > Candle has already been processsed. Nothing to do.") @@ -157,15 +157,13 @@ def process_candle(self, candle): # Keep a small window of values to check if there is a crossover. self._values = (self._values[-1], value) - self.logger.debug(f" > self.bb.input_values: {self.bb.input_values}") - if len(self.bb) < 2 or self.bb[-1] == None or self.bb[-2] == None: - self.logger.info(f" Bollinger Bands: Initializing... ⚙️ ⏳ ") + self.logger.info(f" BOLLINGER BANDS: Initializing... ⚙️ ⏳ ") self.logger.info(f" > Upper band: Not available.") self.logger.info(f" > Lower band: Not available.") return - self.logger.info(f" Bollinger Bands: ") + self.logger.info(f" BOLLINGER BANDS: ") self.logger.info(f" > Upper band: {self.bb[-1].ub}") self.logger.info(f" > Lower band: {self.bb[-1].lb}") @@ -187,27 +185,30 @@ def process_candle(self, candle): def log_orders(self): own_orders = self.api_client.get_own_orders(self.market) - self.logger.info(" Orders:") + self.logger.info(" ON-CHAIN ORDERS:") if (len(own_orders.asks) + len(own_orders.bids)) == 0: self.logger.info(f" > No orders.") return for sell_order in own_orders.asks: - self.logger.info(f" > SELL: {sell_order.output_reference} ") + self.logger.info(f" > SELL: {sell_order.output_reference}") - for sell_order in own_orders.bids: - self.logger.info(f" > BUY: {sell_order.output_reference} ") + for buy_order in own_orders.bids: + self.logger.info(f" > BUY: {buy_order.output_reference} ") def execute(self, api_client : Api, CONFIG, logger): current_time = datetime.now() if self.last_execution_time is None: - logger.info("Executing for the first time") + logger.info("Executing for the first time -> initialize.") candles = api_client.get_price_history(self.market, resolution="1m", sort="asc", limit=self.period*5) for candle in candles[:-1]: + self.logger.info(f"--------------------------------------------------------------------------------") self.process_candle(candle) time.sleep(1) + logger.info(" > [OK] Initialized.") + logger.info("========================================================================") self.initialized = True self.last_candle=None else: @@ -218,16 +219,10 @@ def execute(self, api_client : Api, CONFIG, logger): self.last_execution_time = current_time # Update last execution time self.initialized = True - self.counter += 1 - logger.info(f" > Counter: {self.counter}") - try: get_market_price = api_client.get_market_price(self.market) candle=get_market_price[0] - logger.info(f" > Base closing price: {candle.base_close}") self.process_candle(candle) except: logger.error(f" > ⚠️ [FAILED] could not process candle ⚠️") logger.exception(f" > Exception! ") - - logger.info(f" > EXECUTION FINISHED.") From 750818e6b1b4ff30b9e4f83c859dbd265d9083f7 Mon Sep 17 00:00:00 2001 From: 4TT1L4 <2914096+4TT1L4@users.noreply.github.com> Date: Wed, 22 May 2024 10:46:58 +0200 Subject: [PATCH 3/5] [BB] Improve order management #34 --- strategies/bollinger_bands_strategy.py | 29 +++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/strategies/bollinger_bands_strategy.py b/strategies/bollinger_bands_strategy.py index c1d1006..d7ac947 100644 --- a/strategies/bollinger_bands_strategy.py +++ b/strategies/bollinger_bands_strategy.py @@ -50,8 +50,6 @@ def __init__(self, api_client, CONFIG, logger): def place_buy_order(self, api_client, logger, price): logger.info(" ⚙️ Placing BUY order...") - self.cancel_sell_orders() - try: balance_available = int(api_client.get_balances().get(self.base_asset, 0)) logger.debug(f" > balance_available : {balance_available}") @@ -81,6 +79,10 @@ def place_sell_order(self, api_client, logger, price): self.cancel_buy_orders() + if len(self.get_sell_orders()) > 0: + logger.info("Already placed SELL order. Nothing to do.") + return + try: balance_available = int(api_client.get_balances().get(self.target_asset, 0)) logger.info(f" > balance_available : {balance_available}") @@ -104,6 +106,14 @@ def place_sell_order(self, api_client, logger, price): logger.error(f" > ⚠️ [FAILED] Could not place SELL order. ⚠️") logger.exception(f" > Exception! ") + def get_buy_orders(self): + own_orders = self.api_client.get_own_orders(self.market) + return own_orders.bids + + def get_sell_orders(self): + own_orders = self.api_client.get_own_orders(self.market) + return own_orders.asks + def cancel_buy_orders(self): self.logger.info(" > Cancel all BUY orders...") self.cancel_orders("bid") @@ -115,7 +125,6 @@ def cancel_sell_orders(self): self.logger.info(" > [OK] Canceled all SELL orders.") def cancel_orders(self, side): - while True: orders = [] own_orders = self.api_client.get_own_orders(self.market) @@ -171,14 +180,24 @@ def process_candle(self, candle): self.logger.info(f" -> Initializaion phase. Do not place orders yet.") return + self.place_buy_order(self.api_client, self.logger, candle.base_close) + # Price moved below lower band ? if self._values[-2] >= self.bb[-2].lb and self._values[-1] < self.bb[-1].lb: self.logger.info(f" -> Price moved below the lower band -> BUY! 🛒 🛒 🛒 ") - self.place_buy_order(self.api_client, self.logger, candle.base_close) + self.cancel_sell_orders() + if len(self.get_buy_orders()) > 0: + self.logger.info(" > Already placed BUY order. Nothing to do.") + else: + self.place_buy_order(self.api_client, self.logger, candle.base_close) # Price moved above upper band ? elif self._values[-2] <= self.bb[-2].ub and self._values[-1] > self.bb[-1].ub: self.logger.info(f" -> Price moved above the upper band -> SELL! 💲 💲 💲 ") - self.place_sell_order(self.api_client, self.logger, candle.base_close) + self.cancel_buy_orders() + if len(self.get_sell_orders()) > 0: + self.logger.info(" > Already placed SELL order. Nothing to do.") + else: + self.place_sell_order(self.api_client, self.logger, candle.base_low) self.log_orders() From e7fed7bc4f2d7022347f2dcac35257b122f21004 Mon Sep 17 00:00:00 2001 From: 4TT1L4 <2914096+4TT1L4@users.noreply.github.com> Date: Wed, 22 May 2024 10:50:26 +0200 Subject: [PATCH 4/5] [BB] Improve order management #34 --- strategies/bollinger_bands_strategy.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/strategies/bollinger_bands_strategy.py b/strategies/bollinger_bands_strategy.py index d7ac947..8c10aed 100644 --- a/strategies/bollinger_bands_strategy.py +++ b/strategies/bollinger_bands_strategy.py @@ -75,13 +75,7 @@ def place_buy_order(self, api_client, logger, price): logger.exception(f" > Exception! ") def place_sell_order(self, api_client, logger, price): - logger.info("Placing SELL order...") - - self.cancel_buy_orders() - - if len(self.get_sell_orders()) > 0: - logger.info("Already placed SELL order. Nothing to do.") - return + logger.info(" ⚙️ Placing SELL order...") try: balance_available = int(api_client.get_balances().get(self.target_asset, 0)) From d63186764aa0166949dc78671869857a5bff00bc Mon Sep 17 00:00:00 2001 From: 4TT1L4 <2914096+4TT1L4@users.noreply.github.com> Date: Wed, 22 May 2024 10:51:27 +0200 Subject: [PATCH 5/5] [BB] Improve order management #34 --- strategies/bollinger_bands_strategy.py | 1 - 1 file changed, 1 deletion(-) diff --git a/strategies/bollinger_bands_strategy.py b/strategies/bollinger_bands_strategy.py index 8c10aed..265d021 100644 --- a/strategies/bollinger_bands_strategy.py +++ b/strategies/bollinger_bands_strategy.py @@ -95,7 +95,6 @@ def place_sell_order(self, api_client, logger, price): price_amount=f"{int(math.floor(order_size * price))}" ) logger.info(f" > [OK] PLACED NEW SELL ORDER: {response.order_ref}") - self.sell_order_ref = response.order_ref except: logger.error(f" > ⚠️ [FAILED] Could not place SELL order. ⚠️") logger.exception(f" > Exception! ")