Skip to content

Commit

Permalink
Merge pull request #50 from geniusyield/34-bb-improve-order-management
Browse files Browse the repository at this point in the history
[BB] Improve order management #34
  • Loading branch information
4TT1L4 authored May 22, 2024
2 parents 5251934 + d631867 commit c3dedeb
Showing 1 changed file with 84 additions and 63 deletions.
147 changes: 84 additions & 63 deletions strategies/bollinger_bands_strategy.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from datetime import datetime
import math
from api import Api
from api import Api, ApiException
import time

from talipp.indicators import BB

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! ⚠️ ")
Expand All @@ -22,16 +22,11 @@ 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.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:
Expand All @@ -55,20 +50,6 @@ 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! ")
try:
balance_available = int(api_client.get_balances().get(self.base_asset, 0))
logger.debug(f" > balance_available : {balance_available}")
Expand All @@ -89,29 +70,13 @@ 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
logger.info(" ⚙️ Placing SELL order...")

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! ")
try:
balance_available = int(api_client.get_balances().get(self.target_asset, 0))
logger.info(f" > balance_available : {balance_available}")
Expand All @@ -130,14 +95,56 @@ 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! ")

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")
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):
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 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.")
Expand All @@ -152,48 +159,68 @@ 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.")
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: ")
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}")

if self.initialized == False:
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.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.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()

def log_orders(self):
own_orders = self.api_client.get_own_orders(self.market)

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}")

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:
Expand All @@ -204,16 +231,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.")

0 comments on commit c3dedeb

Please sign in to comment.