├── README.md └── bybit ├── bybit_cli.bat ├── bybit_cli.py ├── bybit_spot.py ├── bybit_usdt_futures.py ├── cli_inputs.py ├── credentials.json └── order_overview.py /README.md: -------------------------------------------------------------------------------- 1 | # Bybit_execution_cli 2 | SPOT and Futures CLI 3 | 4 | todo: 5 | 6 | - paste in api key and secret in credentials.json 7 | - adjust your python ENV and PATH to bybit_cli.py file in bybit_cli.bat 8 | -------------------------------------------------------------------------------- /bybit/bybit_cli.bat: -------------------------------------------------------------------------------- 1 | cmd /k "activate YOUR_PYTON_ENV && python YOUR_PATH_TO_bybit_cli.py" -------------------------------------------------------------------------------- /bybit/bybit_cli.py: -------------------------------------------------------------------------------- 1 | import bybit_spot 2 | import bybit_usdt_futures 3 | import threading 4 | import order_overview 5 | 6 | 7 | def get_all_running_threads(): 8 | if len(threading.enumerate()) == 1: 9 | print("No running proceses") 10 | else: 11 | print("Current running processes:") 12 | for thread in threading.enumerate(): 13 | if thread.name != "MainThread": 14 | print(thread.name) 15 | 16 | 17 | def bybit_spot_cli(account): 18 | 19 | api_key, api_secret = bybit_spot.get_credentials(account=account) 20 | client = bybit_spot.auth(api_key, api_secret) 21 | 22 | exit = False 23 | while not exit: 24 | print("\n") 25 | print("What do you want to do:" 26 | "\n 1 >> display positions" 27 | "\n 2 >> market orders" 28 | "\n 3 >> limit orders" 29 | "\n 4 >> limits at bid/ask" 30 | "\n 5 >> TWAPS" 31 | "\n 0 >> exit - bybit SPOT" 32 | "\n 99 >> restart client" 33 | "\n 999 >> check current running processes") 34 | 35 | try: 36 | mode = int(input("input number >>> ")) 37 | except: 38 | print("input must be number") 39 | mode = 0 40 | 41 | if mode == 0: 42 | exit = True 43 | print(f"Bybit SPOT >> {account} account - closing") 44 | elif mode == 1: 45 | bybit_spot.get_all_spot_positions(client) 46 | elif mode == 2: 47 | print("\n") 48 | print("Market order mode selected >> options:" 49 | "\n 1 >> market order by $ amount" 50 | "\n 2 >> market order by acc %") 51 | try: 52 | order_mode = int(input("input number >>> ")) 53 | except: 54 | print("input must be number") 55 | order_mode = 0 56 | 57 | if order_mode == 1: 58 | bybit_spot.set_market_order_usd(client) 59 | elif order_mode == 2: 60 | bybit_spot.set_market_order_pct(client) 61 | 62 | print("\n") 63 | elif mode == 3: 64 | print("\n") 65 | print("Limit order mode selected >> options:" 66 | "\n 1 >> limit orders between 2 prices by $ amount" 67 | "\n 2 >> limit orders between 2 prices by account %" 68 | ) 69 | try: 70 | order_mode = int(input("input number >>> ")) 71 | except: 72 | print("input must be number") 73 | order_mode = 0 74 | 75 | if order_mode == 1: 76 | bybit_spot.set_limit_orders_usd(client) 77 | elif order_mode == 2: 78 | bybit_spot.set_limit_orders_pct(client) 79 | 80 | print("\n") 81 | elif mode == 4: 82 | print("\n") 83 | print("Limit at bid/ask order mode selected >> options:" 84 | "\n 1 >> limit orders by $ amount" 85 | "\n 2 >> limit orders by account %" 86 | ) 87 | try: 88 | order_mode = int(input("input number >>> ")) 89 | except: 90 | print("input must be number") 91 | order_mode = 0 92 | 93 | if order_mode == 1: 94 | bybit_spot.set_limit_orders_usd_bidask(client) 95 | elif order_mode == 2: 96 | bybit_spot.set_limit_orders_pct_bidask(client) 97 | 98 | print("\n") 99 | elif mode == 5: 100 | print("\n") 101 | print("TWAP mode selected >> options:" 102 | "\n 1 >> linear twap by $ amount" 103 | "\n 2 >> linear twap by account %") 104 | try: 105 | order_mode = int(input("input number >>> ")) 106 | except: 107 | print("input must be number") 108 | order_mode = 0 109 | 110 | if order_mode == 1: 111 | bybit_spot.set_linear_twap_usd(client) 112 | elif order_mode == 2: 113 | bybit_spot.set_linear_twap_pct(client) 114 | elif mode == 999: 115 | print("\n") 116 | get_all_running_threads() 117 | print("\n") 118 | elif mode == 99: 119 | print("Reconnecting client") 120 | api_key, api_secret = bybit_spot.get_credentials(account=account) 121 | client = bybit_spot.auth(api_key, api_secret) 122 | print("\n") 123 | 124 | 125 | def bybit_futures_cli(account): 126 | api_key, api_secret = bybit_usdt_futures.get_credentials(account=account) 127 | client = bybit_usdt_futures.auth(api_key, api_secret) 128 | 129 | exit = False 130 | while not exit: 131 | print("\n") 132 | print("What do you want to do:" 133 | "\n 1 >> display positions" 134 | "\n 2 >> open position" 135 | "\n 3 >> close/reduce position" 136 | "\n 4 >> modify tp/sl" 137 | "\n 0 >> exit - bybit Futures" 138 | "\n 99 >> restart client" 139 | "\n 999 >> check current running processes") 140 | 141 | try: 142 | mode = int(input("input number >>> ")) 143 | except: 144 | print("input must be number") 145 | mode = 0 146 | 147 | if mode == 0: 148 | exit = True 149 | print(f"Bybit Futures >> {account} account - closing") 150 | elif mode == 1: 151 | bybit_usdt_futures.get_open_positions(client, display=True) 152 | elif mode == 2: 153 | print("\n") 154 | print("Open position mode selected >> options:" 155 | "\n 1 >> market orders" 156 | "\n 2 >> limit orders" 157 | "\n 3 >> limits at bid/ask" 158 | "\n 4 >> TWAPS" 159 | "\n 5 >> set multiple TWAPS" 160 | "\n 6 >> Bid OI wipe") 161 | try: 162 | order_mode = int(input("input number >>> ")) 163 | except: 164 | print("input must be number") 165 | order_mode = 0 166 | 167 | if order_mode == 1: 168 | bybit_usdt_futures.set_market_order_open(client) 169 | elif order_mode == 2: 170 | bybit_usdt_futures.set_limits_open(client) 171 | elif order_mode == 3: 172 | bybit_usdt_futures.set_limits_at_bidask_open(client) 173 | elif order_mode == 4: 174 | bybit_usdt_futures.set_linear_twap_open(client) 175 | elif order_mode == 5: 176 | print("\n") 177 | print("Select multiple TWAPS") 178 | bybit_usdt_futures.set_multiple_twaps_open(client) 179 | elif order_mode == 6: 180 | bybit_usdt_futures.bid_IO_wipe(client) 181 | 182 | elif mode == 3: 183 | print("\n") 184 | print("Close / reduce position mode selected >> options:" 185 | "\n 1 >> market orders" 186 | "\n 2 >> limit orders" 187 | "\n 3 >> limits at bid/ask" 188 | "\n 4 >> TWAPS" 189 | "\n 5 >> set multiple TWAPS" 190 | "\n 6 >> close all positions") 191 | try: 192 | order_mode = int(input("input number >>> ")) 193 | except: 194 | print("input must be number") 195 | order_mode = 0 196 | 197 | if order_mode == 1: 198 | bybit_usdt_futures.set_market_order_close(client) 199 | elif order_mode == 2: 200 | bybit_usdt_futures.set_limits_close(client) 201 | elif order_mode == 3: 202 | bybit_usdt_futures.set_limits_at_bidask_close(client) 203 | elif order_mode == 4: 204 | bybit_usdt_futures.set_linear_twap_close(client) 205 | elif order_mode == 5: 206 | bybit_usdt_futures.set_multiple_twaps_close(client) 207 | elif order_mode == 6: 208 | bybit_usdt_futures.close_all_positions(client) 209 | 210 | elif mode == 4: 211 | bybit_usdt_futures.set_position_sl_tp(client) 212 | elif mode == 999: 213 | print("\n") 214 | get_all_running_threads() 215 | print("\n") 216 | elif mode == 99: 217 | print("Reconnecting client") 218 | api_key, api_secret = bybit_usdt_futures.get_credentials(account=account) 219 | client = bybit_usdt_futures.auth(api_key, api_secret) 220 | print("\n") 221 | 222 | 223 | def main(): 224 | 225 | exit = False 226 | while not exit: 227 | print("\n") 228 | print("Select account:" 229 | "\n 1 >> Bybit SPOT - IC_personal" 230 | "\n 2 >> Bybit USDT perps - IC_personal" 231 | "\n 3 >> Order Overview" 232 | "\n 999 >> check current running processes" 233 | "\n 0 >> exit terminal") 234 | 235 | mode = int(input("input number >>> ")) 236 | 237 | if mode == 0: 238 | exit = True 239 | print("\n") 240 | print("Terminal closing") 241 | elif mode == 999: 242 | print("\n") 243 | get_all_running_threads() 244 | print("\n") 245 | elif mode == 1: 246 | print("\n") 247 | bybit_spot_cli(account="IC_personal") 248 | elif mode == 2: 249 | print("\n") 250 | bybit_futures_cli(account="IC_personal") 251 | elif mode == 3: 252 | print("\n") 253 | order_overview.Order_overview() 254 | 255 | 256 | if __name__ == "__main__": 257 | main() -------------------------------------------------------------------------------- /bybit/bybit_spot.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | from pybit.unified_trading import HTTP 3 | import time 4 | import pandas as pd 5 | import json 6 | from pathlib import Path 7 | from dhooks import Webhook 8 | import cli_inputs 9 | from threading import Thread 10 | 11 | 12 | def get_credentials(account): 13 | root = Path(".") 14 | file_path = f"{root}/credentials.json" 15 | 16 | with open(file_path) as file: 17 | 18 | file = file.read() 19 | credentials = json.loads(file) 20 | 21 | api_key = credentials[account]["bybit_api_key"] 22 | api_secret = credentials[account]["bybit_secret_key"] 23 | 24 | return api_key, api_secret 25 | 26 | 27 | def auth(api_key, api_secret): 28 | bybit_client = HTTP(testnet=False, api_key=api_key, api_secret=api_secret) 29 | 30 | return bybit_client 31 | 32 | 33 | def get_usdt_balance(client): 34 | balances = client.get_wallet_balance(accountType="UNIFIED")["result"]["list"][0]["coin"] 35 | usdt_balance = None 36 | for balance in balances: 37 | if balance["coin"] == "USDT": 38 | usdt_balance = round(float(balance["equity"])) 39 | # print(f"total usdt balance: {usdt_balance} USDT") 40 | 41 | if usdt_balance is not None: 42 | return usdt_balance 43 | else: 44 | print("no usdt available") 45 | 46 | 47 | def get_coin_balance(client, ticker): 48 | ticker = ticker.replace("USDT", "") 49 | balances = client.get_wallet_balance(accountType="UNIFIED")["result"]["list"][0]["coin"] 50 | coin_balance = 0 51 | usd_value = 0 52 | for balance in balances: 53 | if balance["coin"] == ticker: 54 | coin_balance = float(balance["equity"]) 55 | usd_value = round(float(balance["usdValue"]),2) 56 | 57 | if coin_balance and usd_value > 1: 58 | # print(f"total {ticker} balance: {coin_balance} || usd value: {usd_value}") 59 | return coin_balance, usd_value 60 | else: 61 | print(f"no spot positions found for: {ticker}") 62 | return coin_balance, usd_value 63 | 64 | 65 | def get_spot_usdt_tickers(client): 66 | symbols = client.get_instruments_info(category="spot")["result"]["list"] 67 | tickers = {} 68 | for row in symbols: 69 | symbol = row["symbol"] 70 | ticker = row["symbol"] 71 | if "USDT" in symbol: 72 | 73 | symbol = symbol.replace("USDT", "") 74 | 75 | if "10000" in symbol: 76 | symbol = symbol.replace("10000", "") 77 | elif "1000" in symbol: 78 | symbol = symbol.replace("1000", "") 79 | elif "100000" in symbol: 80 | symbol = symbol.replace("100000", "") 81 | 82 | tickers[symbol] = ticker 83 | 84 | return tickers 85 | 86 | 87 | def get_instrument_info(client, ticker): 88 | instrument_info = client.get_instruments_info(category="spot", symbol=ticker)["result"]["list"][0] 89 | 90 | min_order_size_coin = float(instrument_info["lotSizeFilter"]["minOrderQty"]) # coin 91 | max_order_size_coin = float(instrument_info["lotSizeFilter"]["maxOrderQty"]) # coin 92 | 93 | min_order_size_usd = int(instrument_info["lotSizeFilter"]["minOrderAmt"]) # usdt 94 | max_order_size_usd = int(instrument_info["lotSizeFilter"]["maxOrderAmt"]) # usdt 95 | 96 | decimals = str(str(instrument_info["lotSizeFilter"]["minOrderQty"]))[::-1].find('.') 97 | 98 | tick_size = instrument_info["priceFilter"]["tickSize"] 99 | 100 | return max_order_size_coin, min_order_size_coin, min_order_size_usd, max_order_size_usd, decimals, tick_size 101 | 102 | 103 | def get_last_price(client, ticker): 104 | ticker_data = client.get_tickers(category="spot", symbol=ticker)["result"]["list"][0] 105 | last_price = float(ticker_data["lastPrice"]) 106 | return last_price 107 | 108 | 109 | def get_all_spot_positions(client): 110 | balances = client.get_wallet_balance(accountType="UNIFIED")["result"]["list"][0]["coin"] 111 | 112 | spot_positions = [] 113 | 114 | for balance in balances: 115 | coin = balance["coin"] 116 | usd_value = round(float(balance["usdValue"])) 117 | coins = float(balance["walletBalance"]) 118 | 119 | if usd_value > 10: 120 | spot_positions.append([coin, usd_value, coins]) 121 | 122 | if spot_positions: 123 | print("\n") 124 | print("Current spot positions") 125 | positions_df = pd.DataFrame(spot_positions, columns=["coin", "usdValue", "coinAmount"]) 126 | positions_df["coinAmount"] = positions_df["coinAmount"].astype(str) 127 | print(positions_df.to_markdown(floatfmt='')) 128 | print("\n") 129 | else: 130 | print("No spot positions") 131 | 132 | 133 | 134 | # order functions 135 | # limit orders 136 | # limit 137 | def limit_tranche(client, usd_size, ticker, side, upper_price, lower_price, order_amount, bid_ask:bool): 138 | """ 139 | 140 | :param client: bybit client 141 | :param usd_size: total size 142 | :param ticker: ticker 143 | :param side: b > buy, s > sell 144 | :param upper_price: upper bound for limit orders 145 | :param lower_price: lower bound for limit orders 146 | :return: 147 | """ 148 | 149 | if order_amount == "default": 150 | order_amount = 15 151 | 152 | max_order_size_coin, min_order_size_coin, min_order_size_usd, max_order_size_usd, decimals, tick_size = get_instrument_info(client, ticker) 153 | tick_decimals = str(tick_size)[::-1].find('.') 154 | orders = [] 155 | 156 | # Calculate the spacing between orders 157 | spacing = (upper_price - lower_price) / (order_amount) 158 | 159 | last_price = get_last_price(client, ticker) 160 | error = True 161 | if not bid_ask: 162 | if upper_price > lower_price: 163 | if side == "b": 164 | if last_price > upper_price: 165 | error = False 166 | else: 167 | print("on buy side last price should be higher than upper price limit") 168 | elif side == "s": 169 | if last_price < lower_price: 170 | error = False 171 | else: 172 | print("on sell side last price should be lower than lower price limit") 173 | else: 174 | print(f"Error with side input || input: {side} || should be: b/s") 175 | else: 176 | print("upper price limit should be higher than lower price limit") 177 | else: 178 | error = False 179 | 180 | if not error: 181 | if side == "b": 182 | usdt_balance = get_usdt_balance(client) 183 | side = "Buy" 184 | if usd_size < usdt_balance: 185 | single_order = int(usd_size / order_amount) 186 | price = lower_price 187 | for i in range(order_amount): 188 | orders.append([round(single_order / price, decimals), round(price, tick_decimals)]) 189 | price += spacing 190 | 191 | else: 192 | print(f"Not enought usdt to execute the limit tranche order || usdt available: {usdt_balance} $") 193 | 194 | if side == "s": 195 | side = "Sell" 196 | coin_balance, usd_value = get_coin_balance(client, ticker) 197 | 198 | coins_to_sell = round(usd_size / ((upper_price + lower_price) / 2), decimals) 199 | single_order = round(coins_to_sell / order_amount, decimals) 200 | if coins_to_sell < coin_balance: 201 | price = lower_price 202 | for i in range(order_amount): 203 | orders.append([single_order, round(price, tick_decimals)]) 204 | price += spacing 205 | else: 206 | print(f"not enough coins available to create limit tranche order || coin balance: {coin_balance}") 207 | 208 | for order in orders: 209 | client.place_order(category="spot", symbol=ticker, side=side, orderType="Limit", qty=order[0], price=order[1] ,timeInForce="GTC") 210 | time.sleep(0.01) 211 | 212 | 213 | # market orders 214 | def market_order(client, usd_size, coin_sell_amount, ticker, side): 215 | """ 216 | this order will split ur size into 20 equal orders and rapid execute them in 0.25s time intervals 217 | 218 | :param client: bybit client 219 | :param usd_size: size in usd 220 | :param ticker: choose ticker 221 | :param side: b > buy, s > sell 222 | :return: 223 | """ 224 | 225 | max_order_size_coin, min_order_size_coin, min_order_size_usd, max_order_size_usd, decimals, tick_size = get_instrument_info(client, ticker) 226 | 227 | orders = [] 228 | if side == "b": 229 | usdt_balance = get_usdt_balance(client) 230 | side = "Buy" 231 | if usd_size <= usdt_balance: 232 | single_order = int(usd_size / 20) 233 | if single_order > min_order_size_usd: 234 | if single_order < max_order_size_usd: 235 | for i in range(20): 236 | orders.append(single_order) 237 | else: 238 | print(f"single order to big to execute twap || order size: {single_order} || max order size: {max_order_size_usd} ") 239 | else: 240 | print(f"total twap size to low: {usd_size}$") 241 | 242 | elif side == "s": 243 | # min order size is in coins 244 | coin_balance, usd_value = get_coin_balance(client, ticker) 245 | coins_to_sell = coin_sell_amount 246 | side = "Sell" 247 | if coin_balance >= coin_sell_amount: 248 | single_order = round(coins_to_sell / 20, decimals) 249 | if single_order > min_order_size_coin: 250 | if single_order < max_order_size_coin: 251 | for i in range(20): 252 | orders.append(single_order) 253 | else: 254 | print(f"single order to big to execute twap || order size: {single_order} coins|| max order size: {max_order_size_coin} coins ") 255 | else: 256 | print(f"total twap size to low: {usd_size}") 257 | else: 258 | print(f"Error with side input || input: {side} || should be: b/s") 259 | 260 | time_delay = 0.25 # seconds 261 | if orders: 262 | for order in orders: 263 | client.place_order(category="spot", symbol=ticker, side=side, orderType="Market", qty=order, timeInForce="IOC") 264 | time.sleep(time_delay) 265 | 266 | 267 | def linear_twap(client, usd_size, coin_sell_amount ,ticker, side, duration, order_amount): 268 | """ 269 | fuction that split order into equal sized orders and executes them over specified duration with equal time delays 270 | :param client: bybit client 271 | :param usd_size: size in usd 272 | :param ticker: choose ticker 273 | :param side: b > buy, s > sell 274 | :param duration: in seconds 275 | :param order_amount: amount of orders [default: 100 orders, int: specific number of orders) 276 | :return: 277 | """ 278 | 279 | max_order_size_coin, min_order_size_coin, min_order_size_usd, max_order_size_usd, decimals, tick_size = get_instrument_info(client, ticker) 280 | 281 | # check if size doesn't excedes available usdt qty 282 | # if based on order amount size becomes lower than min qty fix it to min qty 283 | orders = [] 284 | if side == "b": 285 | usdt_balance = get_usdt_balance(client) 286 | side = "Buy" 287 | if usd_size < usdt_balance: 288 | # min order size is in usd 289 | if order_amount == "default": 290 | single_order = int(usd_size / 100) 291 | if single_order > min_order_size_usd: 292 | if single_order < max_order_size_usd: 293 | for i in range(100): 294 | orders.append(single_order) 295 | else: 296 | print(f"single order to big to execute twap || order size: {single_order} || max order size: {max_order_size_usd} ") 297 | else: 298 | print(f"total twap size to low: {usd_size}") 299 | else: 300 | orders = [] 301 | if int(usd_size / order_amount) > min_order_size_usd: 302 | single_order = int(usd_size / order_amount) 303 | 304 | if single_order < max_order_size_usd: 305 | for i in range(order_amount): 306 | orders.append(single_order) 307 | else: 308 | print(f"single order to big to execute twap || order size: {single_order} || max order size: {max_order_size_usd} ") 309 | else: 310 | print(f"single order size to low to execute twap || order size: {int(usd_size / order_amount)} || min order size: {min_order_size_usd}") 311 | else: 312 | print(f"not enough usdt to execute twap || available funds: {usdt_balance} $ || twap size: {usd_size} $") 313 | 314 | elif side == "s": 315 | # min order size is in coins 316 | coin_balance, usd_value = get_coin_balance(client, ticker) 317 | coins_to_sell = coin_sell_amount 318 | side = "Sell" 319 | if coin_balance >= coin_sell_amount: 320 | if order_amount == "auto": 321 | single_order = round(coins_to_sell / 100, decimals) 322 | if single_order > min_order_size_coin: 323 | if single_order < max_order_size_coin: 324 | for i in range(100): 325 | orders.append(single_order) 326 | else: 327 | print(f"single order to big to execute twap || order size: {single_order} coins|| max order size: {max_order_size_coin} coins ") 328 | else: 329 | print(f"total twap size to low: {usd_size} >> should be atleast 100$") 330 | else: 331 | orders = [] 332 | single_order = round(coins_to_sell / order_amount, decimals) 333 | 334 | if single_order > min_order_size_coin: 335 | if single_order < max_order_size_coin: 336 | for i in range(order_amount): 337 | orders.append(single_order) 338 | else: 339 | print(f"single order to big to execute twap || order size: {single_order} coins || max order size: {max_order_size_coin} coins") 340 | else: 341 | print(f"single order size to low to execute twap || order size: {single_order} coins || min order size: {min_order_size_coin} coins") 342 | else: 343 | print(f"not enough coins to execute Sell twap || available funds: {coin_balance} coins || twap size: {coin_sell_amount} coins") 344 | 345 | else: 346 | print(f"Error with side input || input: {side} || should be: b/s") 347 | 348 | time_delay = duration / order_amount 349 | 350 | if orders: 351 | for order in orders: 352 | client.place_order(category="spot", symbol=ticker, side=side, orderType="Market", qty=order, timeInForce="IOC") 353 | time.sleep(time_delay) 354 | 355 | 356 | # order execution functions 357 | 358 | def set_limit_orders_usd(client): 359 | """ 360 | Functions that sets basic limit orders 361 | 362 | :return: 363 | """ 364 | tickers = get_spot_usdt_tickers(client=client) 365 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=True) 366 | usd_size = cli_inputs.select_usdt_size() 367 | side = cli_inputs.select_side() 368 | upper_price = cli_inputs.select_upper_limit_price() 369 | lower_price = cli_inputs.select_lower_limit_price() 370 | order_amount = cli_inputs.select_order_amount() 371 | bid_ask = False 372 | 373 | limit_thread = Thread(target=limit_tranche, args=(client, usd_size, ticker, side, upper_price, lower_price, order_amount, bid_ask), name=f"BYBIT_SPOT_{ticker}_{side}_{usd_size}limit_tranche").start() 374 | 375 | 376 | def set_limit_orders_pct(client): 377 | """ 378 | Functions that sets basic limit orders 379 | 380 | :return: 381 | """ 382 | tickers = get_spot_usdt_tickers(client=client) 383 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=True) 384 | side = cli_inputs.select_side() 385 | upper_price = cli_inputs.select_upper_limit_price() 386 | lower_price = cli_inputs.select_lower_limit_price() 387 | avg_prc = (upper_price + lower_price) / 2 388 | bid_ask = False 389 | if side == "s": 390 | coin_balance, usd_value = get_coin_balance(client=client, ticker=ticker) 391 | acc_pct = cli_inputs.select_pct() 392 | if acc_pct == 1: 393 | acc_pct = 0.999 394 | usd_size = round((coin_balance * avg_prc * 0.999) * acc_pct) 395 | else: 396 | usdt_balance = get_usdt_balance(client=client) 397 | acc_pct = cli_inputs.select_pct() 398 | if acc_pct == 1: 399 | acc_pct = 0.999 400 | usd_size = round(usdt_balance * acc_pct) 401 | 402 | order_amount = cli_inputs.select_order_amount() 403 | 404 | limit_thread = Thread(target=limit_tranche, args=(client, usd_size, ticker, side, upper_price, lower_price, order_amount, bid_ask), name=f"BYBIT_SPOT_{ticker}_{side}_{usd_size}limit_tranche").start() 405 | 406 | 407 | def set_limit_orders_usd_bidask(client): 408 | """ 409 | Functions that sets basic limit orders 410 | 411 | :return: 412 | """ 413 | tickers = get_spot_usdt_tickers(client=client) 414 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=True) 415 | max_order_size_coin, min_order_size_coin, min_order_size_usd, max_order_size_usd, decimals, tick_size = get_instrument_info(client, ticker) 416 | tick_decimals = str(tick_size)[::-1].find('.') 417 | 418 | usd_size = cli_inputs.select_usdt_size() 419 | side = cli_inputs.select_side() 420 | 421 | bps_range = 0.004 422 | if ticker in ["BTCUSDT", "ETHUSDT"]: 423 | bps_range = 0.001 424 | last_price = get_last_price(client, ticker) 425 | 426 | if side == "b": 427 | upper_price = last_price 428 | lower_price = round(upper_price - (last_price * bps_range), tick_decimals) 429 | elif side == "s": 430 | lower_price = last_price 431 | upper_price = round(lower_price + (last_price * bps_range), tick_decimals) 432 | 433 | order_amount = 10 434 | bid_ask = True 435 | 436 | limit_thread = Thread(target=limit_tranche, args=(client, usd_size, ticker, side, upper_price, lower_price, order_amount, bid_ask), name=f"BYBIT_SPOT_{ticker}_{side}_{usd_size}limit_tranche").start() 437 | 438 | 439 | def set_limit_orders_pct_bidask(client): 440 | """ 441 | Functions that sets basic limit orders 442 | 443 | :return: 444 | """ 445 | 446 | tickers = get_spot_usdt_tickers(client=client) 447 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=True) 448 | side = cli_inputs.select_side() 449 | 450 | max_order_size_coin, min_order_size_coin, min_order_size_usd, max_order_size_usd, decimals, tick_size = get_instrument_info(client, ticker) 451 | tick_decimals = str(tick_size)[::-1].find('.') 452 | 453 | bps_range = 0.004 454 | if ticker in ["BTCUSDT", "ETHUSDT"]: 455 | bps_range = 0.001 456 | 457 | last_price = get_last_price(client, ticker) 458 | if side == "b": 459 | upper_price = last_price 460 | lower_price = round(upper_price - (last_price * bps_range), tick_decimals) 461 | elif side == "s": 462 | lower_price = last_price 463 | upper_price = round(lower_price + (last_price * bps_range), tick_decimals) 464 | 465 | order_amount = 10 466 | bid_ask = True 467 | avg_prc = (upper_price + lower_price) / 2 468 | 469 | if side == "s": 470 | coin_balance, usd_value = get_coin_balance(client=client, ticker=ticker) 471 | acc_pct = cli_inputs.select_pct() 472 | if acc_pct == 1: 473 | acc_pct = 0.999 474 | usd_size = round((coin_balance * avg_prc * 0.999) * acc_pct) 475 | else: 476 | usdt_balance = get_usdt_balance(client=client) 477 | acc_pct = cli_inputs.select_pct() 478 | if acc_pct == 1: 479 | acc_pct = 0.999 480 | usd_size = round(usdt_balance * acc_pct) 481 | 482 | limit_thread = Thread(target=limit_tranche, args=(client, usd_size, ticker, side, upper_price, lower_price, order_amount, bid_ask), name=f"BYBIT_SPOT_{ticker}_{side}_{usd_size}limit_tranche").start() 483 | 484 | 485 | def set_linear_twap_usd(client): 486 | """ 487 | Basic linear twap setup 488 | 489 | :param client: 490 | :return: 491 | """ 492 | tickers = get_spot_usdt_tickers(client=client) 493 | usd_size = cli_inputs.select_usdt_size() 494 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=True) 495 | side = cli_inputs.select_side() 496 | duration = cli_inputs.select_duration() 497 | order_amount = cli_inputs.select_order_amount() 498 | 499 | if side == "s": 500 | last_price = get_last_price(client, ticker) 501 | coin_sell_amount = usd_size / last_price 502 | elif side == "b": 503 | coin_sell_amount = 0 504 | 505 | twap_thread = Thread(target=linear_twap, args=(client, usd_size, coin_sell_amount, ticker, side, duration, order_amount), name=f"BYBIT_SPOT_{ticker}_{side}_{usd_size}_twap{round(duration / 60, 1)}min").start() 506 | 507 | 508 | def set_linear_twap_pct(client): 509 | """ 510 | Basic linear twap setup 511 | 512 | :param client: 513 | :return: 514 | """ 515 | tickers = get_spot_usdt_tickers(client=client) 516 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=True) 517 | side = cli_inputs.select_side() 518 | 519 | if side == "s": 520 | coin_balance, usd_value = get_coin_balance(client=client, ticker=ticker) 521 | acc_pct = cli_inputs.select_pct() 522 | if acc_pct == 1: 523 | acc_pct = 0.999 524 | coin_sell_amount = coin_balance * acc_pct 525 | usd_size = 0 526 | elif side == "b": 527 | usdt_balance = get_usdt_balance(client=client) 528 | acc_pct = cli_inputs.select_pct() 529 | if acc_pct == 1: 530 | acc_pct = 0.999 531 | usd_size = round(usdt_balance * acc_pct) 532 | coin_sell_amount = 0 533 | 534 | duration = cli_inputs.select_duration() 535 | order_amount = cli_inputs.select_order_amount() 536 | 537 | twap_thread = Thread(target=linear_twap, args=(client, usd_size, coin_sell_amount, ticker, side, duration, order_amount), name=f"BYBIT_SPOT_{ticker}_{side}_{usd_size}_twap{round(duration / 60, 1)}min").start() 538 | 539 | 540 | def set_market_order_usd(client): 541 | """ 542 | Basic market order executes in 20 swarm orders 543 | 544 | :param client: 545 | :return: 546 | """ 547 | 548 | tickers = get_spot_usdt_tickers(client=client) 549 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=True) 550 | usd_size = cli_inputs.select_usdt_size() 551 | side = cli_inputs.select_side() 552 | 553 | if side == "s": 554 | last_price = get_last_price(client, ticker) 555 | coin_sell_amount = usd_size / last_price 556 | elif side == "b": 557 | coin_sell_amount = 0 558 | 559 | market_order_thread = Thread(target=market_order, args=(client, usd_size, coin_sell_amount, ticker, side), name=f"SPOT_{ticker}_{side}_{usd_size}").start() 560 | 561 | 562 | def set_market_order_pct(client): 563 | """ 564 | Basic market order executes in 20 swarm orders 565 | 566 | :param client: 567 | :return: 568 | """ 569 | 570 | tickers = get_spot_usdt_tickers(client=client) 571 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=True) 572 | side = cli_inputs.select_side() 573 | 574 | if side == "s": 575 | coin_balance, usd_value = get_coin_balance(client=client, ticker=ticker) 576 | acc_pct = cli_inputs.select_pct() 577 | if acc_pct == 1: 578 | acc_pct = 0.999 579 | coin_sell_amount = coin_balance * acc_pct 580 | usd_size = 0 581 | else: 582 | usdt_balance = get_usdt_balance(client=client) 583 | acc_pct = cli_inputs.select_pct() 584 | if acc_pct == 1: 585 | acc_pct = 0.999 586 | usd_size = round(usdt_balance * acc_pct) 587 | coin_sell_amount = 0 588 | 589 | market_order_thread = Thread(target=market_order, args=(client, usd_size, coin_sell_amount ,ticker, side), name=f"SPOT_{ticker}_{side}_{usd_size}").start() 590 | 591 | # todo: TESTING 592 | # api_key, api_secret = get_credentials(account="IC_personal") 593 | # client = auth(api_key, api_secret) 594 | # 595 | 596 | # set_limit_orders_usd_bidask(client) 597 | # set_limit_orders_pct_bidask(client) 598 | # get_all_spot_positions(client) 599 | 600 | # set_limit_orders_usd(client) 601 | # set_limit_orders_pct(client) 602 | 603 | # set_limit_orders_atAvgPrc_usd(client) 604 | # set_limit_orders_atAvgPrc_pct(client) 605 | 606 | # set_linear_twap_usd(client) 607 | # set_market_order_usd(client) 608 | 609 | # set_linear_twap_pct(client) 610 | # set_market_order_pct(client) 611 | 612 | # todo: dodat price checke da štima glede uper limit itd da so zadeve logične uglavnem pa da nemorš ful velke cifre dat 613 | 614 | # limit_tranche(client, 500, "ETHUSDT", "s", 1850, 1810, 10) 615 | 616 | # limit_tranche_avg_price(client, 1000, "ETHUSDT", "s",1850, 1810, 1833 ,10) 617 | 618 | 619 | # linear_twap(client, 1965, "ETHUSDT", "s", 30, 10) 620 | # market_order(client, 1000, "ETHUSDT", "s") 621 | 622 | 623 | # tickers = get_spot_usdt_tickers(client) 624 | # max_order_size_coin, min_order_size_coin, min_order_amount, max_order_amount, decimals = get_instrument_info(client, "BTCUSDT") 625 | # balance = get_usdt_balance(client) 626 | -------------------------------------------------------------------------------- /bybit/bybit_usdt_futures.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | from pybit.unified_trading import HTTP 3 | import time 4 | import pandas as pd 5 | import json 6 | from pathlib import Path 7 | from dhooks import Webhook 8 | import cli_inputs 9 | from threading import Thread 10 | 11 | 12 | def get_credentials(account): 13 | root = Path(".") 14 | file_path = f"{root}/credentials.json" 15 | 16 | with open(file_path) as file: 17 | 18 | file = file.read() 19 | credentials = json.loads(file) 20 | 21 | api_key = credentials[account]["bybit_api_key"] 22 | api_secret = credentials[account]["bybit_secret_key"] 23 | 24 | return api_key, api_secret 25 | 26 | 27 | def auth(api_key, api_secret): 28 | bybit_client = HTTP(testnet=False, api_key=api_key, api_secret=api_secret) 29 | 30 | return bybit_client 31 | 32 | 33 | def get_usdt_balance(client): 34 | balances = client.get_wallet_balance(accountType="UNIFIED")["result"]["list"][0]["coin"] 35 | usdt_balance = None 36 | for balance in balances: 37 | if balance["coin"] == "USDT": 38 | usdt_balance = round(float(balance["equity"])) 39 | print(f"total usdt balance: {usdt_balance} USDT") 40 | 41 | if usdt_balance is not None: 42 | return usdt_balance 43 | else: 44 | print("no usdt available") 45 | 46 | 47 | def get_usdt_futures_tickers(client): 48 | symbols = client.get_instruments_info(category="linear")["result"]["list"] 49 | tickers = {} 50 | for row in symbols: 51 | symbol = row["symbol"] 52 | ticker = row["symbol"] 53 | if "USDT" in symbol: 54 | 55 | symbol = symbol.replace("USDT", "") 56 | 57 | if "1000000" in symbol: 58 | symbol = symbol.replace("1000000", "") 59 | elif "100000" in symbol: 60 | symbol = symbol.replace("100000", "") 61 | elif "10000" in symbol: 62 | symbol = symbol.replace("10000", "") 63 | elif "1000" in symbol: 64 | symbol = symbol.replace("1000", "") 65 | 66 | tickers[symbol] = ticker 67 | 68 | return tickers 69 | 70 | 71 | def get_instrument_info(client, ticker): 72 | """ 73 | Gives instrument data for size, risk limits, etc 74 | 75 | :param client: bybit client 76 | :param ticker: ticker 77 | :return: 78 | """ 79 | instrument_info = client.get_instruments_info(category="linear", symbol=ticker)["result"]["list"][0] 80 | risk_limit_info = client.get_risk_limit(category="linear", symbol=ticker)["result"]["list"][0] 81 | 82 | position_size_limit = int(risk_limit_info["riskLimitValue"]) # USDT 83 | 84 | min_order_size_coin = float(instrument_info["lotSizeFilter"]["minOrderQty"]) # coin 85 | max_order_size_coin = float(instrument_info["lotSizeFilter"]["maxOrderQty"]) # coin 86 | 87 | decimals = str(str(instrument_info["lotSizeFilter"]["minOrderQty"]))[::-1].find('.') 88 | 89 | tick_size = instrument_info["priceFilter"]["tickSize"] 90 | 91 | return max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit 92 | 93 | 94 | def get_last_price(client, ticker): 95 | ticker_data = client.get_tickers(category="linear", symbol=ticker)["result"]["list"][0] 96 | last_price = float(ticker_data["lastPrice"]) 97 | return last_price 98 | 99 | # ORDER/POSITION OVERVIEW FUNCTIONS 100 | def get_open_positions(client, display:bool): 101 | """ 102 | Gives you all open USDT-Futures positions 103 | 104 | :param client: bybit client 105 | :param display: True = displays all positions into dataframe, False = doesn't display positions 106 | :return: 107 | """ 108 | positions = client.get_positions(category="linear", settleCoin="USDT")["result"]["list"] 109 | open_positions = {} 110 | counter = 0 111 | for position in positions: 112 | size = float(position["size"]) 113 | 114 | if size > 0: 115 | open_positions[counter] = position 116 | counter += 1 117 | 118 | if open_positions: 119 | if display: 120 | print("\n") 121 | print("Current positions:") 122 | positions_df = pd.DataFrame.from_dict(open_positions, orient="index") 123 | positions_df = positions_df[["symbol", "side", "size", "positionValue", "avgPrice", "unrealisedPnl", "takeProfit", "stopLoss"]] 124 | print(positions_df.to_markdown()) 125 | print("\n") 126 | 127 | return open_positions 128 | 129 | else: 130 | if display: 131 | print("\n") 132 | print("No open positions") 133 | print("\n") 134 | return open_positions 135 | 136 | 137 | def set_position_sl_tp(client): 138 | positions = get_open_positions(client=client, display=True) 139 | try: 140 | modify_id = int(input("select ID of the position you wish to modify >>> ")) 141 | except: 142 | modify_id = None 143 | print("Error: ID must be number") 144 | 145 | 146 | try: 147 | print("What do you want to modify: 1=tp/sl, 2=tp, 3=sl") 148 | modify_type = int(input("Input the modification type you want[1, 2, 3] >>>")) 149 | except: 150 | modify_type = None 151 | print("Error: Modification type must me number") 152 | 153 | if modify_type is not None and modify_id is not None: 154 | if modify_id in positions.keys(): 155 | 156 | position = positions[modify_id] 157 | ticker = position["symbol"] 158 | position_side = position["side"] 159 | 160 | takeProfit = position["takeProfit"] 161 | stopLoss = position["stopLoss"] 162 | 163 | last_price = get_last_price(client, ticker) 164 | print(f"{ticker} selected to modify") 165 | 166 | if position_side == "Buy": 167 | if modify_type == 1: 168 | try: 169 | new_tp_price = float(input("new TP price >>> ")) 170 | if new_tp_price < last_price and new_tp_price != 0: 171 | print("TP price below last price, TP won't be set/changed") 172 | new_tp_price = None 173 | else: 174 | new_tp_price = str(new_tp_price) 175 | takeProfit = new_tp_price 176 | except: 177 | print("TP price should be number") 178 | 179 | try: 180 | new_sl_price = float(input("new SL price >>> ")) 181 | 182 | if new_sl_price > last_price: 183 | print("SL price above last price, SL won't be set/changed") 184 | new_sl_price = None 185 | else: 186 | new_sl_price = str(new_sl_price) 187 | stopLoss = new_sl_price 188 | except: 189 | print("SL price should be number") 190 | 191 | if new_tp_price is not None or new_sl_price is not None: 192 | client.set_trading_stop(category="linear", symbol=ticker, takeProfit=takeProfit, tpTriggerBy="LastPrice",stopLoss=stopLoss, slTriggerBy="LastPrice", positionIdx=0) 193 | print(f"{ticker} TP and SL modified >>> new TP: {takeProfit} | new SL: {stopLoss}") 194 | else: 195 | print("no modifications were made") 196 | 197 | elif modify_type == 2: 198 | try: 199 | new_tp_price = float(input("new TP price >>> ")) 200 | if new_tp_price < last_price and new_tp_price != 0: 201 | print("TP price below last price, TP won't be set/changed") 202 | new_tp_price = None 203 | else: 204 | new_tp_price = str(new_tp_price) 205 | takeProfit = new_tp_price 206 | except: 207 | print("TP price should be number") 208 | 209 | if new_tp_price is not None: 210 | client.set_trading_stop(category="linear", symbol=ticker, takeProfit=takeProfit, tpTriggerBy="LastPrice", stopLoss=stopLoss, slTriggerBy="LastPrice", positionIdx=0) 211 | print(f"{ticker} TP modified >>> new TP: {takeProfit}") 212 | else: 213 | print("no modifications were made") 214 | 215 | elif modify_type == 3: 216 | try: 217 | new_sl_price = float(input("new SL price >>> ")) 218 | 219 | if new_sl_price > last_price: 220 | print("SL price above last price, SL won't be set/changed") 221 | new_sl_price = None 222 | else: 223 | new_sl_price = str(new_sl_price) 224 | stopLoss = new_sl_price 225 | 226 | except: 227 | print("SL price should be number") 228 | 229 | if new_sl_price is not None: 230 | client.set_trading_stop(category="linear", symbol=ticker, takeProfit=takeProfit, tpTriggerBy="LastPrice", stopLoss=stopLoss, slTriggerBy="LastPrice", positionIdx=0) 231 | print(f"{ticker} SL modified >>> new TP: {stopLoss}") 232 | else: 233 | print("no modifications were made") 234 | 235 | elif position_side == "Sell": 236 | if modify_type == 1: 237 | try: 238 | new_tp_price = float(input("new TP price >>> ")) 239 | if new_tp_price > last_price: 240 | print("TP price above last price, TP won't be set/changed") 241 | new_tp_price = None 242 | else: 243 | new_tp_price = str(new_tp_price) 244 | takeProfit = new_tp_price 245 | except: 246 | print("TP price should be number") 247 | 248 | try: 249 | new_sl_price = float(input("new SL price >>> ")) 250 | 251 | if new_sl_price < last_price and new_sl_price != 0: 252 | print("SL price below last price, SL won't be set/changed") 253 | new_sl_price = None 254 | else: 255 | new_sl_price = str(new_sl_price) 256 | stopLoss = new_sl_price 257 | 258 | except: 259 | print("SL price should be number") 260 | 261 | if new_tp_price is not None or new_sl_price is not None: 262 | client.set_trading_stop(category="linear", symbol=ticker, takeProfit=takeProfit, tpTriggerBy="LastPrice", stopLoss=stopLoss, slTriggerBy="LastPrice", positionIdx=0) 263 | print(f"{ticker} TP and SL modified >>> new TP: {takeProfit} | new SL: {stopLoss}") 264 | else: 265 | print("no modifications were made") 266 | 267 | elif modify_type == 2: 268 | try: 269 | new_tp_price = float(input("new TP price >>> ")) 270 | if new_tp_price > last_price: 271 | print("TP price above last price, TP won't be set/changed") 272 | new_tp_price = None 273 | else: 274 | new_tp_price = str(new_tp_price) 275 | takeProfit = new_tp_price 276 | 277 | except: 278 | print("TP price should be number") 279 | 280 | if new_tp_price is not None: 281 | client.set_trading_stop(category="linear", symbol=ticker, takeProfit=takeProfit, tpTriggerBy="LastPrice", stopLoss=stopLoss, slTriggerBy="LastPrice", positionIdx=0) 282 | print(f"{ticker} TP modified >>> new TP: {takeProfit}") 283 | else: 284 | print("no modifications were made") 285 | 286 | elif modify_type == 3: 287 | try: 288 | new_sl_price = float(input("new SL price >>> ")) 289 | 290 | if new_sl_price < last_price and new_sl_price != 0: 291 | print("SL price below last price, SL won't be set/changed") 292 | new_sl_price = None 293 | else: 294 | new_sl_price = str(new_sl_price) 295 | stopLoss = new_sl_price 296 | 297 | except: 298 | print("SL price should be number") 299 | 300 | if new_sl_price is not None: 301 | client.set_trading_stop(category="linear", symbol=ticker, takeProfit=takeProfit, tpTriggerBy="LastPrice", stopLoss=stopLoss, slTriggerBy="LastPrice", positionIdx=0) 302 | print(f"{ticker} SL modified >>> new TP: {stopLoss}") 303 | else: 304 | print("no modifications were made") 305 | 306 | else: 307 | print("ID not found in positions") 308 | 309 | 310 | # market orders 311 | 312 | 313 | def market_order_open(client, ticker, side, usd_size): 314 | """ 315 | 316 | this order will split ur size into 20 equal orders and rapid execute them in 0.25s time intervals 317 | 318 | :param client: bybit client 319 | :param ticker: ticker 320 | :param side: b > buy, s > sell 321 | :param usd_size: position size in usdt 322 | :return: 323 | """ 324 | 325 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 326 | 327 | orders = [] 328 | error = True 329 | if side == "b": 330 | side = "Buy" 331 | error = False 332 | elif side == "s": 333 | side = "Sell" 334 | error = False 335 | else: 336 | print(f"Error with side input || input: {side} || should be: b/s") 337 | 338 | if not error: 339 | last_price = get_last_price(client, ticker) 340 | coins_to_execute = round(usd_size / last_price, decimals) 341 | 342 | single_order = round(coins_to_execute / 20, decimals) 343 | if single_order > min_order_size_coin: 344 | if single_order < max_order_size_coin: 345 | for i in range(20): 346 | orders.append(single_order) 347 | else: 348 | print(f"single order to big to execute twap || order size: {single_order} || max order size: {max_order_size_coin} ") 349 | else: 350 | print(f"total twap size to low: {usd_size}$") 351 | 352 | time_delay = 0.25 353 | for order in orders: 354 | client.place_order(category="linear", symbol=ticker, side=side, orderType="Market", qty=order, timeInForce="IOC", reduceOnly=False) 355 | time.sleep(time_delay) 356 | 357 | 358 | def market_order_close(client, ticker, side, coin_size): 359 | """ 360 | this order will split ur size into 20 equal orders and rapid execute them in 0.25s time intervals, orders are reduce only 361 | 362 | :param client: bybit client 363 | :param ticker: ticker 364 | :param side: b > buy, s > sell 365 | :param usd_size: position size in usdt 366 | :return: 367 | """ 368 | 369 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 370 | 371 | orders = [] 372 | error = True 373 | if side == "b": 374 | side = "Buy" 375 | error = False 376 | elif side == "s": 377 | side = "Sell" 378 | error = False 379 | else: 380 | print(f"Error with side input || input: {side} || should be: b/s") 381 | 382 | if not error: 383 | single_order = round(coin_size / 20, decimals) 384 | if single_order > min_order_size_coin: 385 | if single_order < max_order_size_coin: 386 | for i in range(20): 387 | orders.append(single_order) 388 | else: 389 | print(f"single order to big to execute twap || order size: {single_order} || max order size: {max_order_size_coin} ") 390 | else: 391 | print(f"total twap size to low: {coin_size} coins") 392 | 393 | time_delay = 0.1 394 | for order in orders: 395 | loop_start = time.time() 396 | position_size = client.get_positions(category="linear", symbol=ticker)["result"]["list"][0]["size"] 397 | 398 | if order > float(position_size): 399 | order = float(position_size) 400 | client.place_order(category="linear", symbol=ticker, side=side, orderType="Market", qty=order, timeInForce="IOC", reduceOnly=True) 401 | break 402 | 403 | client.place_order(category="linear", symbol=ticker, side=side, orderType="Market", qty=order, timeInForce="IOC", reduceOnly=True) 404 | 405 | loop_end = time.time() 406 | if loop_end - loop_start > time_delay: 407 | pass 408 | else: 409 | interval = time_delay - (loop_end - loop_start) 410 | time.sleep(interval) 411 | 412 | 413 | def linear_twap_open(client, ticker, side, usd_size, duration, order_amount): 414 | """ 415 | fuction that split order into equal sized orders and executes them over specified duration with equal time delays 416 | :param client: bybit client 417 | :param usd_size: size in usd 418 | :param ticker: choose ticker 419 | :param side: b > buy, s > sell 420 | :param duration: in seconds 421 | :param order_amount: amount of orders [default: 100 orders, int: specific number of orders) 422 | :return: 423 | """ 424 | 425 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 426 | 427 | orders = [] 428 | error = True 429 | if side == "b": 430 | side = "Buy" 431 | error = False 432 | elif side == "s": 433 | side = "Sell" 434 | error = False 435 | else: 436 | print(f"Error with side input || input: {side} || should be: b/s") 437 | 438 | if not error: 439 | if order_amount == "default": 440 | single_order = round(usd_size / 100) 441 | for i in range(100): 442 | orders.append(single_order) 443 | else: 444 | single_order = round(usd_size / order_amount) 445 | for i in range(order_amount): 446 | orders.append(single_order) 447 | 448 | time_delay = duration / order_amount # seconds 449 | 450 | for order in orders: 451 | loop_start = time.time() 452 | last_price = get_last_price(client, ticker) 453 | order = round(order / last_price, decimals) 454 | if order > min_order_size_coin: 455 | if order < max_order_size_coin: 456 | client.place_order(category="linear", symbol=ticker, side=side, orderType="Market", qty=order, timeInForce="IOC", reduceOnly=False) 457 | else: 458 | print(f"order to big tp execute || order: {order} || max order: {max_order_size_coin}") 459 | break 460 | else: 461 | print(f"order to low to be able to execute || order: {order} || min order: {min_order_size_coin}") 462 | break 463 | 464 | loop_end = time.time() 465 | if loop_end - loop_start > time_delay: 466 | pass 467 | else: 468 | interval = time_delay - (loop_end - loop_start) 469 | time.sleep(interval) 470 | 471 | 472 | def linear_twap_close(client, ticker, side, coin_size, duration, order_amount): 473 | """ 474 | fuction that split order into equal sized orders and executes them over specified duration with equal time delays 475 | :param client: bybit client 476 | :param usd_size: size in usd 477 | :param ticker: choose ticker 478 | :param side: b > buy, s > sell 479 | :param duration: in seconds 480 | :param order_amount: amount of orders [default: 100 orders, int: specific number of orders) 481 | :return: 482 | """ 483 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 484 | 485 | orders = [] 486 | error = True 487 | if side == "b": 488 | side = "Buy" 489 | error = False 490 | elif side == "s": 491 | side = "Sell" 492 | error = False 493 | else: 494 | print(f"Error with side input || input: {side} || should be: b/s") 495 | 496 | if not error: 497 | single_order = round(coin_size / order_amount, decimals) 498 | if single_order > min_order_size_coin: 499 | if single_order < max_order_size_coin: 500 | for i in range(order_amount): 501 | orders.append(single_order) 502 | else: 503 | print(f"single order to big to execute twap || order size: {single_order} || max order size: {max_order_size_coin} ") 504 | else: 505 | print(f"total twap size to low: {coin_size} coins") 506 | 507 | time_delay = duration / order_amount # seconds 508 | 509 | for order in orders: 510 | loop_start = time.time() 511 | last_price = get_last_price(client, ticker) 512 | order = round(order, decimals) 513 | if order > min_order_size_coin: 514 | if order < max_order_size_coin: 515 | position_size = client.get_positions(category="linear", symbol=ticker)["result"]["list"][0]["size"] 516 | 517 | if order > float(position_size): 518 | order = float(position_size) 519 | client.place_order(category="linear", symbol=ticker, side=side, orderType="Market", qty=order, timeInForce="IOC", reduceOnly=True) 520 | break 521 | 522 | client.place_order(category="linear", symbol=ticker, side=side, orderType="Market", qty=order, timeInForce="IOC", reduceOnly=True) 523 | 524 | else: 525 | print(f"order to big tp execute || order: {order} || max order: {max_order_size_coin}") 526 | break 527 | else: 528 | print(f"order to low to be able to execute || order: {order} || min order: {min_order_size_coin}") 529 | break 530 | 531 | loop_end = time.time() 532 | if loop_end - loop_start > time_delay: 533 | pass 534 | else: 535 | interval = time_delay - (loop_end - loop_start) 536 | time.sleep(interval) 537 | 538 | 539 | # limit oders 540 | 541 | def limit_tranche_open(client, usd_size, ticker, side, upper_price, lower_price, order_amount, bid_ask:bool): 542 | """ 543 | 544 | :param client: bybit client 545 | :param usd_size: total size 546 | :param ticker: ticker 547 | :param side: b > buy, s > sell 548 | :param upper_price: upper bound for limit orders 549 | :param lower_price: lower bound for limit orders 550 | :return: 551 | """ 552 | 553 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 554 | tick_decimals = str(tick_size)[::-1].find('.') 555 | orders = [] 556 | 557 | # Calculate the spacing between orders 558 | spacing = (upper_price - lower_price) / (order_amount) 559 | last_price = get_last_price(client, ticker) 560 | if side == "b": 561 | side = "Buy" 562 | elif side == "s": 563 | side = "Sell" 564 | 565 | error = True 566 | if not bid_ask: 567 | if upper_price > lower_price: 568 | if side == "Buy": 569 | if last_price > upper_price: 570 | error = False 571 | else: 572 | print("on buy side last price should be higher than upper price limit") 573 | elif side == "Sell": 574 | if last_price < lower_price: 575 | error = False 576 | else: 577 | print("on sell side last price should be lower than lower price limit") 578 | else: 579 | print(f"Error with side input || input: {side} || should be: b/s") 580 | else: 581 | print("upper price limit should be higher than lower price limit") 582 | else: 583 | error = False 584 | 585 | if not error: 586 | single_order = int(usd_size / order_amount) 587 | price = lower_price 588 | for i in range(order_amount): 589 | orders.append([round(single_order / price, decimals), round(price, tick_decimals)]) 590 | price += spacing 591 | 592 | for order in orders: 593 | client.place_order(category="linear", symbol=ticker, side=side, orderType="Limit", qty=order[0], price=order[1], timeInForce="GTC", reduceOnly=False) 594 | time.sleep(0.01) 595 | 596 | 597 | def limit_tranche_close(client, coin_size, ticker, side, upper_price, lower_price, order_amount, bid_ask:bool): 598 | """ 599 | 600 | :param client: bybit client 601 | :param usd_size: total size 602 | :param ticker: ticker 603 | :param side: b > buy, s > sell 604 | :param upper_price: upper bound for limit orders 605 | :param lower_price: lower bound for limit orders 606 | :return: 607 | """ 608 | 609 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 610 | tick_decimals = str(tick_size)[::-1].find('.') 611 | orders = [] 612 | 613 | # Calculate the spacing between orders 614 | spacing = (upper_price - lower_price) / (order_amount) 615 | last_price = get_last_price(client, ticker) 616 | if side == "b": 617 | side = "Buy" 618 | elif side == "s": 619 | side = "Sell" 620 | 621 | error = True 622 | if not bid_ask: 623 | if upper_price > lower_price: 624 | if side == "Buy": 625 | if last_price > upper_price: 626 | error = False 627 | else: 628 | print("on buy side last price should be higher than upper price limit") 629 | elif side == "Sell": 630 | if last_price < lower_price: 631 | error = False 632 | else: 633 | print("on sell side last price should be lower than lower price limit") 634 | else: 635 | print(f"Error with side input || input: {side} || should be: b/s") 636 | else: 637 | print("upper price limit should be higher than lower price limit") 638 | else: 639 | error = False 640 | 641 | if not error: 642 | single_order = round(coin_size / order_amount, decimals) 643 | price = lower_price 644 | for i in range(order_amount): 645 | orders.append([round(single_order, decimals), round(price, tick_decimals)]) 646 | price += spacing 647 | 648 | for order in orders: 649 | client.place_order(category="linear", symbol=ticker, side=side, orderType="Limit", qty=order[0], price=order[1], timeInForce="GTC", reduceOnly=True) 650 | time.sleep(0.01) 651 | 652 | 653 | 654 | # risk limit check 655 | def check_risk_limit(client, ticker, usd_size, side): 656 | 657 | risk_ok = False 658 | position = client.get_positions(category="linear", symbol=ticker)["result"]["list"][0] 659 | position_size_limit = float(position["riskLimitValue"]) 660 | curr_pos_size_coins = float(position["size"]) 661 | 662 | if curr_pos_size_coins > 0: 663 | if position["side"] == "Buy" and side == "b": 664 | new_total_size = float(position["positionValue"]) + usd_size 665 | if new_total_size < position_size_limit: 666 | risk_ok = True 667 | else: 668 | print("\n") 669 | print(f"risk limit would be exceded adjust risk limits or choose lower pos size || risk limit: {position_size_limit}") 670 | print("\n") 671 | elif position["side"] == "Sell" and side == "s": 672 | new_total_size = float(position["positionValue"]) + usd_size 673 | if new_total_size < position_size_limit: 674 | risk_ok = True 675 | else: 676 | if usd_size < position_size_limit: 677 | risk_ok = True 678 | else: 679 | if usd_size < position_size_limit: 680 | risk_ok = True 681 | else: 682 | print("\n") 683 | print(f"risk limit would be exceded adjust risk limits or choose lower pos size || risk limit: {position_size_limit}") 684 | print("\n") 685 | 686 | return risk_ok 687 | 688 | 689 | def select_close_id_futures(client): 690 | positions = get_open_positions(client=client, display=True) 691 | 692 | try: 693 | 694 | while True: 695 | close_id = int(input("select ID of the position you wish to close >>> ")) 696 | 697 | if close_id in positions.keys(): 698 | position = positions[close_id] 699 | ticker = position["symbol"] 700 | side = position["side"] 701 | size = float(position["size"]) 702 | usd_value = float(position["positionValue"]) 703 | 704 | if side == "Buy": 705 | side = "s" 706 | elif side == "Sell": 707 | side = "b" 708 | 709 | return close_id, ticker, side, size, usd_value 710 | else: 711 | print("Wrong ID selected") 712 | except: 713 | print("Error: ID must be number") 714 | 715 | 716 | def set_market_order_open(client): 717 | """ 718 | 719 | :param client: 720 | :return: 721 | """ 722 | 723 | tickers = get_usdt_futures_tickers(client=client) 724 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=False) 725 | 726 | side = cli_inputs.select_side() 727 | usd_size = cli_inputs.select_usdt_size() 728 | 729 | market_order_thread = Thread(target=market_order_open, args=(client, ticker, side, usd_size), name=f"FUTURES_{ticker}_{side}_{usd_size}").start() 730 | 731 | 732 | def set_market_order_close(client): 733 | """ 734 | 735 | :param client: 736 | :return: 737 | """ 738 | 739 | close_id, ticker, side, size, usd_value = select_close_id_futures(client) 740 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 741 | 742 | pct = cli_inputs.select_pct() 743 | coin_size = round(size * pct, decimals) 744 | 745 | market_order_thread = Thread(target=market_order_close, args=(client, ticker, side, coin_size), name=f"FUTURES_{ticker}_{side}_{coin_size}_coins").start() 746 | 747 | 748 | def set_linear_twap_open(client): 749 | tickers = get_usdt_futures_tickers(client=client) 750 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=False) 751 | 752 | side = cli_inputs.select_side() 753 | usd_size = cli_inputs.select_usdt_size() 754 | duration = cli_inputs.select_duration() 755 | order_amount = cli_inputs.select_order_amount() 756 | 757 | linear_twap_thread = Thread(target=linear_twap_open, args=(client, ticker, side, usd_size, duration, order_amount), name=f"FUTURES_{ticker}_{side}_{usd_size}_twap{round(duration / 60)}min").start() 758 | 759 | 760 | def set_linear_twap_close(client): 761 | """ 762 | 763 | :param client: 764 | :return: 765 | """ 766 | 767 | close_id, ticker, side, size, usd_value = select_close_id_futures(client) 768 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 769 | 770 | pct = cli_inputs.select_pct() 771 | coin_size = round(size * pct, decimals) 772 | duration = cli_inputs.select_duration() 773 | order_amount = cli_inputs.select_order_amount() 774 | 775 | linear_twap_thread = Thread(target=linear_twap_close, args=(client, ticker, side, coin_size, duration, order_amount), name=f"FUTURES_{ticker}_{side}_{coin_size}_coins_twap{round(duration / 60)}min").start() 776 | 777 | 778 | def set_limits_open(client): 779 | 780 | positions = get_open_positions(client, False) 781 | 782 | tickers = get_usdt_futures_tickers(client=client) 783 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=False) 784 | side = cli_inputs.select_side() 785 | usd_size = cli_inputs.select_usdt_size() 786 | upper_price = cli_inputs.select_upper_limit_price() 787 | lower_price = cli_inputs.select_lower_limit_price() 788 | order_amount = cli_inputs.select_order_amount() 789 | bid_ask = False 790 | position_exits = False 791 | position = None 792 | for key, value in positions.items(): 793 | if value["symbol"] == ticker: 794 | position_exits = True 795 | position = value 796 | break 797 | 798 | if not position_exits: 799 | # do you want to place sl ? 800 | sl_check = 0 801 | while sl_check not in [1, 2]: 802 | sl_check = int(input("Do you want to place stoploss ?[1 > yes, 2 > no] >>> ")) 803 | if sl_check in [1, 2]: 804 | if sl_check == 1: 805 | sl_price_ok = False 806 | sl_side = None 807 | while not sl_price_ok: 808 | if side == "b": 809 | sl_price = float(input("Choose stoploss price >>> ")) 810 | try: 811 | if sl_price > 0 and sl_price < lower_price: 812 | sl_price_ok = True 813 | sl_side = "Sell" 814 | client.place_order(category="linear", symbol=ticker, side=sl_side, orderType="Market", qty="0", triggerDirection=2, timeInForce="IOC", reduceOnly=True, closeOnTrigger=True, triggerBy="LastPrice", triggerPrice=str(sl_price)) 815 | except: 816 | print("Wrong stoploss input, must be number and lower than lowest limit order") 817 | 818 | elif side == "s": 819 | sl_price = float(input("Choose stoploss price >>> ")) 820 | try: 821 | if sl_price > upper_price: 822 | sl_price_ok = True 823 | sl_side = "Buy" 824 | client.place_order(category="linear", symbol=ticker, side=sl_side, orderType="Market", qty="0", triggerDirection=1, timeInForce="IOC", reduceOnly=True, closeOnTrigger=True, triggerBy="LastPrice", triggerPrice=str(sl_price)) 825 | except: 826 | print("Wrong stoploss input, must be number and higher than highest limit order") 827 | else: 828 | print("wrong input, try again") 829 | 830 | 831 | limit_open_thread = Thread(target=limit_tranche_open, args=(client, usd_size, ticker, side, upper_price, lower_price, order_amount, bid_ask), name=f"FUTURES_{ticker}_{side}_limit_tranche_{usd_size}").start() 832 | 833 | 834 | def set_limits_close(client): 835 | close_id, ticker, side, size, usd_value = select_close_id_futures(client) 836 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 837 | bid_ask = False 838 | close = False 839 | while not close: 840 | close_by = input("close by: usd size or % [1-usd, 2-%] >>> ") 841 | if int(close_by) == 1: 842 | usd_size = cli_inputs.select_usdt_size() 843 | last_price = get_last_price(client, ticker) 844 | coin_size = round(usd_size / last_price, decimals) 845 | close = True 846 | elif int(close_by) == 2: 847 | pct = cli_inputs.select_pct() 848 | coin_size = round(size * pct, decimals) 849 | close = True 850 | else: 851 | print("Wrong input should be 1 or 2") 852 | 853 | upper_price = cli_inputs.select_upper_limit_price() 854 | lower_price = cli_inputs.select_lower_limit_price() 855 | order_amount = cli_inputs.select_order_amount() 856 | 857 | if close: 858 | limit_close_thread = Thread(target=limit_tranche_close, args=(client, coin_size, ticker, side, upper_price, lower_price, order_amount, bid_ask), name=f"FUTURES_{ticker}_{side}_limit_tranche_{coin_size}").start() 859 | 860 | 861 | def set_limits_at_bidask_open(client): 862 | positions = get_open_positions(client, False) 863 | 864 | tickers = get_usdt_futures_tickers(client=client) 865 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=False) 866 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 867 | tick_decimals = str(tick_size)[::-1].find('.') 868 | 869 | side = cli_inputs.select_side() 870 | usd_size = cli_inputs.select_usdt_size() 871 | 872 | bps_range = 0.004 873 | if ticker in ["BTCUSDT", "ETHUSDT"]: 874 | bps_range = 0.001 875 | last_price = get_last_price(client, ticker) 876 | 877 | if side == "b": 878 | upper_price = last_price 879 | lower_price = round( upper_price - (last_price * bps_range) ,tick_decimals) 880 | elif side == "s": 881 | lower_price = last_price 882 | upper_price = round(lower_price + (last_price * bps_range), tick_decimals) 883 | 884 | order_amount = 10 885 | bid_ask = True 886 | 887 | position_exits = False 888 | position = None 889 | for key, value in positions.items(): 890 | if value["symbol"] == ticker: 891 | position_exits = True 892 | position = value 893 | break 894 | 895 | if not position_exits: 896 | # do you want to place sl ? 897 | sl_check = 0 898 | while sl_check not in [1, 2]: 899 | sl_check = int(input("Do you want to place stoploss ?[1 > yes, 2 > no] >>> ")) 900 | if sl_check in [1, 2]: 901 | if sl_check == 1: 902 | sl_price_ok = False 903 | sl_side = None 904 | while not sl_price_ok: 905 | if side == "b": 906 | sl_price = float(input("Choose stoploss price >>> ")) 907 | try: 908 | if sl_price > 0 and sl_price < lower_price: 909 | sl_price_ok = True 910 | sl_side = "Sell" 911 | client.place_order(category="linear", symbol=ticker, side=sl_side, orderType="Market", qty="0", triggerDirection=2, timeInForce="IOC", reduceOnly=True, closeOnTrigger=True, triggerBy="LastPrice", triggerPrice=str(sl_price)) 912 | except: 913 | print("Wrong stoploss input, must be number and lower than lowest limit order") 914 | 915 | elif side == "s": 916 | sl_price = float(input("Choose stoploss price >>> ")) 917 | try: 918 | if sl_price > upper_price: 919 | sl_price_ok = True 920 | sl_side = "Buy" 921 | client.place_order(category="linear", symbol=ticker, side=sl_side, orderType="Market", qty="0", triggerDirection=1, timeInForce="IOC", reduceOnly=True, closeOnTrigger=True, triggerBy="LastPrice", triggerPrice=str(sl_price)) 922 | except: 923 | print("Wrong stoploss input, must be number and higher than highest limit order") 924 | else: 925 | print("wrong input, try again") 926 | 927 | limit_open_thread = Thread(target=limit_tranche_open, args=(client, usd_size, ticker, side, upper_price, lower_price, order_amount, bid_ask), name=f"FUTURES_{ticker}_{side}_limit_tranche_{usd_size}").start() 928 | 929 | 930 | def set_limits_at_bidask_close(client): 931 | close_id, ticker, side, size, usd_value = select_close_id_futures(client) 932 | max_order_size_coin, min_order_size_coin, decimals, tick_size, position_size_limit = get_instrument_info(client, ticker) 933 | tick_decimals = str(tick_size)[::-1].find('.') 934 | 935 | bps_range = 0.004 936 | if ticker in ["BTCUSDT", "ETHUSDT"]: 937 | bps_range = 0.001 938 | 939 | 940 | bid_ask = True 941 | close = False 942 | while not close: 943 | close_by = input("close by: usd size or % [1-usd, 2-%] >>> ") 944 | if int(close_by) == 1: 945 | usd_size = cli_inputs.select_usdt_size() 946 | last_price = get_last_price(client, ticker) 947 | coin_size = round(usd_size / last_price, decimals) 948 | close = True 949 | elif int(close_by) == 2: 950 | pct = cli_inputs.select_pct() 951 | coin_size = round(size * pct, decimals) 952 | close = True 953 | else: 954 | print("Wrong input should be 1 or 2") 955 | 956 | last_price = get_last_price(client, ticker) 957 | if side == "b": 958 | upper_price = last_price 959 | lower_price = round(upper_price - (last_price * bps_range), tick_decimals) 960 | elif side == "s": 961 | lower_price = last_price 962 | upper_price = round(lower_price + (last_price * bps_range), tick_decimals) 963 | 964 | order_amount = 10 965 | 966 | if close: 967 | limit_close_thread = Thread(target=limit_tranche_close, args=(client, coin_size, ticker, side, upper_price, lower_price, order_amount, bid_ask), name=f"FUTURES_{ticker}_{side}_limit_tranche_{coin_size}").start() 968 | 969 | 970 | def set_multiple_twaps_open(client): 971 | 972 | exit_ = False 973 | 974 | tickers = get_usdt_futures_tickers(client=client) 975 | twaps = [] 976 | mode = 0 977 | while not exit_: 978 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=False) 979 | side = cli_inputs.select_side() 980 | usd_size = cli_inputs.select_usdt_size() 981 | order_amount = cli_inputs.select_order_amount() 982 | duration = cli_inputs.select_duration() 983 | print("\n") 984 | 985 | twaps.append([ticker,side, usd_size, duration, order_amount]) 986 | mode = 0 987 | 988 | while mode not in [1,2]: 989 | mode = int(input("add another twap/exit [1- another twap, 2-exit] >>> ")) 990 | if mode == 2: 991 | exit_ = True 992 | elif mode not in [1,2]: 993 | print("Wrong input, input must be 1 or 2") 994 | 995 | if twaps: 996 | print("Executing following twaps:") 997 | for i in twaps: 998 | print(f"{i[0]} - {i[1]} - {i[2]} usd - {i[3] / 60}min") 999 | 1000 | linear_twap_thread = Thread(target=linear_twap_open, args=(client, i[0], i[1], i[2], i[3], i[4]), name=f"FUTURES_{i[0]}_{i[1]}_{i[2]}_twap{round(i[3] / 60)}min").start() 1001 | 1002 | 1003 | def set_multiple_twaps_close(client): 1004 | 1005 | exit_ = False 1006 | mode = 0 1007 | while not exit_: 1008 | 1009 | set_linear_twap_close(client) 1010 | mode = 0 1011 | 1012 | while mode not in [1, 2]: 1013 | mode = int(input("add another twap_close/exit [1- another twap, 2-exit] >>> ")) 1014 | if mode == 2: 1015 | exit_ = True 1016 | elif mode not in [1, 2]: 1017 | print("Wrong input, input must be 1 or 2") 1018 | 1019 | 1020 | def close_all_positions(client): 1021 | """ 1022 | Function that close all open positions 1023 | :param client: 1024 | :return: 1025 | """ 1026 | 1027 | positions = get_open_positions(client=client, display=False) 1028 | if positions: 1029 | print("Select duration in which you want to close all positions[minutes]") 1030 | duration = cli_inputs.select_duration() 1031 | for close_id in positions.keys(): 1032 | position = positions[close_id] 1033 | ticker = position["symbol"] 1034 | side = position["side"] 1035 | coin_size = float(position["size"]) 1036 | usd_value = float(position["positionValue"]) 1037 | 1038 | if side == "Buy": 1039 | side_ = "long" 1040 | side = "s" 1041 | elif side == "Sell": 1042 | side_ = "short" 1043 | side = "b" 1044 | 1045 | if duration > 400: 1046 | if usd_value <= 20000: 1047 | order_amount = 20 1048 | elif 20000 < usd_value <= 50000: 1049 | order_amount = 50 1050 | elif 50000 < usd_value <= 100000: 1051 | order_amount = 100 1052 | elif 100000 < usd_value <= 250000: 1053 | order_amount = 150 1054 | elif 250000 < usd_value <= 500000: 1055 | order_amount = 200 1056 | elif 500000 < usd_value <= 1000000: 1057 | order_amount = 300 1058 | elif usd_value > 1000000: 1059 | order_amount = 400 1060 | else: 1061 | if usd_value <= 20000: 1062 | order_amount = 1 1063 | elif 20000 < usd_value <= 50000: 1064 | order_amount = 3 1065 | elif 50000 < usd_value <= 100000: 1066 | order_amount = 5 1067 | elif 100000 < usd_value <= 250000: 1068 | order_amount = 10 1069 | elif 250000 < usd_value <= 500000: 1070 | order_amount = 15 1071 | elif 500000 < usd_value <= 1000000: 1072 | order_amount = 30 1073 | elif usd_value > 1000000: 1074 | order_amount = 45 1075 | 1076 | print(f"started closing {ticker} {side_} || {coin_size} coins") 1077 | linear_twap_thread = Thread(target=linear_twap_close, args=(client, ticker, side, coin_size, duration, order_amount), name=f"FUTURES_{ticker}_{side}_{coin_size}_coins_twap{round(duration / 60)}min").start() 1078 | else: 1079 | print("\nNo open positions") 1080 | 1081 | 1082 | def bid_IO_wipe(client): 1083 | """ 1084 | Function that sets limits order in prefered % range below from current price >> it's buy only function 1085 | :param client: 1086 | :return: 1087 | """ 1088 | tickers = get_usdt_futures_tickers(client=client) 1089 | print("\nSelect % below price where you want to bid > ex: [15-30% below current price]") 1090 | upper_pct = cli_inputs.select_upper_pct() 1091 | lower_pct = cli_inputs.select_lower_pct() 1092 | 1093 | if upper_pct < lower_pct: 1094 | side = "b" 1095 | 1096 | exit_ = False 1097 | 1098 | tickers = get_usdt_futures_tickers(client=client) 1099 | while not exit_: 1100 | 1101 | ticker = cli_inputs.select_ticker(tickers=tickers, spot=False) 1102 | usd_size = cli_inputs.select_usdt_size() 1103 | last_price = get_last_price(client, ticker) 1104 | 1105 | upper_price = last_price - (last_price * upper_pct) 1106 | lower_price = last_price - (last_price * lower_pct) 1107 | 1108 | if usd_size <= 20000: 1109 | order_amount = 10 1110 | elif 20000 < usd_size <= 50000: 1111 | order_amount = 20 1112 | elif 50000 < usd_size <= 100000: 1113 | order_amount = 30 1114 | elif 100000 < usd_size <= 250000: 1115 | order_amount = 40 1116 | elif 250000 < usd_size <= 500000: 1117 | order_amount = 50 1118 | elif usd_size > 500000: 1119 | order_amount = 70 1120 | 1121 | 1122 | limit_open_thread = Thread(target=limit_tranche_open, args=(client, usd_size, ticker, side, upper_price, lower_price, order_amount), name=f"FUTURES_{ticker}_{side}_limit_tranche_{usd_size}").start() 1123 | 1124 | mode = 0 1125 | while mode not in [1,2]: 1126 | mode = int(input("add another coin bids/exit [1- another coin, 2-exit] >>> ")) 1127 | if mode == 2: 1128 | exit_ = True 1129 | elif mode not in [1,2]: 1130 | print("Wrong input, input must be 1 or 2") 1131 | else: 1132 | print("\nUpper % must be lower number than lower %") 1133 | 1134 | 1135 | 1136 | # todo: TESTING 1137 | # api_key, api_secret = get_credentials(account="personal") 1138 | # client = auth(api_key, api_secret) 1139 | 1140 | 1141 | # set_limits_at_bidask_open(client) 1142 | # set_limits_at_bidask_close(client) 1143 | 1144 | 1145 | # set_limits_open(client) 1146 | 1147 | # bid_IO_wipe(client) 1148 | 1149 | # close_all_positions(client) 1150 | 1151 | # set_multiple_twaps_open(client) 1152 | # set_multiple_twaps_close(client) 1153 | 1154 | # usdt = get_usdt_balance(client) 1155 | # tickers = get_usdt_futures_tickers(client) 1156 | 1157 | # set_limits_close(client) 1158 | # set_limits_at_avgPrc_close(client) 1159 | 1160 | # set_limits_open(client) 1161 | # set_limits_at_avgPrc_open(client) 1162 | 1163 | # set_linear_twap_open(client) 1164 | # set_linear_twap_close(client) 1165 | 1166 | # set_market_order_open(client) 1167 | # set_market_order_close(client) 1168 | 1169 | 1170 | # get_instrument_info(client, "BTCUSDT") 1171 | # positions = get_open_positions(client, display=True) 1172 | 1173 | # market_order(client, "ETHUSDT", "s", 1000) 1174 | # market_close(client, "ETHUSDT", "b", 0.6) 1175 | 1176 | # linear_twap_open(client, "ETHUSDT", "s", 1000, 30, 5) 1177 | # linear_twap_close(client, "ETHUSDT", "b", 1000, 30, 5) 1178 | 1179 | # limit_tranche_open(client, 1000, "ETHUSDT", "b", 1770, 1740, 5) 1180 | # limit_tranche_close(client, 0.55, "ETHUSDT", "b", 1780, 1740, 5) 1181 | 1182 | 1183 | # limit_tranche_avg_price_reduce(client, 0.028, "BTCUSDT", "s", 35800, 35500, 35600, 5) -------------------------------------------------------------------------------- /bybit/cli_inputs.py: -------------------------------------------------------------------------------- 1 | # CLI inputs 2 | from pybit.unified_trading import HTTP 3 | import pandas as pd 4 | 5 | def auth(): 6 | bybit_client = HTTP(testnet=False, api_key="", api_secret="") 7 | return bybit_client 8 | 9 | 10 | def ob_depth(ticker, spot:bool): 11 | client = auth() 12 | if spot: 13 | ob = client.get_orderbook(category="spot", symbol=ticker, limit=200)["result"] 14 | else: 15 | ob = client.get_orderbook(category="linear", symbol=ticker, limit=200)["result"] 16 | 17 | bids = ob["b"] 18 | asks = ob["a"] 19 | bid_df = pd.DataFrame(bids, columns=["price", "size"]) 20 | ask_df = pd.DataFrame(asks, columns=["price", "size"]) 21 | 22 | bid_df["price"] = pd.to_numeric(bid_df["price"]) 23 | bid_df["size"] = pd.to_numeric(bid_df["size"]) 24 | 25 | bid_depth = round(abs(((bid_df["price"].head(1).values[0] / bid_df["price"].tail(1).values[0])-1) * 100), 4) 26 | avg_bid_price = bid_df["price"].mean() 27 | total_bid_size_coins = bid_df["size"].sum() 28 | bid_usd_depth = avg_bid_price * total_bid_size_coins 29 | 30 | if bid_usd_depth > 1000000: 31 | bid_usd_depth = f"{round(bid_usd_depth / 1000000, 3)} Mil" 32 | else: 33 | bid_usd_depth = f"{round(bid_usd_depth / 1000, 1)} k" 34 | 35 | 36 | ask_df["price"] = pd.to_numeric(ask_df["price"]) 37 | ask_df["size"] = pd.to_numeric(ask_df["size"]) 38 | 39 | ask_depth = round(abs(((ask_df["price"].head(1).values[0] / ask_df["price"].tail(1).values[0]) - 1) * 100), 4) 40 | avg_ask_price = ask_df["price"].mean() 41 | total_ask_size_coins = ask_df["size"].sum() 42 | ask_usd_depth = avg_ask_price * total_ask_size_coins 43 | 44 | if ask_usd_depth > 1000000: 45 | ask_usd_depth = f"{round(ask_usd_depth / 1000000, 3)} Mil" 46 | else: 47 | ask_usd_depth = f"{round(ask_usd_depth / 1000, 1)} k" 48 | 49 | print(f"ob data for: {ticker}") 50 | print(f"BID: 200_level depth: {bid_depth} % | usd depth: {bid_usd_depth}") 51 | print(f"ASK: 200_level depth: {ask_depth} % | usd depth: {ask_usd_depth}") 52 | 53 | 54 | def select_ticker(tickers, spot:bool): 55 | ticker_selected = False 56 | while not ticker_selected: 57 | try: 58 | input_ticker = input("select ticker[without denominator -> ex: btc] >>> ") 59 | ticker = tickers[input_ticker.upper()] 60 | print(f"{ticker} selected") 61 | ob_depth(ticker, spot) 62 | 63 | ticker_selected = True 64 | return ticker 65 | except: 66 | print("Invalid ticker selected >> try again") 67 | 68 | 69 | def select_order_amount(): 70 | """ 71 | :return: number of orders 72 | """ 73 | order_amount_selected = False 74 | while not order_amount_selected: 75 | order_number = input("select number of orders or type def for default option[15 orders] >>> ") 76 | try: 77 | if order_number.lower() == "def": 78 | order_number = "default" 79 | order_amount_selected = True 80 | return order_number 81 | else: 82 | order_number = int(order_number) 83 | order_amount_selected = True 84 | return order_number 85 | except: 86 | print("Error selecting number of orders: input must be number") 87 | 88 | 89 | def select_usdt_size(): 90 | """ 91 | :return: position size in usdt 92 | """ 93 | size_selected = False 94 | while not size_selected: 95 | input_size = input("select position size[usdt] >>> ") 96 | try: 97 | input_size = int(input_size) 98 | size_selected = True 99 | return input_size 100 | except: 101 | print("Error selecting positions size: input must be number") 102 | 103 | 104 | def select_duration(): 105 | """ 106 | :return: duration in seconds 107 | """ 108 | duration_selected = False 109 | while not duration_selected: 110 | 111 | input_duration = input("select duration minutes >>> ") 112 | try: 113 | input_duration = float(input_duration) * 60 114 | duration_selected = True 115 | return input_duration 116 | except: 117 | print("Error selecting duration input must be number") 118 | 119 | 120 | def select_side(): 121 | """ 122 | :return: order side 123 | """ 124 | side_selected = False 125 | while not side_selected: 126 | input_side = input("select side b=Buy, s=Sell >>> ") 127 | if input_side.lower() == "b": 128 | input_side = input_side.lower() 129 | side_selected = True 130 | return input_side 131 | elif input_side.lower() == "s": 132 | input_side = input_side.lower() 133 | side_selected = True 134 | return input_side 135 | else: 136 | print("Error with selecting side") 137 | 138 | 139 | def select_pct(): 140 | """ 141 | :return: % in basis points from 0-1 142 | """ 143 | pct_selected = False 144 | while not pct_selected: 145 | 146 | pct_input = input("select how much of acc. you want to buy/sell [1-100 %] >>> ") 147 | try: 148 | if 0 < float(pct_input) <= 100: 149 | pct_input = float(pct_input) / 100 150 | 151 | pct_selected = True 152 | return pct_input 153 | else: 154 | print("Error choose % between 1 and 100") 155 | except: 156 | print("Error selecting %: input must be number") 157 | 158 | 159 | def select_upper_limit_price(): 160 | """ 161 | 162 | :return: upper limit price for limit order tranche 163 | """ 164 | price_selected = False 165 | while not price_selected: 166 | 167 | input_price = input("input upper limit price >>> ") 168 | try: 169 | input_price = float(input_price) 170 | price_selected = True 171 | return input_price 172 | except: 173 | print("Error selecting upper limit price") 174 | 175 | 176 | def select_lower_limit_price(): 177 | """ 178 | :return: lower limit price for limit order tranche 179 | """ 180 | price_selected = False 181 | while not price_selected: 182 | input_price = input("input lower limit price >>> ") 183 | try: 184 | input_price = float(input_price) 185 | price_selected = True 186 | return input_price 187 | except: 188 | print("Error selecting lower limit price") 189 | 190 | 191 | def select_avg_limit_price(): 192 | """ 193 | :return: avg limit price for limit order tranche 194 | """ 195 | price_selected = False 196 | while not price_selected: 197 | input_price = input("input avg limit price >>> ") 198 | try: 199 | input_price = float(input_price) 200 | price_selected = True 201 | return input_price 202 | except: 203 | print("Error selecting avg limit price") 204 | 205 | 206 | def select_lookback_window(): 207 | """ 208 | :return: lookcback window[hours] 209 | """ 210 | window_selected = False 211 | while not window_selected: 212 | input_number = input("select lookback window[hours] >>> ") 213 | try: 214 | input_number = int(input_number) 215 | window_selected = True 216 | return input_number 217 | except: 218 | print("Error selecting lookback window") 219 | 220 | 221 | def select_upper_pct(): 222 | """ 223 | :return: % in basis points from 0-1 224 | """ 225 | pct_selected = False 226 | while not pct_selected: 227 | 228 | pct_input = input("select upper % point of where you want to bid >>> ") 229 | try: 230 | if 0 < float(pct_input) <= 100: 231 | pct_input = float(pct_input) / 100 232 | 233 | pct_selected = True 234 | return pct_input 235 | else: 236 | print("Error choose % between 1 and 100") 237 | except: 238 | print("Error selecting %: input must be number") 239 | 240 | 241 | def select_lower_pct(): 242 | """ 243 | :return: % in basis points from 0-1 244 | """ 245 | pct_selected = False 246 | while not pct_selected: 247 | 248 | pct_input = input("select lower % point of where you want to bid >>> ") 249 | try: 250 | if 0 < float(pct_input) <= 100: 251 | pct_input = float(pct_input) / 100 252 | 253 | pct_selected = True 254 | return pct_input 255 | else: 256 | print("Error choose % between 1 and 100") 257 | except: 258 | print("Error selecting %: input must be number") -------------------------------------------------------------------------------- /bybit/credentials.json: -------------------------------------------------------------------------------- 1 | { 2 | "personal": { 3 | "bybit_api_key": "", 4 | "bybit_secret_key": "" 5 | } 6 | 7 | } -------------------------------------------------------------------------------- /bybit/order_overview.py: -------------------------------------------------------------------------------- 1 | from pybit.unified_trading import HTTP 2 | import time 3 | import pandas as pd 4 | import datetime as dt 5 | import json 6 | from pathlib import Path 7 | import cli_inputs 8 | from threading import Thread 9 | 10 | 11 | def get_credentials(account): 12 | root = Path(".") 13 | file_path = f"{root}/credentials.json" 14 | 15 | with open(file_path) as file: 16 | 17 | file = file.read() 18 | credentials = json.loads(file) 19 | 20 | api_key = credentials[account]["bybit_api_key"] 21 | api_secret = credentials[account]["bybit_secret_key"] 22 | 23 | return api_key, api_secret 24 | 25 | 26 | def auth(api_key, api_secret): 27 | bybit_client = HTTP(testnet=False, api_key=api_key, api_secret=api_secret) 28 | 29 | return bybit_client 30 | 31 | 32 | def get_spot_usdt_tickers(client): 33 | symbols = client.get_instruments_info(category="spot")["result"]["list"] 34 | tickers = {} 35 | for row in symbols: 36 | symbol = row["symbol"] 37 | ticker = row["symbol"] 38 | if "USDT" in symbol: 39 | 40 | symbol = symbol.replace("USDT", "") 41 | 42 | if "10000" in symbol: 43 | symbol = symbol.replace("10000", "") 44 | elif "1000" in symbol: 45 | symbol = symbol.replace("1000", "") 46 | 47 | tickers[symbol] = ticker 48 | 49 | return tickers 50 | 51 | def get_usdt_futures_tickers(client): 52 | symbols = client.get_instruments_info(category="linear")["result"]["list"] 53 | tickers = {} 54 | for row in symbols: 55 | symbol = row["symbol"] 56 | ticker = row["symbol"] 57 | if "USDT" in symbol: 58 | 59 | symbol = symbol.replace("USDT", "") 60 | 61 | if "10000" in symbol: 62 | symbol = symbol.replace("10000", "") 63 | elif "1000" in symbol: 64 | symbol = symbol.replace("1000", "") 65 | 66 | tickers[symbol] = ticker 67 | 68 | return tickers 69 | 70 | 71 | def get_all_spot_positions(client): 72 | balances = client.get_wallet_balance(accountType="UNIFIED")["result"]["list"][0]["coin"] 73 | 74 | spot_positions = [] 75 | 76 | for balance in balances: 77 | coin = balance["coin"] 78 | usd_value = round(float(balance["usdValue"])) 79 | coins = float(balance["walletBalance"]) 80 | 81 | if usd_value > 10: 82 | spot_positions.append([coin, usd_value, coins]) 83 | 84 | if spot_positions: 85 | print("\n") 86 | print("Current spot positions") 87 | positions_df = pd.DataFrame(spot_positions, columns=["coin", "usdValue", "coinAmount"]) 88 | positions_df["coinAmount"] = positions_df["coinAmount"].astype(str) 89 | print(positions_df.to_markdown(floatfmt='')) 90 | print("\n") 91 | else: 92 | print("No spot positions") 93 | 94 | 95 | def get_open_orders(client, spot:bool, display:bool): 96 | """ 97 | returns all sitting orders and their avg price 98 | 99 | :param client: 100 | :param spot: 101 | :return: 102 | """ 103 | 104 | if spot: 105 | category = "spot" 106 | else: 107 | category = "linear" 108 | 109 | if category == "linear": 110 | settleCoin = "USDT" 111 | 112 | next_page_cursor = "" 113 | order_data_list = [] 114 | while True: 115 | if category == "spot": 116 | orders = client.get_open_orders(category=category, limit=50, cursor=next_page_cursor)["result"] 117 | elif category == "linear": 118 | orders = client.get_open_orders(category=category, settleCoin="USDT" ,limit=50, cursor=next_page_cursor)["result"] 119 | 120 | next_page_cursor = orders["nextPageCursor"] 121 | order_data = orders["list"] 122 | order_data_list.append(order_data) 123 | if not order_data: 124 | break 125 | 126 | orders_by_ticker = {} 127 | for order_list in order_data_list: 128 | for order in order_list: 129 | if order["symbol"] not in orders_by_ticker.keys(): 130 | orders_by_ticker[order["symbol"]] = {"Buy": [], "Sell": []} 131 | orders_by_ticker[order["symbol"]] = {"Buy": [], "Sell": []} 132 | 133 | if order["orderType"] == "Limit": 134 | orders_by_ticker[order["symbol"]][order["side"]].append(order) 135 | 136 | if orders_by_ticker: 137 | open = [] 138 | for key in orders_by_ticker.keys(): 139 | for side in orders_by_ticker[key].keys(): 140 | ticker_orders = orders_by_ticker[key][side] 141 | price_times_qty = 0 142 | qty_sum = 0 143 | coin_qty_sum = 0 144 | if ticker_orders: 145 | for order in ticker_orders: 146 | usd_val_open = round(float(order["leavesValue"]), 1) 147 | price = float(order["price"]) 148 | coin_qty_open = float(order["leavesQty"]) 149 | 150 | price_times_qty += usd_val_open * price 151 | qty_sum += usd_val_open 152 | coin_qty_sum += coin_qty_open 153 | 154 | weighted_avg_price = price_times_qty / qty_sum 155 | # print(f"{key} {side} side filled: {qty_sum} USDT at: {weighted_avg_price}") 156 | open.append([key, side, weighted_avg_price, coin_qty_sum, weighted_avg_price * coin_qty_sum]) 157 | else: 158 | # print(f"{key} no {side} side orders filled") 159 | pass 160 | 161 | filled_df = pd.DataFrame(open, columns=["ticker", "side", "avg_price", "unfilled qty[coins]", "unfilled usdt value"]) 162 | filled_df.set_index("ticker", inplace=True) 163 | 164 | if display: 165 | print(f"Open limit orders || category: {category}") 166 | print(filled_df.to_markdown()) 167 | 168 | return orders_by_ticker 169 | 170 | else: 171 | print(f"no Limit orders for {category} category") 172 | 173 | 174 | def get_filled_orders_by_hours(client, hours_back:int, spot:bool): 175 | """ 176 | returns filled orders with respective avg filled price 177 | 178 | :param hours_back: 179 | :param spot: True: return spot filled orders, False: returns derivs filled orders 180 | :return: 181 | """ 182 | 183 | 184 | end = dt.datetime.now() 185 | start = end - dt.timedelta(hours=hours_back) 186 | 187 | end_ts = int(end.timestamp()*1000) 188 | start_ts = int(start.timestamp()*1000) 189 | 190 | if spot: 191 | category = "spot" 192 | else: 193 | category = "linear" 194 | 195 | next_page_cursor = "" 196 | 197 | order_data_list = [] 198 | while True: 199 | orders = client.get_order_history(category=category,startTime=start_ts, endTime=end_ts, limit=50, cursor=next_page_cursor)["result"] 200 | 201 | next_page_cursor = orders["nextPageCursor"] 202 | order_data = orders["list"] 203 | order_data_list.append(order_data) 204 | if not order_data: 205 | break 206 | 207 | orders_by_ticker = {} 208 | for order_list in order_data_list: 209 | for order in order_list: 210 | if order["symbol"] not in orders_by_ticker.keys(): 211 | orders_by_ticker[order["symbol"]] = {"Buy": [], "Sell": []} 212 | orders_by_ticker[order["symbol"]] = {"Buy": [], "Sell": []} 213 | 214 | orders_by_ticker[order["symbol"]][order["side"]].append(order) 215 | 216 | if orders_by_ticker: 217 | filled = [] 218 | for key in orders_by_ticker.keys(): 219 | for side in orders_by_ticker[key].keys(): 220 | ticker_orders = orders_by_ticker[key][side] 221 | price_times_qty = 0 222 | qty_sum = 0 223 | if ticker_orders: 224 | for order in ticker_orders: 225 | 226 | usd_val_filled = round(float(order["cumExecValue"]),1) 227 | if usd_val_filled > 1: 228 | filled_avg_price = float(order["avgPrice"]) 229 | 230 | price_times_qty += usd_val_filled * filled_avg_price 231 | qty_sum += usd_val_filled 232 | 233 | if qty_sum > 0: 234 | weighted_avg_price = price_times_qty / qty_sum 235 | # print(f"{key} {side} side filled: {qty_sum} USDT at: {weighted_avg_price}") 236 | filled.append([key, side, weighted_avg_price, qty_sum]) 237 | else: 238 | # print(f"{key} no {side} side orders filled") 239 | pass 240 | 241 | 242 | filled_df = pd.DataFrame(filled, columns=["ticker", "side", "avg_filled_prc", "filled_usdt_qty"]) 243 | filled_df.sort_values(by="ticker", inplace=True) 244 | filled_df.set_index("ticker", inplace=True) 245 | print(f"Filled qty's in last {hours_back} hours || category: {category}") 246 | print(filled_df.to_markdown()) 247 | 248 | else: 249 | print(f"no executed order for {category} category") 250 | 251 | 252 | def view_filled_orders(client): 253 | lookback_window = cli_inputs.select_lookback_window() 254 | 255 | category = input("Select spot/futures [1-spot, 2-futures] >>> ") 256 | category = int(category) 257 | if category == 1: 258 | spot = True 259 | elif category == 2: 260 | spot = False 261 | 262 | print("\n") 263 | get_filled_orders_by_hours(client=client, hours_back=lookback_window, spot=spot) 264 | 265 | 266 | def view_open_orders(client): 267 | category = input("Select spot/futures [1-spot, 2-futures] >>> ") 268 | category = int(category) 269 | if category == 1: 270 | spot = True 271 | elif category == 2: 272 | spot = False 273 | print("\n") 274 | get_open_orders(client, spot=spot, display=True) 275 | 276 | 277 | def delete_orders(client, category, ticker, cancel_ids): 278 | for id_ in cancel_ids: 279 | client.cancel_order(category=category, symbol=ticker, orderId=id_) 280 | time.sleep(0.01) 281 | 282 | 283 | def cancel_orders(client, spot:bool): 284 | 285 | if spot: 286 | tickers = get_spot_usdt_tickers(client) 287 | category = "spot" 288 | else: 289 | tickers = get_usdt_futures_tickers(client) 290 | category = "linear" 291 | 292 | ticker = cli_inputs.select_ticker(tickers, spot=spot) 293 | side = cli_inputs.select_side() 294 | if side == "s": 295 | side = "Sell" 296 | elif side == "b": 297 | side = "Buy" 298 | 299 | open_orders = get_open_orders(client, spot=spot, display=False) 300 | open_orders_for_ticker = open_orders[ticker][side] 301 | 302 | if open_orders_for_ticker: 303 | cancel_ids = [] 304 | for order in open_orders_for_ticker: 305 | cancel_ids.append(order["orderId"]) 306 | 307 | cancel_thread = Thread(target=delete_orders, args=(client, category, ticker, cancel_ids), name=f"Cancel_{category}_{ticker}_{side}_orders").start() 308 | 309 | else: 310 | print(f"No open orders for {ticker} {side} side") 311 | 312 | 313 | def cancel_orders_between_prices(client, spot:bool): 314 | 315 | if spot: 316 | tickers = get_spot_usdt_tickers(client) 317 | category = "spot" 318 | else: 319 | tickers = get_usdt_futures_tickers(client) 320 | category = "linear" 321 | 322 | ticker = cli_inputs.select_ticker(tickers) 323 | side = cli_inputs.select_side() 324 | if side == "s": 325 | side = "Sell" 326 | elif side == "b": 327 | side = "Buy" 328 | 329 | upper_price = cli_inputs.select_upper_limit_price() 330 | lower_price = cli_inputs.select_lower_limit_price() 331 | 332 | if upper_price > lower_price: 333 | 334 | open_orders = get_open_orders(client, spot=spot, display=False) 335 | open_orders_for_ticker = open_orders[ticker][side] 336 | 337 | if open_orders_for_ticker: 338 | cancel_ids = [] 339 | for order in open_orders_for_ticker: 340 | order_price = float(order["price"]) 341 | 342 | if lower_price <= order_price <= upper_price: 343 | cancel_ids.append(order["orderId"]) 344 | 345 | cancel_thread = Thread(target=delete_orders, args=(client, category, ticker, cancel_ids), name=f"Cancel_{category}_{ticker}_{side}_orders").start() 346 | 347 | else: 348 | print(f"No open orders for {ticker} {side} side") 349 | else: 350 | print(f"Upper price must be higher than lower price") 351 | 352 | 353 | def orderOverview_bybit_IC_personal(account): 354 | api_key, api_secret = get_credentials(account=account) 355 | client = auth(api_key, api_secret) 356 | 357 | exit = False 358 | while not exit: 359 | print("\n") 360 | print("What do you want to do:" 361 | "\n 1 >> display spot positions" 362 | "\n 2 >> view filled orders" 363 | "\n 3 >> view open limit orders" 364 | "\n 4 >> cancel orders" 365 | "\n 0 >> exit ") 366 | mode = int(input("input number >>> ")) 367 | if mode == 0: 368 | exit = True 369 | print(f"Bybit Futures >> IC_personal account - closing") 370 | elif mode == 1: 371 | print("\n") 372 | get_all_spot_positions(client) 373 | elif mode == 2: 374 | print("\n") 375 | view_filled_orders(client) 376 | elif mode == 3: 377 | print("\n") 378 | view_open_orders(client) 379 | elif mode == 4: 380 | print("\n") 381 | print("cancel options:" 382 | "\n 1 >> cancel all orders for specific side" 383 | "\n 2 >> cancel orders between 2 prices for specific side") 384 | price_mode = int(input("Input number >>> ")) 385 | 386 | if price_mode == 1: 387 | print("\n") 388 | cancel_mode = int(input("Select market you want to close orders on [1-spot, 2-futures] >>> ")) 389 | if cancel_mode in [1,2]: 390 | if cancel_mode == 1: 391 | spot = True 392 | elif cancel_mode == 2: 393 | spot = False 394 | cancel_orders(client, spot=spot) 395 | else: 396 | print("input must be 1 or 2") 397 | elif price_mode == 2: 398 | print("\n") 399 | cancel_mode = int(input("Select market you want to close orders on [1-spot, 2-futures] >>> ")) 400 | if cancel_mode in [1,2]: 401 | if cancel_mode == 1: 402 | spot = True 403 | elif cancel_mode == 2: 404 | spot = False 405 | cancel_orders_between_prices(client, spot=spot) 406 | else: 407 | print("input must be 1 or 2") 408 | else: 409 | print("Input must be 1 or 2") 410 | 411 | 412 | def Order_overview(): 413 | exit = False 414 | while not exit: 415 | print("\n") 416 | print("Select account:" 417 | "\n 1 >> Bybit - IC_personal" 418 | "\n 2 >> Bybit - IC_pairs" 419 | "\n 0 >> exit terminal") 420 | 421 | mode = int(input("input number >>> ")) 422 | if mode == 0: 423 | exit = True 424 | print("\n") 425 | print("Terminal closing") 426 | elif mode == 1: 427 | print("\n") 428 | orderOverview_bybit_IC_personal(account="IC_personal") 429 | elif mode == 2: 430 | print("\n") 431 | orderOverview_bybit_IC_personal(account="IC_pairs") 432 | 433 | 434 | # if __name__ == "__main__": 435 | # main() 436 | 437 | 438 | # api_key, api_secret = get_credentials(account="IC_personal") 439 | # client = auth(api_key, api_secret) 440 | # 441 | # cancel_orders_between_prices(client, spot=False) 442 | --------------------------------------------------------------------------------