diff --git a/backpack_exchange_sdk/__init__.py b/backpack_exchange_sdk/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backpack_exchange_sdk/authenticated.py b/backpack_exchange_sdk/authenticated.py new file mode 100644 index 0000000..56e2ac3 --- /dev/null +++ b/backpack_exchange_sdk/authenticated.py @@ -0,0 +1,72 @@ +import base64 +import json +import time +import requests +from cryptography.hazmat.primitives.asymmetric import ed25519 + + +class AuthenticationClient: + base_url = 'https://api.backpack.exchange/' + private_key_obj: ed25519.Ed25519PrivateKey + + def __init__(self): + self.is_debug_mode = False + self.network_proxies = {'http': '', 'https': ''} + self.key = '' + self.secret = '' + + def setup(self, key, secret): + self.key = key + self.secret = secret + self.private_key_obj = ed25519.Ed25519PrivateKey.from_private_bytes( + base64.b64decode(secret) + ) + + def get_balances(self): + return self._send_request('GET', 'api/v1/capital', 'balanceQuery', {}) + + def get_deposits(self): + return self._send_request('GET', 'wapi/v1/capital/deposits', 'depositQueryAll', {}) + + def get_deposit_address(self, blockchain_name: str): + params = {'blockchain': blockchain_name} + return self._send_request('GET', 'wapi/v1/capital/deposit/address', 'depositAddressQuery', params) + + def get_withdrawals(self, num: int, start: int): + params = {'limit': num, 'offset': start} + return self._send_request('GET', 'wapi/v1/capital/withdrawals', 'withdrawalQueryAll', params) + + def make_withdrawal(self, wallet_address: str, asset_symbol: str, chain_name: str, amount: str): + data = { + 'address': wallet_address, + 'blockchain': chain_name, + 'quantity': amount, + 'symbol': asset_symbol, + } + return self._send_request('POST', 'wapi/v1/capital/withdrawals', 'withdraw', data) + + def _send_request(self, method, endpoint, action, params): + url = f'{self.base_url}{endpoint}' + ts = int(time.time() * 1e3) + headers = self._generate_signature(action, ts, params) + if method == 'GET': + response = requests.get(url, headers=headers, params=params, proxies=self.network_proxies) + else: + response = requests.post(url, headers=headers, data=json.dumps(params), proxies=self.network_proxies) + return response.json() + + def _generate_signature(self, action: str, timestamp: int, params=None): + if params is None: + params = {} + if 'postOnly' in params: + params = params.copy() + params['postOnly'] = str(params['postOnly']).lower() + param_str = "&".join(f"{k}={v}" for k, v in sorted(params.items())) + sign_str = f"instruction={action}&{param_str}×tamp={timestamp}&window={self.window}" + signature = base64.b64encode(self.private_key_obj.sign(sign_str.encode())).decode() + return { + "X-API-Key": self.key, + "X-Signature": signature, + "X-Timestamp": str(timestamp), + "Content-Type": "application/json; charset=utf-8", + } diff --git a/backpack_exchange_sdk/public.py b/backpack_exchange_sdk/public.py new file mode 100644 index 0000000..9c193eb --- /dev/null +++ b/backpack_exchange_sdk/public.py @@ -0,0 +1,83 @@ +import requests + +class PublicClient: + def __init__(self): + self.base_url = 'https://api.backpack.exchange/' + + # Market - Public market data. + def get_assets(self): + """ + Retrieves all the assets that are supported by the exchange. + """ + return requests.get(url=f'{self.base_url}api/v1/assets').json() + + def get_markets(self): + """ + Retrieves all the markets that are supported by the exchange. + """ + return requests.get(url=f'{self.base_url}api/v1/markets').json() + + def get_ticker(self, symbol: str): + """ + Retrieves summarised statistics for the last 24 hours for the given market symbol. + """ + return requests.get(url=f'{self.base_url}api/v1/ticker', params={'symbol': symbol}).json() + + def get_tickers(self): + """ + Retrieves summarised statistics for the last 24 hours for all market symbols. + """ + return requests.get(url=f'{self.base_url}api/v1/tickers').json() + + def get_order_book_depth(self, symbol: str): + """ + Retrieves the order book depth for a given market symbol. + """ + return requests.get(url=f'{self.base_url}api/v1/depth', params={'symbol': symbol}).json() + + def get_klines(self, symbol: str, interval: str, start_time: int = 0, end_time: int = 0): + """ + Get K-Lines for the given market symbol, optionally providing a startTime and endTime. If no startTime is provided, the interval duration will be used. If no endTime is provided, the current time will be used. + """ + params = {'symbol': symbol, 'interval': interval} + if start_time > 0: + params['startTime'] = start_time + if end_time > 0: + params['endTime'] = end_time + return requests.get(url=f'{self.base_url}api/v1/klines', params=params).json() + + + # System - Exchange system status. + def get_status(self): + """ + Get the system status, and the status message, if any. + """ + return requests.get(url=f'{self.base_url}api/v1/status').json() + + def send_ping(self): + """ + Responds with pong. + """ + return requests.get(url=f'{self.base_url}api/v1/ping').text + + def get_system_time(self): + """ + Retrieves the current system time. + """ + return requests.get(url=f'{self.base_url}api/v1/time').text + + # Trades - Public trade data. + def get_recent_trades(self, symbol: str, limit: int = 100): + """ + Retrieve the most recent trades for a symbol. This is public data and is not specific to any account. + The maximum available recent trades is 1000. If you need more than 1000 trades use the historical trades endpoint. + """ + params = {'symbol': symbol, 'limit': limit} + return requests.get(url=f'{self.base_url}api/v1/trades', params=params).json() + + def get_historical_trades(self, symbol: str, limit: int = 100, offset: int = 0): + """ + Retrieves all historical trades for the given symbol. This is public trade data and is not specific to any account. + """ + params = {'symbol': symbol, 'limit': limit, 'offset': offset} + return requests.get(url=f'{self.base_url}api/v1/trades/history', params=params).json() \ No newline at end of file diff --git a/examples/example_authenticated.py b/examples/example_authenticated.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/example_public.py b/examples/example_public.py new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/_init__.py b/tests/_init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_authenticated.py b/tests/test_authenticated.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_public.py b/tests/test_public.py new file mode 100644 index 0000000..e69de29