def process_withdrawals(self): # Set wallet from relevant currency according to side to_wallet = ( self.buda.wallets.base if self.side == Side.BUY else self.buda.wallets.quote ) for deposit in self.deposits.values(): # Load money amounts original_amount = Money.loads(deposit["amounts"]["original_amount"]) converted_amount = Money.loads(deposit["amounts"]["converted_amount"]) converted_value = Money.loads(deposit["amounts"]["converted_value"]) remaining = original_amount - converted_amount if ( self.side == Side.BUY ): # Change remaining amount to base currency for minimum order amount check remaining = ( self.buda.fetch_order_book().quote(self.side, remaining).base_amount ) # Filter deposits already converted and pending withdrawal original_amount_is_converted = remaining < self.buda.min_order_amount if ( deposit["status"] == TxStatus.OK.value and deposit["pending_withdrawal"] and original_amount_is_converted ): withdrawal_amount = truncate_money(converted_value) available = to_wallet.fetch_balance().free if ( withdrawal_amount <= available ): # We cannot withdraw more than available balance w = to_wallet.request_withdrawal( withdrawal_amount, self.to_address, subtract_fee=True ) if ( w.status == TxStatus.PENDING ): # Check state to set and store updated values self.log.info( f"{self.to_currency} withdrawal request received, updating store values" ) deposit["pending_withdrawal"] = False self.store.set(self.from_currency + "_deposits", self.deposits) else: self.log.warning("Withdrawal failed") else: self.log.warning( f"Available balance not enough for withdrawal amount {withdrawal_amount}" )
def process_conversions(self): for deposit in self.deposits.values(): # Calculate remaining amount to convert original_amount = Money.loads(deposit["amounts"]["original_amount"]) converted_amount = Money.loads(deposit["amounts"]["converted_amount"]) converted_value = Money.loads(deposit["amounts"]["converted_value"]) remaining = original_amount - converted_amount if ( self.side == Side.BUY ): # Change remaining amount to base currency for order creation purposes remaining = ( self.buda.fetch_order_book().quote(self.side, remaining).base_amount ) if ( deposit["status"] == TxStatus.OK.value and remaining > self.buda.min_order_amount ): remaining = truncate_money(remaining) # Convert remaining amount using market order order = self.buda.place_market_order(self.side, remaining) # Wait for traded state to set updated values if order: self.log.info( f"{self.side} market order placed, waiting for traded state" ) while order.status != OrderStatus.CLOSED: order = self.buda.fetch_order(order.id) maya.time.sleep(1) self.log.info(f"{self.side} order traded, updating store values") if self.side == Side.BUY: converted_amount += order.cost converted_value += order.filled - order.fee if self.side == Side.SELL: converted_amount += order.filled converted_value += order.cost - order.fee deposit["orders"].append( order.id ) # Save related orders for debugging # Save new values __str__ deposit["amounts"]["converted_amount"] = repr(converted_amount) deposit["amounts"]["converted_value"] = repr(converted_value) # Store all deposits self.store.set(self.from_currency + "_deposits", self.deposits)
def _algorithm(self): # Update candle data and TA indicators self.log.info( f"Getting trades from {self.reference.name} {self.reference.market.code}" ) from_time = maya.when("1 day ago").epoch trades = self.get_trades(from_time) # Create pandas DataFrame from trades and set date as index df = pd.DataFrame(trades) df.index = df.timestamp.apply(lambda x: pd.datetime.utcfromtimestamp(x)) # Build 5min candles from trades DataFrame [open, high, close, low] df = df.rate.resample(self.candle_interval).ohlc() # Calculate Bollinger Bands and RSI from talib df["bb_lower"], df["bb_middle"], df["bb_upper"] = talib.BBANDS( df.close, timeperiod=self.bbands_periods ) df["rsi"] = talib.RSI(df.close, timeperiod=self.rsi_periods) lower = self.truncate_price(df.bb_lower[-1]) middle = self.truncate_price(df.bb_middle[-1]) upper = self.truncate_price(df.bb_upper[-1]) self.log.info(f"BB_lower: {lower} | BB_middle: {middle} | BB_upper: {upper}") self.log.info(f"RSI: {df.rsi[-1]:.2f}") # Check if our position is open or closed if self.position["status"] == "closed": # Try conditions to open position self.log.info(f"Position is closed, checking to open") if df.close[-1] < df.bb_lower[-1] and df.rsi[-1] < self.rsi_oversold: # Last price is lower than the lower BBand and RSI is oversold, BUY! self.log.info(f"Market oversold! BUY!") amount = self.get_amount(Side.BUY) if amount >= self.buda.min_order_amount: tx = self.buda.place_market_order(Side.BUY, amount) self.position = { "status": "open", "side": Side.BUY.value, "amount": repr(tx.amount), } else: self.log.warning( f"Available amount is lower than minimum order amount" ) elif df.close[-1] > df.bb_upper[-1] and df.rsi[-1] > self.rsi_overbought: # Last price is higher than the upper BBand and RSI is overbought, SELL! self.log.info(f"Market overbought! SELL!") amount = self.get_amount(Side.SELL) if amount >= self.buda.min_order_amount: tx = self.buda.place_market_order(Side.SELL, amount) self.position = { "status": "open", "side": Side.SELL.value, "amount": repr(tx.amount), } else: self.log.warning( f"Available amount is lower than minimum order amount" ) else: self.log.info(f"Market conditions unmet to open position") else: self.log.info(f"Position is open, checking to close") if self.position["side"] == Side.BUY.value and df.rsi[-1] >= 30: # RSI is back to normal, close Buy position self.log.info(f"Market is back to normal, closing position") amount = Money.loads(self.position["amount"]) if amount >= self.buda.min_order_amount: tx = self.buda.place_market_order(Side.SELL, amount) remaining = amount - tx.amount if remaining < self.buda.min_order_amount: self.position = {"status": "closed"} else: self.position["amount"] = remaining else: self.log.warning( f"Available amount is lower than minimum order amount" ) elif self.position["side"] == Side.SELL.value and df.rsi[-1] <= 70: # RSI is back to normal, close Sell position self.log.info(f"Market is back to normal, closing position") amount = Money.loads(self.position["amount"]) if amount >= self.buda.min_order_amount: tx = self.buda.place_market_order(Side.BUY, amount) remaining = amount - tx.amount if remaining < self.buda.min_order_amount: self.position = {"status": "closed"} else: self.position["amount"] = repr(remaining) else: self.log.warning( f"Available amount is lower than minimum order amount" ) else: self.log.info(f"Market conditions unmet to close position") self.store.set("position", self.position)