Are you looking to take your cryptocurrency trading to the next level? Look no further than Bybit, the leading crypto derivatives exchange. With advanced trading tools, low fees, and a user-friendly platform, Bybit makes it easy to trade Bitcoin, Ethereum, and other popular cryptocurrencies. And if you sign up using our affiliate link and use the referral code CODEARMO, you'll receive exclusive benefits and bonuses up to $30,000 to help you get started. Don't miss out on this opportunity to join one of the fastest-growing communities in crypto trading. Sign up for Bybit today and start trading like a pro!
If you haven't already installed Pybit please see the article on setting up an API key and installing Pybit. Once we have imported Pybit as shown below:
from pybit.unified_trading import HTTP
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
import time
import json
with open('authcreds.json') as j:
creds = json.load(j)
key = creds['KEY_NAME']['key']
secret = creds['KEY_NAME']['secret']
session = HTTP(api_key=key, api_secret=secret, testnet=False)
In order to collect historical data from Bybit there are a number of parameters we must decide on prior to calling the API. For the purposes of this article we will be collecting USDT future perpetual contracts. Therefore the category we will use is 'linear' as shown below.
Parameter | Required | Type | Comments |
---|---|---|---|
category | true | string | Product type. spot,linear,inverse,option |
symbol | false | string | Symbol name |
baseCoin | false | string | Base coin. For option only |
expDate | false | string | Expiry date. e.g., 25DEC22. For option only |
Get List of Available USDT Perpetuals Bybit
A cryptocurrency ticker is a symbol or abbreviation that represents a particular cryptocurrency, similar to how stock symbols represent publicly traded companies.
Cryptocurrency tickers are typically a combination of letters and numbers that are used to uniquely identify a particular cryptocurrency. For example, Bitcoin's ticker is "BTC", Ethereum's ticker is "ETH", and so on.
Cryptocurrency tickers are used to track the performance of a particular cryptocurrency and to provide easy reference when discussing or trading that cryptocurrency. When you look up a cryptocurrency on a trading platform or a price tracker, you'll typically see its ticker symbol displayed alongside its current price and other information.
result = session.get_tickers(
category="linear").get('result')['list']
tickers = [asset['symbol'] for asset in result if asset['symbol'].endswith('USDT')]
print(tickers)
This will print out a total list of which USDT perps Bybit currently offer. Users can then select an asset to download historical data in the next section.
['10000NFTUSDT', '1000BONKUSDT', '1000BTTUSDT', '1000FLOKIUSDT', '1000LUNCUSDT', '1000XECUSDT', '1INCHUSDT', 'AAVEUSDT', 'ACHUSDT', 'ADAUSDT', 'AGIXUSDT', 'AGLDUSDT', 'AKROUSDT', 'ALGOUSDT', 'ALICEUSDT', 'ALPHAUSDT', 'ANKRUSDT', 'ANTUSDT', 'APEUSDT', 'API3USDT', 'APTUSDT', 'ARBUSDT', 'ARPAUSDT', 'ARUSDT', 'ASTRUSDT', 'ATOMUSDT', 'AUDIOUSDT', 'AVAXUSDT', 'AXSUSDT', 'BAKEUSDT', 'BALUSDT', 'BANDUSDT', 'BATUSDT', 'BCHUSDT', 'BELUSDT', 'BICOUSDT', 'BITUSDT', 'BLURUSDT', 'BLZUSDT', 'BNBUSDT', 'BNXUSDT', 'BOBAUSDT', 'BSVUSDT', 'BSWUSDT', 'BTCUSDT', 'BUSDUSDT', 'C98USDT', 'CEEKUSDT', 'CELOUSDT', 'CELRUSDT', 'CFXUSDT', 'CHRUSDT', 'CHZUSDT', 'CKBUSDT', 'COCOSUSDT', 'COMPUSDT', 'COREUSDT', 'COTIUSDT', 'CREAMUSDT', 'CROUSDT', 'CRVUSDT', 'CTCUSDT', 'CTKUSDT', 'CTSIUSDT', 'CVCUSDT', 'CVXUSDT', 'DARUSDT', 'DASHUSDT', 'DENTUSDT', 'DGBUSDT', 'DODOUSDT', 'DOGEUSDT', 'DOTUSDT', 'DUSKUSDT', 'DYDXUSDT', 'EGLDUSDT', 'ENJUSDT', 'ENSUSDT', 'EOSUSDT', 'ETCUSDT', 'ETHUSDT', 'ETHWUSDT', 'FETUSDT', 'FILUSDT', 'FITFIUSDT', 'FLMUSDT', 'FLOWUSDT', 'FLRUSDT', 'FTMUSDT', 'FXSUSDT', 'GALAUSDT', 'GALUSDT', 'GFTUSDT', 'GLMRUSDT', 'GMTUSDT', 'GMXUSDT', 'GPTUSDT', 'GRTUSDT', 'GTCUSDT', 'HBARUSDT', 'HFTUSDT', 'HIGHUSDT', 'HNTUSDT', 'HOOKUSDT', 'HOTUSDT', 'ICPUSDT', 'ICXUSDT', 'IDUSDT', 'ILVUSDT', 'IMXUSDT', 'INJUSDT', 'IOSTUSDT', 'IOTAUSDT', 'IOTXUSDT', 'JASMYUSDT', 'JOEUSDT', 'JSTUSDT', 'KAVAUSDT', 'KDAUSDT', 'KLAYUSDT', 'KNCUSDT', 'KSMUSDT', 'LDOUSDT', 'LINAUSDT', 'LINKUSDT', 'LITUSDT', 'LOOKSUSDT', 'LPTUSDT', 'LQTYUSDT', 'LRCUSDT', 'LTCUSDT', 'LUNA2USDT', 'MAGICUSDT', 'MANAUSDT', 'MASKUSDT', 'MATICUSDT', 'MINAUSDT', 'MKRUSDT', 'MTLUSDT', 'NEARUSDT', 'NEOUSDT', 'NKNUSDT', 'OCEANUSDT', 'OGNUSDT', 'OMGUSDT', 'ONEUSDT', 'ONTUSDT', 'OPUSDT', 'PAXGUSDT', 'PEOPLEUSDT', 'QTUMUSDT', 'RDNTUSDT', 'REEFUSDT', 'RENUSDT', 'REQUSDT', 'RLCUSDT', 'RNDRUSDT', 'ROSEUSDT', 'RPLUSDT', 'RSRUSDT', 'RSS3USDT', 'RUNEUSDT', 'RVNUSDT', 'SANDUSDT', 'SCRTUSDT', 'SCUSDT', 'SFPUSDT', 'SHIB1000USDT', 'SKLUSDT', 'SLPUSDT', 'SNXUSDT', 'SOLUSDT', 'SPELLUSDT', 'SSVUSDT', 'STGUSDT', 'STMXUSDT', 'STORJUSDT', 'STXUSDT', 'SUNUSDT', 'SUSHIUSDT', 'SWEATUSDT', 'SXPUSDT', 'THETAUSDT', 'TLMUSDT', 'TOMOUSDT', 'TRBUSDT', 'TRUUSDT', 'TRXUSDT', 'TUSDT', 'TWTUSDT', 'UNFIUSDT', 'UNIUSDT', 'USDCUSDT', 'VETUSDT', 'WAVESUSDT', 'WOOUSDT', 'XCNUSDT', 'XEMUSDT', 'XLMUSDT', 'XMRUSDT', 'XNOUSDT', 'XRPUSDT', 'XTZUSDT', 'YFIUSDT', 'YGGUSDT', 'ZECUSDT', 'ZENUSDT', 'ZILUSDT', 'ZRXUSDT']
Get Historical Daily Data
Once we have chosen a USDT perpetual we can proceed to collecting data. The table below shows the arguments we need to be aware of to retrieve historical data. Note that the interval parameter shown in the table below relates to the data frequency i.e. 1 = 1 minute.
Request Arguments
Parameter | Required | Type | Comments |
---|---|---|---|
category | true | string | Product type. spot, linear, inverse |
symbol | true | string | Symbol name |
interval | true | int/string | Kline interval. 1, 3, 5, 15, 30, 60, 120, 240, 360, 720, D, M, W |
start | false | integer | The start timestamp (ms) |
end | false | integer | The end timestamp (ms) |
The table below shows the response parameters , the function format_data above extracts the information in the list from the API and formats them in to a pandas dataframe.
Request Response
Parameter | Type | Comments |
---|---|---|
category | string | Product type |
symbol | string | Symbol name |
list | array | An string array of individual candle
|
The python script below calls the get_kline method from Pybit. Note that we do not pass the start/end timestamp argument, which we will come back to later in the article.
response = session.get_kline(category='linear',
symbol='ETHUSDT',
interval='D').get('result')
def format_data(response):
'''
Parameters
----------
respone : dict
response from calling get_klines() method from pybit.
Returns
-------
dataframe of ohlc data with date as index
'''
data = response.get('list', None)
if not data:
return
data = pd.DataFrame(data,
columns =[
'timestamp',
'open',
'high',
'low',
'close',
'volume',
'turnover'
],
)
f = lambda x: dt.datetime.utcfromtimestamp(int(x)/1000)
data.index = data.timestamp.apply(f)
return data[::-1].apply(pd.to_numeric)
df = format_data(response)
print(df)
'''
timestamp open ... volume turnover
timestamp ...
2022-10-12 1.665533e+12 1279.300049 ... 7.275909e+05 9.415818e+08
2022-10-13 1.665619e+12 1293.849976 ... 2.185120e+06 2.725300e+09
2022-10-14 1.665706e+12 1286.500000 ... 1.124476e+06 1.480705e+09
2022-10-15 1.665792e+12 1295.650024 ... 5.074429e+05 6.510826e+08
2022-10-16 1.665878e+12 1274.250000 ... 5.975026e+05 7.729099e+08
... ... ... ... ...
2023-04-25 1.682381e+12 1841.000000 ... 8.319169e+05 1.524671e+09
2023-04-26 1.682467e+12 1865.099976 ... 1.701774e+06 3.202957e+09
2023-04-27 1.682554e+12 1865.209961 ... 1.035564e+06 1.968957e+09
2023-04-28 1.682640e+12 1907.699951 ... 5.036653e+05 9.560499e+08
2023-04-29 1.682726e+12 1890.010010 ... 2.651855e+05 5.038554e+08
[200 rows x 7 columns]
'''
The problem with this approach is that we are constrained to only 200 rows of data. Therefore if we want data exceeding (in this case) 200 days we have to make multiple function calls. Let's say we wanted to get hourly data for DOGE since the start of 2023. We will have to make multiple API calls.
def get_last_timestamp(df):
return int(df.timestamp[-1:].values[0])
start = int(dt.datetime(2023, 1, 1).timestamp()* 1000)
interval = 60
symbol = 'DOGEUSDT'
df = pd.DataFrame()
while True:
response = session.get_kline(category='linear',
symbol=symbol,
start=start,
interval=interval).get('result')
latest = format_data(response)
if not isinstance(latest, pd.DataFrame):
break
start = get_last_timestamp(latest)
time.sleep(0.1)
df = pd.concat([df, latest])
print(f'Collecting data starting {dt.datetime.fromtimestamp(start/1000)}')
if len(latest) == 1: break
df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True)
Cool now we have hourly data!
Get Orderbook Data
A cryptocurrency order book is similar to the order book for any other asset, but it's specific to cryptocurrencies like Bitcoin or Ethereum.
In a cryptocurrency order book, you'll see the current bids and asks for a particular cryptocurrency, along with the amount of cryptocurrency being offered and the price being asked for it.
On the buy side, people place bids to purchase a certain amount of cryptocurrency at a specific price. On the sell side, people place asks to sell a certain amount of cryptocurrency at a specific price.
The order book will typically show the highest bids and lowest asks at the top, with lower bids and higher asks listed further down. This provides traders with an idea of the current market depth and the supply and demand of the cryptocurrency.
Traders use the information in the order book to make informed decisions about when to buy or sell cryptocurrency. For example, if there are a lot of buy orders at a certain price level, it may indicate that demand for the cryptocurrency is increasing and that the price is likely to rise. Conversely, if there are a lot of sell orders at a certain price level, it may indicate that there is a lot of supply and that the price is likely to fall.
response = session.get_orderbook(
category="linear",
symbol="DOGEUSDT",
limit=50).get('result')
def format_order_book(response):
'''
Parameters
----------
response : dict
Returns
-------
two list of lists containing bid/ask price with associated volume
'''
bids = response.get('b')
asks = response.get('a')
return bids, asks
bids, asks = format_order_book(response)
for bid in bids:
print(f'Bid price - {bid[0]} , quantity = {bid[1]}')
'''
Bid price - 0.081 , quantity = 1177521
Bid price - 0.08099 , quantity = 936765
Bid price - 0.08098 , quantity = 541063
Bid price - 0.08097 , quantity = 483457
Bid price - 0.08096 , quantity = 1211693
'''
Get Open Interest Data
Open interest is the total number of outstanding futures contracts that have not been settled or closed out by an offsetting trade. In other words, it represents the number of contracts that are currently open or active in the market.
When someone buys or sells a futures contract, the open interest increases by one. When someone closes out a position by selling or buying a contract to offset their original trade, the open interest decreases by one.
Open interest is an important indicator of market liquidity and sentiment, as it represents the number of market participants who are actively trading a particular futures contract. High open interest suggests that there is a lot of trading activity and interest in the contract, while low open interest may indicate that the market is less active or less popular.
The input arguments are similar to the get_klines method we used previously. However, the interval seems to be different for some reason. Also note the loop through the dictionaries, this is due to the fact that Pandas doesn't seem to like the 7 trailing zeros , and sometimes returns NaN and sometimes doesn't! So we use a suboptimal solution as shown below.
Parameter | Required | Type | Comments |
---|---|---|---|
category | true | string | Product type. linear,inverse |
symbol | true | string | Symbol name |
intervalTime | true | string | Interval. 5min,15min,30min,1h,4h,1d |
startTime | false | integer | The start timestamp (ms) |
endTime | false | integer | The end timestamp (ms) |
limit | false | integer | Limit for data size |
def format_oi(response):
'''
Parameters
----------
respone : dict
response from calling get_open_interest
Returns
-------
dataframe of open interest and timestamp
'''
data = response.get('list', None)
if not data:
return
ois =[]
tss = []
for row in data:
oi = float(row.get('openInterest'))
ts = int(row.get('timestamp'))
ois.append(oi)
tss.append(ts)
data = pd.DataFrame()
data['open_interest'] = ois
data['timestamp'] = tss
f = lambda x: dt.datetime.utcfromtimestamp(int(x)/1000)
data.index = data.timestamp.apply(f)
return data[::-1]
response = session.get_open_interest(
category="linear",
symbol="DOGEUSDT",
intervalTime="1h",
limit=200
).get('result')
oi = format_oi(response)
'''
openInterest timestamp
timestamp
2023-04-28 01:00:00 934277376.0 1.682644e+12
2023-04-28 02:00:00 935817856.0 1.682647e+12
2023-04-28 03:00:00 935150784.0 1.682651e+12
2023-04-28 04:00:00 934870976.0 1.682654e+12
2023-04-28 05:00:00 933942976.0 1.682658e+12
'''
If you want to get open interest data for longer than 200 periods, you can apply the same logic as we used for the get_klines method previously.