├── Derivatives.py └── class ├── helper.py ├── keys.py └── main.py /Derivatives.py: -------------------------------------------------------------------------------- 1 | from keys import api, secret 2 | from pybit.unified_trading import HTTP 3 | import pandas as pd 4 | import ta 5 | from time import sleep 6 | 7 | 8 | session = HTTP( 9 | api_key=api, 10 | api_secret=secret 11 | ) 12 | 13 | # Config: 14 | tp = 0.012 # Take Profit +1.2% 15 | sl = 0.009 # Stop Loss -0.9% 16 | timeframe = 15 # 15 minutes 17 | mode = 1 # 1 - Isolated, 0 - Cross 18 | leverage = 10 19 | qty = 50 # Amount of USDT for one order 20 | 21 | 22 | # Getting balance on Bybit Derivatrives Asset (in USDT) 23 | def get_balance(): 24 | try: 25 | resp = session.get_wallet_balance(accountType="CONTRACT", coin="USDT")['result']['list'][0]['coin'][0]['walletBalance'] 26 | resp = float(resp) 27 | return resp 28 | except Exception as err: 29 | print(err) 30 | 31 | print(f'Your balance: {get_balance()} USDT') 32 | 33 | 34 | # Getting all available symbols from Derivatives market (like 'BTCUSDT', 'XRPUSDT', etc) 35 | def get_tickers(): 36 | try: 37 | resp = session.get_tickers(category="linear")['result']['list'] 38 | symbols = [] 39 | for elem in resp: 40 | if 'USDT' in elem['symbol'] and not 'USDC' in elem['symbol']: 41 | symbols.append(elem['symbol']) 42 | return symbols 43 | except Exception as err: 44 | print(err) 45 | 46 | 47 | # Klines is the candles of some symbol (up to 1500 candles). Dataframe, last elem has [-1] index 48 | def klines(symbol): 49 | try: 50 | resp = session.get_kline( 51 | category='linear', 52 | symbol=symbol, 53 | interval=timeframe, 54 | limit=500 55 | )['result']['list'] 56 | resp = pd.DataFrame(resp) 57 | resp.columns = ['Time', 'Open', 'High', 'Low', 'Close', 'Volume', 'Turnover'] 58 | resp = resp.set_index('Time') 59 | resp = resp.astype(float) 60 | resp = resp[::-1] 61 | return resp 62 | except Exception as err: 63 | print(err) 64 | 65 | 66 | # Getting your current positions. It returns symbols list with opened positions 67 | def get_positions(): 68 | try: 69 | resp = session.get_positions( 70 | category='linear', 71 | settleCoin='USDT' 72 | )['result']['list'] 73 | pos = [] 74 | for elem in resp: 75 | pos.append(elem['symbol']) 76 | return pos 77 | except Exception as err: 78 | print(err) 79 | 80 | 81 | # Getting last 50 PnL. I used it to check strategies performance 82 | def get_pnl(): 83 | try: 84 | resp = session.get_closed_pnl(category="linear", limit=50)['result']['list'] 85 | pnl = 0 86 | for elem in resp: 87 | pnl += float(elem['closedPnl']) 88 | return pnl 89 | except Exception as err: 90 | print(err) 91 | 92 | 93 | # Changing mode and leverage: 94 | def set_mode(symbol): 95 | try: 96 | resp = session.switch_margin_mode( 97 | category='linear', 98 | symbol=symbol, 99 | tradeMode=mode, 100 | buyLeverage=leverage, 101 | sellLeverage=leverage 102 | ) 103 | print(resp) 104 | except Exception as err: 105 | print(err) 106 | 107 | 108 | # Getting number of decimal digits for price and qty 109 | def get_precisions(symbol): 110 | try: 111 | resp = session.get_instruments_info( 112 | category='linear', 113 | symbol=symbol 114 | )['result']['list'][0] 115 | price = resp['priceFilter']['tickSize'] 116 | if '.' in price: 117 | price = len(price.split('.')[1]) 118 | else: 119 | price = 0 120 | qty = resp['lotSizeFilter']['qtyStep'] 121 | if '.' in qty: 122 | qty = len(qty.split('.')[1]) 123 | else: 124 | qty = 0 125 | 126 | return price, qty 127 | except Exception as err: 128 | print(err) 129 | 130 | 131 | # Placing order with Market price. Placing TP and SL as well 132 | def place_order_market(symbol, side): 133 | price_precision = get_precisions(symbol)[0] 134 | qty_precision = get_precisions(symbol)[1] 135 | mark_price = session.get_tickers( 136 | category='linear', 137 | symbol=symbol 138 | )['result']['list'][0]['markPrice'] 139 | mark_price = float(mark_price) 140 | print(f'Placing {side} order for {symbol}. Mark price: {mark_price}') 141 | order_qty = round(qty/mark_price, qty_precision) 142 | sleep(2) 143 | if side == 'buy': 144 | try: 145 | tp_price = round(mark_price + mark_price * tp, price_precision) 146 | sl_price = round(mark_price - mark_price * sl, price_precision) 147 | resp = session.place_order( 148 | category='linear', 149 | symbol=symbol, 150 | side='Buy', 151 | orderType='Market', 152 | qty=order_qty, 153 | takeProfit=tp_price, 154 | stopLoss=sl_price, 155 | tpTriggerBy='Market', 156 | slTriggerBy='Market' 157 | ) 158 | print(resp) 159 | except Exception as err: 160 | print(err) 161 | 162 | if side == 'sell': 163 | try: 164 | tp_price = round(mark_price - mark_price * tp, price_precision) 165 | sl_price = round(mark_price + mark_price * sl, price_precision) 166 | resp = session.place_order( 167 | category='linear', 168 | symbol=symbol, 169 | side='Sell', 170 | orderType='Market', 171 | qty=order_qty, 172 | takeProfit=tp_price, 173 | stopLoss=sl_price, 174 | tpTriggerBy='Market', 175 | slTriggerBy='Market' 176 | ) 177 | print(resp) 178 | except Exception as err: 179 | print(err) 180 | 181 | 182 | # Some RSI strategy. Make your own using this example 183 | def rsi_signal(symbol): 184 | kl = klines(symbol) 185 | ema = ta.trend.ema_indicator(kl.Close, window=200) 186 | rsi = ta.momentum.RSIIndicator(kl.Close).rsi() 187 | if rsi.iloc[-3] < 30 and rsi.iloc[-2] < 30 and rsi.iloc[-1] > 30: 188 | return 'up' 189 | if rsi.iloc[-3] > 70 and rsi.iloc[-2] > 70 and rsi.iloc[-1] < 70: 190 | return 'down' 191 | else: 192 | return 'none' 193 | 194 | # William %R signal 195 | def williamsR(symbol): 196 | kl = klines(symbol) 197 | w = ta.momentum.WilliamsRIndicator(kl.High, kl.Low, kl.Close, lbp=24).williams_r() 198 | ema_w = ta.trend.ema_indicator(w, window=24) 199 | if w.iloc[-1] < -99.5: 200 | return 'up' 201 | elif w.iloc[-1] > -0.5: 202 | return 'down' 203 | elif w.iloc[-1] < -75 and w.iloc[-2] < -75 and w.iloc[-2] < ema_w.iloc[-2] and w.iloc[-1] > ema_w.iloc[-1]: 204 | return 'up' 205 | elif w.iloc[-1] > -25 and w.iloc[-2] > -25 and w.iloc[-2] > ema_w.iloc[-2] and w.iloc[-1] < ema_w.iloc[-1]: 206 | return 'down' 207 | else: 208 | return 'none' 209 | 210 | 211 | 212 | max_pos = 50 # Max current orders 213 | symbols = get_tickers() # getting all symbols from the Bybit Derivatives 214 | 215 | # Infinite loop 216 | while True: 217 | balance = get_balance() 218 | if balance == None: 219 | print('Cant connect to API') 220 | if balance != None: 221 | balance = float(balance) 222 | print(f'Balance: {balance}') 223 | pos = get_positions() 224 | print(f'You have {len(pos)} positions: {pos}') 225 | 226 | if len(pos) < max_pos: 227 | # Checking every symbol from the symbols list: 228 | for elem in symbols: 229 | pos = get_positions() 230 | if len(pos) >= max_pos: 231 | break 232 | # Signal to buy or sell 233 | signal = rsi_signal(elem) 234 | if signal == 'up': 235 | print(f'Found BUY signal for {elem}') 236 | set_mode(elem) 237 | sleep(2) 238 | place_order_market(elem, 'buy') 239 | sleep(5) 240 | if signal == 'down': 241 | print(f'Found SELL signal for {elem}') 242 | set_mode(elem) 243 | sleep(2) 244 | place_order_market(elem, 'sell') 245 | sleep(5) 246 | print('Waiting 2 mins') 247 | sleep(120) 248 | 249 | -------------------------------------------------------------------------------- /class/helper.py: -------------------------------------------------------------------------------- 1 | from pybit.unified_trading import HTTP 2 | import pandas as pd 3 | import ta 4 | from time import sleep 5 | import random 6 | import requests 7 | 8 | class Bybit: 9 | def __init__(self, api, secret, accounttype): 10 | self.api = api 11 | self.secret = secret 12 | self.accountType = accounttype 13 | self.session = HTTP(api_key=self.api, api_secret=self.secret, testnet=True) 14 | 15 | def get_balance(self): 16 | try: 17 | resp = self.session.get_wallet_balance(accountType=self.accountType, coin="USDT", recv_window=40000)['result']['list'][0]['coin'][0]['walletBalance'] 18 | resp = round(float(resp), 3) 19 | return resp 20 | except Exception as err: 21 | print(err) 22 | 23 | def get_positions(self): 24 | try: 25 | resp = self.session.get_positions( 26 | category='linear', 27 | settleCoin='USDT', 28 | recv_window = 40000 29 | )['result']['list'] 30 | pos = [] 31 | for elem in resp: 32 | pos.append(elem['symbol']) 33 | return pos 34 | except Exception as err: 35 | print(err) 36 | 37 | def get_last_pnl(self, limit=50): 38 | try: 39 | resp = self.session.get_closed_pnl(category="linear", limit=limit, recv_window=40000)['result']['list'] 40 | pnl = 0 41 | for elem in resp: 42 | pnl += float(elem['closedPnl']) 43 | return round(pnl, 4) 44 | except Exception as err: 45 | print(err) 46 | 47 | def get_current_pnl(self): 48 | try: 49 | resp = self.session.get_positions( 50 | category="linear", 51 | settleCoin="USDT", 52 | recv_window=10000 53 | )['result']['list'] 54 | pnl = 0 55 | for elem in resp: 56 | pnl += float(elem['unrealisedPnl']) 57 | return round(pnl, 4) 58 | except Exception as err: 59 | print(err) 60 | 61 | def get_tickers(self): 62 | try: 63 | resp = self.session.get_tickers(category="linear", recv_window=10000)['result']['list'] 64 | symbols = [] 65 | for elem in resp: 66 | if 'USDT' in elem['symbol'] and not 'USDC' in elem['symbol']: 67 | symbols.append(elem['symbol']) 68 | return symbols 69 | except Exception as err: 70 | print(err) 71 | 72 | def klines(self, symbol, timeframe, limit=500): 73 | try: 74 | resp = self.session.get_kline( 75 | category='linear', 76 | symbol=symbol, 77 | interval=timeframe, 78 | limit=limit, 79 | recv_window=7000 80 | )['result']['list'] 81 | resp = pd.DataFrame(resp) 82 | resp.columns = ['Time', 'Open', 'High', 'Low', 'Close', 'Volume', 'Turnover'] 83 | resp = resp.set_index('Time') 84 | resp = resp.astype(float) 85 | resp = resp[::-1] 86 | return resp 87 | except Exception as err: 88 | print(err) 89 | 90 | def get_precisions(self, symbol): 91 | try: 92 | resp = self.session.get_instruments_info( 93 | category='linear', 94 | symbol=symbol, 95 | recv_window=10000 96 | )['result']['list'][0] 97 | price = resp['priceFilter']['tickSize'] 98 | if '.' in price: 99 | price = len(price.split('.')[1]) 100 | else: 101 | price = 0 102 | qty = resp['lotSizeFilter']['qtyStep'] 103 | if '.' in qty: 104 | qty = len(qty.split('.')[1]) 105 | else: 106 | qty = 0 107 | return price, qty 108 | except Exception as err: 109 | print(err) 110 | 111 | def get_max_leverage(self, symbol): 112 | try: 113 | resp = self.session.get_instruments_info( 114 | category="linear", 115 | symbol=symbol, 116 | recv_window=10000 117 | )['result']['list'][0]['leverageFilter']['maxLeverage'] 118 | return float(resp) 119 | except Exception as err: 120 | print(err) 121 | 122 | def set_mode(self, symbol, mode=1, leverage=10): 123 | try: 124 | resp = self.session.switch_margin_mode( 125 | category='linear', 126 | symbol=symbol, 127 | tradeMode=str(mode), 128 | buyLeverage=str(leverage), 129 | sellLeverage=str(leverage), 130 | recv_window=10000 131 | ) 132 | if resp['retMsg'] == 'OK': 133 | if mode == 1: 134 | print(f'[{symbol}] Changed margin mode to ISOLATED') 135 | if mode == 0: 136 | print(f'[{symbol}] Changed margin mode to CROSS') 137 | except Exception as err: 138 | if '110026' in str(err): 139 | print(f'[{symbol}] Margin mode is Not changed') 140 | else: 141 | print(err) 142 | 143 | def set_leverage(self, symbol, leverage=10): 144 | try: 145 | resp = self.session.set_leverage( 146 | category="linear", 147 | symbol=symbol, 148 | buyLeverage=str(leverage), 149 | sellLeverage=str(leverage), 150 | recv_window=10000 151 | ) 152 | if resp['retMsg'] == 'OK': 153 | print(f'[{symbol}] Changed leverage to {leverage}') 154 | except Exception as err: 155 | if '110043' in str(err): 156 | print(f'[{symbol}] Leverage is Not changed') 157 | else: 158 | print(err) 159 | 160 | def place_order_market(self, symbol, side, mode, leverage, qty=10, tp=0.012, sl=0.009): 161 | self.set_mode(symbol, mode, leverage) 162 | sleep(0.5) 163 | self.set_leverage(symbol, leverage) 164 | sleep(0.5) 165 | price_precision = self.get_precisions(symbol)[0] 166 | qty_precision = self.get_precisions(symbol)[1] 167 | mark_price = self.session.get_tickers( 168 | category='linear', 169 | symbol=symbol, recv_window=10000 170 | )['result']['list'][0]['markPrice'] 171 | mark_price = float(mark_price) 172 | print(f'Placing {side} order for {symbol}. Mark price: {mark_price}') 173 | order_qty = round(qty / mark_price, qty_precision) 174 | sleep(2) 175 | if side == 'buy': 176 | try: 177 | tp_price = round(mark_price + mark_price * tp, price_precision) 178 | sl_price = round(mark_price - mark_price * sl, price_precision) 179 | resp = self.session.place_order( 180 | category='linear', 181 | symbol=symbol, 182 | side='Buy', 183 | orderType='Market', 184 | qty=order_qty, 185 | takeProfit=tp_price, 186 | stopLoss=sl_price, 187 | tpTriggerBy='Market', 188 | slTriggerBy='Market', recv_window=10000 189 | ) 190 | print(resp['retMsg']) 191 | except Exception as err: 192 | print(err) 193 | 194 | if side == 'sell': 195 | try: 196 | tp_price = round(mark_price - mark_price * tp, price_precision) 197 | sl_price = round(mark_price + mark_price * sl, price_precision) 198 | resp = self.session.place_order( 199 | category='linear', 200 | symbol=symbol, 201 | side='Sell', 202 | orderType='Market', 203 | qty=order_qty, 204 | takeProfit=tp_price, 205 | stopLoss=sl_price, 206 | tpTriggerBy='Market', 207 | slTriggerBy='Market', recv_window=10000 208 | ) 209 | print(resp['retMsg']) 210 | except Exception as err: 211 | print(err) 212 | 213 | def place_order_limit(self, symbol, side, mode, leverage, qty=10, tp=0.012, sl=0.009): 214 | self.set_mode(symbol, mode, leverage) 215 | sleep(0.5) 216 | self.set_leverage(symbol, leverage) 217 | sleep(0.5) 218 | price_precision = self.get_precisions(symbol)[0] 219 | qty_precision = self.get_precisions(symbol)[1] 220 | limit_price = self.session.get_tickers( 221 | category='linear', 222 | symbol=symbol 223 | )['result']['list'][0]['lastPrice'] 224 | limit_price = float(limit_price) 225 | print(f'Placing {side} order for {symbol}. Limit price: {limit_price}') 226 | order_qty = round(qty / limit_price, qty_precision) 227 | sleep(2) 228 | if side == 'buy': 229 | try: 230 | tp_price = round(limit_price + limit_price * tp, price_precision) 231 | sl_price = round(limit_price - limit_price * sl, price_precision) 232 | resp = self.session.place_order( 233 | category='linear', 234 | symbol=symbol, 235 | side='Buy', 236 | orderType='Limit', 237 | price= limit_price, 238 | qty=order_qty, 239 | takeProfit=tp_price, 240 | stopLoss=sl_price, 241 | tpTriggerBy='LastPrice', 242 | slTriggerBy='LastPrice' 243 | ) 244 | print(resp['retMsg']) 245 | except Exception as err: 246 | print(err) 247 | 248 | if side == 'sell': 249 | try: 250 | tp_price = round(limit_price - limit_price * tp, price_precision) 251 | sl_price = round(limit_price + limit_price * sl, price_precision) 252 | resp = self.session.place_order( 253 | category='linear', 254 | symbol=symbol, 255 | side='Sell', 256 | orderType='Limit', 257 | price=limit_price, 258 | qty=order_qty, 259 | takeProfit=tp_price, 260 | stopLoss=sl_price, 261 | tpTriggerBy='LastPrice', 262 | slTriggerBy='LastPrice' 263 | ) 264 | print(resp['retMsg']) 265 | except Exception as err: 266 | print(err) 267 | 268 | def send_tg(self, key, tg_id, text): 269 | try: 270 | url = f'https://api.telegram.org/bot{key}/sendMessage' 271 | data = { 272 | 'chat_id': tg_id, 273 | 'text': text 274 | } 275 | resp = requests.post(url, data=data) 276 | print(resp) 277 | except Exception as err: 278 | print(err) 279 | -------------------------------------------------------------------------------- /class/keys.py: -------------------------------------------------------------------------------- 1 | api = "" 2 | secret = "" 3 | accountType = "UNIFIED" 4 | # type is "CONTRACT" or "UNIFIED" -------------------------------------------------------------------------------- /class/main.py: -------------------------------------------------------------------------------- 1 | import random 2 | from keys import api, secret, accountType 3 | from helper import Bybit 4 | from time import sleep 5 | import ta 6 | from threading import Thread 7 | 8 | session = Bybit(api, secret, accountType) 9 | 10 | tp = 0.02 11 | sl = 0.015 12 | mode = 1 13 | leverage = 10 14 | timeframe = 5 15 | qty = 10 16 | max_positions = 200 17 | 18 | 19 | def rsi_signal(symbol): 20 | kl = session.klines(symbol, timeframe) 21 | rsi = ta.momentum.RSIIndicator(kl.Close).rsi() 22 | if rsi.iloc[-2] < 25: 23 | return 'buy' 24 | if rsi.iloc[-2] > 75: 25 | return 'sell' 26 | 27 | qty = 10 28 | symbols = session.get_tickers() 29 | while True: 30 | try: 31 | balance = session.get_balance() 32 | # qty = balance * 0.3 33 | print(f'Balance: {round(balance, 3)} USDT') 34 | positions = session.get_positions() 35 | print(f'{len(positions)} Positions: {positions}') 36 | 37 | for symbol in symbols: 38 | positions = session.get_positions() 39 | if len(positions) >= max_positions: 40 | break 41 | sign = rsi_signal(symbol) 42 | if sign is not None and not symbol in positions: 43 | print(symbol, sign) 44 | session.place_order_market(symbol, sign, mode, leverage, qty, tp, sl) 45 | sleep(1) 46 | 47 | wait = 100 48 | print(f'Waiting {wait} sec') 49 | sleep(wait) 50 | except Exception as err: 51 | print(err) 52 | sleep(30) 53 | 54 | 55 | --------------------------------------------------------------------------------