diff --git a/README.md b/README.md index e070ead..d3a5cb2 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,8 @@ _Now when your alerts fire off they should go strait to your server and get proc |type | Market or Limit | |order_mode| Both(Stop Loss & Take Profit Orders Used), Profit ( Omly Take Profit Orders), Stop (Only Stop Loss orders)| |qty| amount of base currency to buy | +|qty_percent| optional percent of available quote-currency balance to use instead of qty | +|quote_coin / quote_currency| optional quote balance currency for qty_percent, for example USDT | |price| ticker in quote currency | |close_position| True or False | |cancel_orders|True or False | diff --git a/app.py b/app.py index d2a1b00..51bf8df 100644 --- a/app.py +++ b/app.py @@ -27,6 +27,23 @@ def validate_binance_api_key(exchange): with open('config.json') as config_file: config = json.load(config_file) +def calculate_percent_qty(balance, price, percent): + return (float(balance) * (float(percent) / 100)) / float(price) + +def get_bybit_wallet_balance(session, coin): + wallet_balance = session.get_wallet_balance(coin=coin) + result = wallet_balance.get('result', {}) + coin_balance = result.get(coin, result) + return coin_balance.get('available_balance') or coin_balance.get('wallet_balance') + +def get_bybit_order_qty(session, data, price): + if 'qty_percent' not in data: + return data['qty'] + + quote_coin = data.get('quote_coin') or data['symbol'][-4:] + balance = get_bybit_wallet_balance(session, quote_coin) + return calculate_percent_qty(balance, price, data['qty_percent']) + ############################################################################### # # This Section is for Exchange Validation @@ -114,11 +131,12 @@ def webhook(): else: price = 0 + current_price = session.latest_information_for_symbol(symbol=data['symbol'])['result'][0]['last_price'] + qty = get_bybit_order_qty(session, data, current_price) if data['order_mode'] == 'Both': take_profit_percent = float(data['take_profit_percent'])/100 stop_loss_percent = float(data['stop_loss_percent'])/100 - current_price = session.latest_information_for_symbol(symbol=data['symbol'])['result'][0]['last_price'] if data['side'] == 'Buy': take_profit_price = round(float(current_price) + (float(current_price) * take_profit_percent), 2) stop_loss_price = round(float(current_price) - (float(current_price) * stop_loss_percent), 2) @@ -130,12 +148,11 @@ def webhook(): print("Stop Loss Price: " + str(stop_loss_price)) session.place_active_order(symbol=data['symbol'], order_type=data['type'], side=data['side'], - qty=data['qty'], time_in_force="GoodTillCancel", reduce_only=False, + qty=qty, time_in_force="GoodTillCancel", reduce_only=False, close_on_trigger=False, price=price, take_profit=take_profit_price, stop_loss=stop_loss_price) elif data['order_mode'] == 'Profit': take_profit_percent = float(data['take_profit_percent'])/100 - current_price = session.latest_information_for_symbol(symbol=data['symbol'])['result'][0]['last_price'] if data['side'] == 'Buy': take_profit_price = round(float(current_price) + (float(current_price) * take_profit_percent), 2) elif data['side'] == 'Sell': @@ -143,11 +160,10 @@ def webhook(): print("Take Profit Price: " + str(take_profit_price)) session.place_active_order(symbol=data['symbol'], order_type=data['type'], side=data['side'], - qty=data['qty'], time_in_force="GoodTillCancel", reduce_only=False, + qty=qty, time_in_force="GoodTillCancel", reduce_only=False, close_on_trigger=False, price=price, take_profit=take_profit_price) elif data['order_mode'] == 'Stop': stop_loss_percent = float(data['stop_loss_percent'])/100 - current_price = session.latest_information_for_symbol(symbol=data['symbol'])['result'][0]['last_price'] if data['side'] == 'Buy': stop_loss_price = round(float(current_price) - (float(current_price) * stop_loss_percent), 2) elif data['side'] == 'Sell': @@ -155,12 +171,12 @@ def webhook(): print("Stop Loss Price: " + str(stop_loss_price)) session.place_active_order(symbol=data['symbol'], order_type=data['type'], side=data['side'], - qty=data['qty'], time_in_force="GoodTillCancel", reduce_only=False, + qty=qty, time_in_force="GoodTillCancel", reduce_only=False, close_on_trigger=False, price=price, stop_loss=stop_loss_price) else: session.place_active_order(symbol=data['symbol'], order_type=data['type'], side=data['side'], - qty=data['qty'], time_in_force="GoodTillCancel", reduce_only=False, + qty=qty, time_in_force="GoodTillCancel", reduce_only=False, close_on_trigger=False, price=price) return { @@ -170,23 +186,25 @@ def webhook(): ############################################################################## # Binance Futures ############################################################################## - if data['exchange'] == 'binance-futures': - if use_binance_futures: - bot = Bot() - bot.run(data) - return { - "status": "success", - "message": "Binance Futures Webhook Received!" - } - - else: - print("Invalid Exchange, Please Try Again!") + if data['exchange'] == 'binance-futures': + if use_binance_futures: + bot = Bot() + bot.run(data) return { - "status": "error", - "message": "Invalid Exchange, Please Try Again!" + "status": "success", + "message": "Binance Futures Webhook Received!" } + return { + "status": "error", + "message": "Binance Futures is not enabled or failed API validation." + } + + else: + print("Invalid Exchange, Please Try Again!") + return { + "status": "error", + "message": "Invalid Exchange, Please Try Again!" + } if __name__ == '__main__': app.run(debug=False) - - diff --git a/binanceFutures.py b/binanceFutures.py index e2034ed..8dab869 100644 --- a/binanceFutures.py +++ b/binanceFutures.py @@ -7,11 +7,12 @@ with open('config.json') as config_file: config = json.load(config_file) +binance_config = config['EXCHANGES'].get('binance-futures') or config['EXCHANGES'].get('BINANCE-FUTURES') -if config['EXCHANGES']['binance-futures']['TESTNET']: +if binance_config['TESTNET']: exchange = ccxt.binance({ - 'apiKey': config['EXCHANGES']['binance-futures']['API_KEY'], - 'secret': config['EXCHANGES']['binance-futures']['API_SECRET'], + 'apiKey': binance_config['API_KEY'], + 'secret': binance_config['API_SECRET'], 'options': { 'defaultType': 'future', }, @@ -24,8 +25,8 @@ exchange.set_sandbox_mode(True) else: exchange = ccxt.binance({ - 'apiKey': config['EXCHANGES']['binance-futures']['API_KEY'], - 'secret': config['EXCHANGES']['binance-futures']['API_SECRET'], + 'apiKey': binance_config['API_KEY'], + 'secret': binance_config['API_SECRET'], 'options': { 'defaultType': 'future', }, @@ -51,6 +52,20 @@ def create_string(self): self.clientId = baseId + str(res) return + def get_order_qty(self, data, current_price): + if 'qty_percent' not in data: + return float(data['qty']) + + quote_currency = data.get('quote_currency') or data['symbol'].split('/')[-1] + balance = exchange.fetch_balance() + available = balance.get(quote_currency, {}).get('free') + + if available is None: + available = balance.get('free', {}).get(quote_currency) + + qty = (float(available) * (float(data['qty_percent']) / 100)) / float(current_price) + return float(exchange.amount_to_precision(data['symbol'], qty)) + def close_position(self, symbol): position = exchange.fetch_positions(symbol)[0]['info']['positionAmt'] self.create_string() @@ -150,10 +165,12 @@ def run(self, data): else: price = 0 + current_price = exchange.fetch_ticker(data['symbol'])['last'] + qty = self.get_order_qty(data, current_price) + if data['order_mode'] == 'Both': take_profit_percent = float(data['take_profit_percent']) / 100 stop_loss_percent = float(data['stop_loss_percent']) / 100 - current_price = exchange.fetch_ticker(data['symbol'])['last'] if data['side'] == 'Buy': take_profit_price = round(float(current_price) + (float(current_price) * take_profit_percent), 2) @@ -172,10 +189,10 @@ def run(self, data): 'reduceOnly': False } if data['type'] == 'Limit': - exchange.create_order(data['symbol'], data['type'], data['side'], float(data['qty']), + exchange.create_order(data['symbol'], data['type'], data['side'], qty, price=float(price), params=params) else: - exchange.create_order(data['symbol'], data['type'], data['side'], float(data['qty']), + exchange.create_order(data['symbol'], data['type'], data['side'], qty, params=params) self.set_risk(data['symbol'], data, stop_loss_price, take_profit_price) @@ -183,7 +200,6 @@ def run(self, data): elif data['order_mode'] == 'Profit': take_profit_percent = float(data['take_profit_percent']) / 100 - current_price = exchange.fetch_ticker(data['symbol'])['last'] if data['side'] == 'Buy': take_profit_price = round(float(current_price) + (float(current_price) * take_profit_percent), @@ -201,10 +217,10 @@ def run(self, data): } if data['type'] == 'Limit': - exchange.create_order(data['symbol'], data['type'], data['side'], float(data['qty']), + exchange.create_order(data['symbol'], data['type'], data['side'], qty, price=float(price), params=params) else: - exchange.create_order(data['symbol'], data['type'], data['side'], float(data['qty']), + exchange.create_order(data['symbol'], data['type'], data['side'], qty, params=params) self.set_risk(data['symbol'], data, 0, take_profit_price) @@ -212,7 +228,6 @@ def run(self, data): elif data['order_mode'] == 'Stop': stop_loss_percent = float(data['stop_loss_percent']) / 100 - current_price = exchange.fetch_ticker(data['symbol'])['last'] if data['side'] == 'Buy': stop_loss_price = round(float(current_price) - (float(current_price) * stop_loss_percent), 2) @@ -228,10 +243,10 @@ def run(self, data): } if data['type'] == 'Limit': - exchange.create_order(data['symbol'], data['type'], data['side'], float(data['qty']), + exchange.create_order(data['symbol'], data['type'], data['side'], qty, price=float(price), params=params) else: - exchange.create_order(data['symbol'], data['type'], data['side'], float(data['qty']), + exchange.create_order(data['symbol'], data['type'], data['side'], qty, params=params) self.set_risk(data['symbol'], data, stop_loss_price, 0)