From 25f721301b5db3f8c97d8ec7313f23182ffbdddc Mon Sep 17 00:00:00 2001 From: 4TT1L4 <2914096+4TT1L4@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:36:46 +0200 Subject: [PATCH] [MAINNET] Test BB strategy #24 --- api.py | 7 +++- app.py | 4 +-- compose.yaml | 9 +++-- strategies/bollinger_bands_strategy.py | 50 +++++++++++++------------- 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/api.py b/api.py index 23e5d2c..eee4342 100644 --- a/api.py +++ b/api.py @@ -61,7 +61,7 @@ def get_own_orders(self, market_id : str): return cast(OrderBookInfo, self.process_response(response)) def get_price_history(self, market_id : str, resolution : str, from_date : str | Unset = UNSET, until_date: Unset | str = UNSET, sort="asc", limit=1000): - response: Response[ErrorResponse | List[MarketOHLC]] = get_historical_prices_maestro_market_dex.sync_detailed(client=self.client, market=market_id, dex="genius-yield", resolution=resolution, from_=from_date, to=until_date) + response: Response[ErrorResponse | List[MarketOHLC]] = get_historical_prices_maestro_market_dex.sync_detailed(client=self.client, market=market_id, dex="genius-yield", resolution=resolution, from_=from_date, to=until_date, sort=sort, limit=limit) return cast(List[MarketOHLC], self.process_response(response)) def get_market_price(self, market_id : str): @@ -70,6 +70,10 @@ def get_market_price(self, market_id : str): def place_order(self, offered_amount : str, offered_token : str, price_token : str, price_amount : str): self.logger.info(f"[PLACE-ORDER] Placing order...") + self.logger.info(f"[PLACE-ORDER] offered_amount: {offered_amount}") + self.logger.info(f"[PLACE-ORDER] offered_token: {offered_token}") + self.logger.info(f"[PLACE-ORDER] price_token: {price_token}") + self.logger.info(f"[PLACE-ORDER] price_amount: {price_amount}") body = PostOrderParameters() body.offer_amount = offered_amount body.offer_token = offered_token @@ -83,6 +87,7 @@ def place_order(self, offered_amount : str, offered_token : str, price_token : s def cancel_order(self, order_reference : str): self.logger.info(f"[CANCEL-ORDER] Canceling order...") + self.logger.info(f"[CANCEL-ORDER] order_reference: {order_reference}") body = DeleteOrderParameters() body.address=self.own_address body.order_references=[order_reference] diff --git a/app.py b/app.py index ef4a1c0..e05f7f2 100644 --- a/app.py +++ b/app.py @@ -99,10 +99,10 @@ def worker(): try: strategy.execute(api_client, CONFIG, logger) except Exception: - logger.error(f" ❌ Strategy exeuction has failed with an exception. ❌ ") + logger.error(f" ❌ Strategy execution has failed with an exception. ❌ ") logger.exception(" ❌ Exception occurred:") else: - logger.info(f"[OK] Strategy exeuction has been finished ✅ ") + logger.info(f"[OK] Strategy execution has been finished ✅ ") finally: end_time = time.time() execution_time = end_time - start_time diff --git a/compose.yaml b/compose.yaml index 447c5c7..dc0bfe2 100644 --- a/compose.yaml +++ b/compose.yaml @@ -14,7 +14,7 @@ services: coreProvider: maestroToken: <> turboSubmit: false - networkId: "preprod" # supported: mainnet ot preprod + networkId: "mainnet" # supported: mainnet ot preprod logging: - type: {tag: stderr} severity: "Debug" # Options: Debug, Info, Warning or Error @@ -72,8 +72,11 @@ services: STRATEGY: bollinger_bands_strategy CONFIG: | BASE_ASSET: lovelace - TARGET_ASSET: c6e65ba7878b2f8ea0ad39287d3e2fd256dc5c4160fc19bdf4c4d87e.7447454e53 - POSITION_SIZE_LOVELACES: 10000000 + # GENS for MAINNET: + TARGET_ASSET: dda5fdb1002f7389b33e036b6afee82a8189becb6cba852e8b79b4fb.0014df1047454e53 + # tGENS for PRERPOD: + # TARGET_ASSET: c6e65ba7878b2f8ea0ad39287d3e2fd256dc5c4160fc19bdf4c4d87e.7447454e53 + POSITION_SIZE_LOVELACES: 1000000 STD_DEV_MULTIPLIER: 1.5 PERIOD: 5 depends_on: diff --git a/strategies/bollinger_bands_strategy.py b/strategies/bollinger_bands_strategy.py index d266316..dc985ab 100644 --- a/strategies/bollinger_bands_strategy.py +++ b/strategies/bollinger_bands_strategy.py @@ -52,7 +52,7 @@ def __init__(self, api_client, CONFIG, logger): # Create the BB strategy instance with the config: self.bb = BB(self.period, self.std_dev_multiplier) - def place_buy_order(self, api_client, logger): + def place_buy_order(self, api_client, logger, price): logger.info(" ⚙️ Placing BUY order...") if not self.buy_order_ref == None: @@ -70,26 +70,23 @@ def place_buy_order(self, api_client, logger): logger.exception(f" > ⚠️ [FAILED] could not cancel order: {self.sell_order_ref} ⚠️") logger.error(f" > Exception! ") try: - HUNDRED_ADA=100000000 - balance_available = int(api_client.get_balances().get(self.base_asset, 0)) - HUNDRED_ADA + balance_available = int(api_client.get_balances().get(self.base_asset, 0)) logger.debug(f" > balance_available : {balance_available}") logger.debug(f" > self.position_size: {self.position_size}") - # Get best ask price: - order_book = api_client.get_order_book(self.market) - best_ask_price = float(order_book.asks[-1].price) - order_size = min(self.position_size, balance_available) / float(best_ask_price) + order_size = min(self.position_size, balance_available) if not order_size: logger.info(" ⚠️ Insufficient balance to place BUY order! ⚠️") return - logger.info(f" > Place BUY order: {order_size}...") offered_amount = int(math.floor(order_size)) + + logger.info(f" > Place BUY order: {offered_amount} at price {price}...") response = api_client.place_order( offered_amount=f"{offered_amount}", offered_token=self.base_asset, price_token=self.target_asset, - price_amount=f"{int(math.floor(offered_amount * best_ask_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 @@ -97,7 +94,7 @@ def place_buy_order(self, api_client, logger): logger.error(" > ⚠️ [FAILED] Could not place BUY order. ⚠️") logger.exception(f" > Exception! ") - def place_sell_order(self, api_client, logger): + def place_sell_order(self, api_client, logger, price): logger.info("Placing SELL order...") if not self.sell_order_ref == None: @@ -116,22 +113,21 @@ def place_sell_order(self, api_client, logger): logger.error(f" > ⚠️ [FAILED] could not cancel order: {self.buy_order_ref} ⚠️") logger.exception(f" > Exception! ") try: - balance_available = api_client.get_balances().get(self.target_asset, 0) + balance_available = int(api_client.get_balances().get(self.target_asset, 0)) logger.info(f" > balance_available : {balance_available}") - - order_book = api_client.get_order_book(self.market) - best_bid_price = order_book.bids[-1].price - order_size = min(self.position_size, balance_available) / float(best_bid_price) + order_size = min(self.position_size / price, balance_available) + logger.info(f" > order_size : {order_size}") + logger.info(f" > price : {price}") if not order_size: logger.info("⚠️ Insufficient balance to place SELL order! ⚠️") return - logger.info(f" > Place SELL order: {order_size} at ...") + logger.info(f" > Place SELL order: {order_size} at price {price}...") response = api_client.place_order( offered_amount=f"{int(math.floor(order_size))}", offered_token=self.target_asset, - price_token=self.target_asset, - price_amount=f"{int(math.floor(best_bid_price))}" + price_token=self.base_asset, + 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 @@ -144,7 +140,7 @@ def process_candle(self, candle): self.logger.info(f" > processsing 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.") + self.logger.info(f" > Candle has already been processsed. Nothing to do.") return self.last_candle = candle @@ -171,14 +167,18 @@ def process_candle(self, candle): self.logger.info(f" > Upper band: {self.bb[-1].ub}") self.logger.info(f" > Lower band: {self.bb[-1].lb}") + if self.initialized == False: + self.logger.info(f" -> Initializaion phase. Do not place orders yet.") + return + # 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) + self.logger.info(f" -> Price moved below the lower band -> BUY! 🛒 🛒 🛒 ") + 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) + 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} ") @@ -190,10 +190,12 @@ def execute(self, api_client : Api, CONFIG, logger): if self.last_execution_time is None: logger.info("Executing for the first time") - candles = api_client.get_price_history(self.market, resolution="1m", sort="asc", limit=self.period) + candles = api_client.get_price_history(self.market, resolution="1m", sort="asc", limit=self.period*5) for candle in candles[:-1]: self.process_candle(candle) time.sleep(1) + self.initialized = True + self.last_candle=None else: time_since_last_execution = (current_time - self.last_execution_time).total_seconds() logger.info(f"Last executed: {self.last_execution_time}")