diff --git a/build/lib/ftx/__init__.py b/build/lib/ftx/__init__.py deleted file mode 100644 index 82fbd51..0000000 --- a/build/lib/ftx/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from api import FtxClient \ No newline at end of file diff --git a/build/lib/ftx/api.py b/build/lib/ftx/api.py deleted file mode 100644 index 1bf3550..0000000 --- a/build/lib/ftx/api.py +++ /dev/null @@ -1,254 +0,0 @@ -import time -import urllib.parse -from typing import Optional, Dict, Any, List - -from requests import Request, Session, Response -import hmac -from ciso8601 import parse_datetime - - -class FtxClient: - - def __init__(self, base_url=None, api_key=None, api_secret=None, subaccount_name=None) -> None: - self._session = Session() - self._base_url = 'https://ftx.com/api/' - self._api_key = api_key - self._api_secret = api_secret - self._subaccount_name = subaccount_name - - def _get(self, path: str, params: Optional[Dict[str, Any]] = None) -> Any: - return self._request('GET', path, params=params) - - def _post(self, path: str, params: Optional[Dict[str, Any]] = None) -> Any: - return self._request('POST', path, json=params) - - def _delete(self, path: str, params: Optional[Dict[str, Any]] = None) -> Any: - return self._request('DELETE', path, json=params) - - def _request(self, method: str, path: str, **kwargs) -> Any: - request = Request(method, self._base_url + path, **kwargs) - if self._api_key: - self._sign_request(request) - response = self._session.send(request.prepare()) - - return self._process_response(response) - - def _sign_request(self, request: Request) -> None: - ts = int(time.time() * 1000) - prepared = request.prepare() - signature_payload = f'{ts}{prepared.method}{prepared.path_url}'.encode() - if prepared.body: - signature_payload += prepared.body - signature = hmac.new(self._api_secret.encode(), signature_payload, 'sha256').hexdigest() - request.headers['FTX-KEY'] = self._api_key - request.headers['FTX-SIGN'] = signature - request.headers['FTX-TS'] = str(ts) - if self._subaccount_name: - request.headers['FTX-SUBACCOUNT'] = urllib.parse.quote(self._subaccount_name) - - def _process_response(self, response: Response) -> Any: - try: - data = response.json() - except ValueError: - response.raise_for_status() - raise - else: - if not data['success']: - raise Exception(data['error']) - return data['result'] - - - # - # Authentication required methods - # - - def authentication_required(fn): - """Annotation for methods that require auth.""" - def wrapped(self, *args, **kwargs): - if not self._api_key: - raise TypeError("You must be authenticated to use this method") - else: - return fn(self, *args, **kwargs) - return wrapped - - @authentication_required - def get_account_info(self) -> dict: - return self._get(f'account') - - @authentication_required - def get_open_orders(self, market: str = None) -> List[dict]: - return self._get(f'orders', {'market': market}) - - @authentication_required - def get_order_history(self, market: str = None, side: str = None, order_type: str = None, start_time: float = None, end_time: float = None) -> List[dict]: - return self._get(f'orders/history', {'market': market, 'side': side, 'orderType': order_type, 'start_time': start_time, 'end_time': end_time}) - - @authentication_required - def get_conditional_order_history(self, market: str = None, side: str = None, type: str = None, order_type: str = None, start_time: float = None, end_time: float = None) -> List[dict]: - return self._get(f'conditional_orders/history', {'market': market, 'side': side, 'type': type, 'orderType': order_type, 'start_time': start_time, 'end_time': end_time}) - - @authentication_required - def modify_order( - self, existing_order_id: Optional[str] = None, - existing_client_order_id: Optional[str] = None, price: Optional[float] = None, - size: Optional[float] = None, client_order_id: Optional[str] = None, - ) -> dict: - assert (existing_order_id is None) ^ (existing_client_order_id is None), \ - 'Must supply exactly one ID for the order to modify' - assert (price is None) or (size is None), 'Must modify price or size of order' - path = f'orders/{existing_order_id}/modify' if existing_order_id is not None else \ - f'orders/by_client_id/{existing_client_order_id}/modify' - return self._post(path, { - **({'size': size} if size is not None else {}), - **({'price': price} if price is not None else {}), - ** ({'clientId': client_order_id} if client_order_id is not None else {}), - }) - - @authentication_required - def get_conditional_orders(self, market: str = None) -> List[dict]: - return self._get(f'conditional_orders', {'market': market}) - - @authentication_required - def place_order(self, market: str, side: str, price: float, size: float, type: str = 'limit', - reduce_only: bool = False, ioc: bool = False, post_only: bool = False, - client_id: str = None) -> dict: - return self._post(f'orders', {'market': market, - 'side': side, - 'price': price, - 'size': size, - 'type': type, - 'reduceOnly': reduce_only, - 'ioc': ioc, - 'postOnly': post_only, - 'clientId': client_id, - }) - @authentication_required - def place_conditional_order( - self, market: str, side: str, size: float, type: str = 'stop', - limit_price: float = None, reduce_only: bool = False, cancel: bool = True, - trigger_price: float = None, trail_value: float = None - ) -> dict: - """ - To send a Stop Market order, set type='stop' and supply a trigger_price - To send a Stop Limit order, also supply a limit_price - To send a Take Profit Market order, set type='trailing_stop' and supply a trigger_price - To send a Trailing Stop order, set type='trailing_stop' and supply a trail_value - """ - assert type in ('stop', 'take_profit', 'trailing_stop') - assert type not in ('stop', 'take_profit') or trigger_price is not None, \ - 'Need trigger prices for stop losses and take profits' - assert type not in ('trailing_stop',) or (trigger_price is None and trail_value is not None), \ - 'Trailing stops need a trail value and cannot take a trigger price' - - return self._post(f'conditional_orders', - {'market': market, 'side': side, 'triggerPrice': trigger_price, - 'size': size, 'reduceOnly': reduce_only, 'type': 'stop', - 'cancelLimitOnTrigger': cancel, 'orderPrice': limit_price}) - - @authentication_required - def cancel_order(self, order_id: str) -> dict: - return self._delete(f'orders/{order_id}') - - @authentication_required - def cancel_orders(self, market_name: str = None, conditional_orders: bool = False, - limit_orders: bool = False) -> dict: - return self._delete(f'orders', {'market': market_name, - 'conditionalOrdersOnly': conditional_orders, - 'limitOrdersOnly': limit_orders, - }) - - @authentication_required - def get_fills(self) -> List[dict]: - return self._get(f'fills') - - @authentication_required - def get_balances(self) -> List[dict]: - return self._get(f'wallet/balances') - - @authentication_required - def get_deposit_address(self, ticker: str) -> dict: - return self._get(f'wallet/deposit_address/{ticker}') - - @authentication_required - def get_positions(self, show_avg_price: bool = False) -> List[dict]: - return self._get(f'positions', {'showAvgPrice': show_avg_price}) - - @authentication_required - def get_position(self, name: str, show_avg_price: bool = False) -> dict: - return next(filter(lambda x: x['future'] == name, self.get_positions(show_avg_price)), None) - - @authentication_required - def set_leverage(self, leverage): - return self._post(f'account/leverage', {'leverage': leverage}) - - @authentication_required - def get_subaccounts(self) -> List[dict]: - return self._get(f'subaccounts') - - @authentication_required - def create_subaccounts(self, nickname) -> List[dict]: - return self._post(f'subaccounts', {'nickname': nickname}) - - @authentication_required - def delete_subaccounts(self, nickname) -> List[dict]: - return self._delete(f'subaccounts', {'nickname': nickname}) - - @authentication_required - def get_subaccounts_balance(self, nickname) -> List[dict]: - return self._get(f'subaccounts/{nickname}/balances', {'nickname': nickname}) - - @authentication_required - def request_quote(self, fromCoin, toCoin , size) -> List[dict]: - return self._post(f'otc/quotes', {'fromCoin': fromCoin, 'toCoin': toCoin, 'size': size}) - - # - # Public methods - # - - def get_futures(self) -> List[dict]: - return self._get(f'futures') - - def get_future(self, future_name: str) -> dict: - return self._get(f'futures/{future_name}') - - def get_markets(self) -> List[dict]: - return self._get(f'markets') - - def get_market(self, market: str) -> dict: - return self._get(f'markets/{market}') - - def get_orderbook(self, market: str, depth: int = None) -> dict: - return self._get(f'markets/{market}/orderbook', {'depth': depth}) - - def get_trades(self, market: str, limit: int = 100, start_time: float = None, end_time: float = None) -> dict: - return self._get(f'markets/{market}/trades', {'limit':limit, 'start_time': start_time, 'end_time': end_time}) - - def get_all_trades(self, market: str, start_time: float = None, end_time: float = None) -> List: - ids = set() - limit = 100 - results = [] - while True: - response = self._get(f'markets/{market}/trades', { - 'end_time': end_time, - 'start_time': start_time, - }) - deduped_trades = [r for r in response if r['id'] not in ids] - results.extend(deduped_trades) - ids |= {r['id'] for r in deduped_trades} - print(f'Adding {len(response)} trades with end time {end_time}') - if len(response) == 0: - break - end_time = min(parse_datetime(t['time']) for t in response).timestamp() - if len(response) < limit: - break - return results - - def get_historical_data(self,market_name: str,resolution: int ,limit: int ,start_time: float ,end_time: float ) -> dict: - return self._get(f'markets/{market_name}/candles', dict(resolution=resolution,limit=limit,start_time=start_time,end_time=end_time)) - - def get_future_stats(self, future_name) -> List[dict]: - return self._get(f'futures/{future_name}/stats', {'future_name' : future_name}) - - def get_funding_rates(self) -> List[dict]: - return self._get(f'funding_rates') - diff --git a/dist/ftx-0.0.1-py3-none-any.whl b/dist/ftx-0.0.1-py3-none-any.whl deleted file mode 100644 index 5d71e3b..0000000 Binary files a/dist/ftx-0.0.1-py3-none-any.whl and /dev/null differ diff --git a/dist/ftx-0.0.1.tar.gz b/dist/ftx-0.0.1.tar.gz deleted file mode 100644 index 9fd121a..0000000 Binary files a/dist/ftx-0.0.1.tar.gz and /dev/null differ diff --git a/ftx.egg-info/PKG-INFO b/ftx.egg-info/PKG-INFO deleted file mode 100644 index 6685765..0000000 --- a/ftx.egg-info/PKG-INFO +++ /dev/null @@ -1,104 +0,0 @@ -Metadata-Version: 1.1 -Name: ftx -Version: 0.0.1 -Summary: Unofficial python3 FTX exchange API 1.0. -Home-page: https://github.com/thomgabriel/ftx -Author: thomgabriel -Author-email: thomgabriel@protonmail.com -License: MIT -Download-URL: https://github.com/thomgabriel/ftx/dist/ftx-0.0.1.tar.gz -Description: # FTX Python client - A Unofficial Python3 library to interact with [FTX's](https://ftx.com/) API. The library can be used to fetch - market data, make trades, place orders or create third-party clients. - - For more information, see [the FTX documentation.](https://docs.ftx.com/) - - - ## Installation - - $ pip install ftx - - ## Quickstart - This is an introduction on how to get started with FTX client. First, make sure the FTX library is installed. - - The next thing you need to do is import the library and get an instance of the client: - - import ftx - client = ftx.FtxClient() - - - ### Get ordedrbook - Get the orderbook levels of bid/ask: - - >>> import ftx - >>> client = ftx.FtxClient() - >>> result = client.get_orderbook('BTC/USD', 1) - >>> result - {'asks': [[11861.0, 1.778]], 'bids': [[11860.5, 0.1]]} - - >>> result['asks'] - [[11861.0, 1.778]] - - >>> result['bids'] - [[11860.5, 0.1]] - - ### Market's Instrument data - The API supports fetching full data for one or multiple markets. - - >>> client.get_market('BTC/USD') - {'ask': 11849.0, 'baseCurrency': 'BTC', 'bid': 11848.5, 'change1h': 0.00025325004220834034, 'change24h': 0.008983693106825051, 'changeBod': 0.006925855109411514, 'enabled': True, 'last': 11849.0, 'minProvideSize': 0.0001, 'name': 'BTC/USD', 'postOnly': False, 'price': 11849.0, 'priceIncrement': 0.5, 'quoteCurrency': 'USD', 'quoteVolume24h': 9271567.5201, 'restricted': False, 'sizeIncrement': 0.0001, 'type': 'spot', 'underlying': None, 'volumeUsd24h': 9271567.5201} - - ### Date ranges - Any time-based parameters accept Python `datetime` objects. All timestamps returned from FTX are UTC. - - >>> client = ftx.FtxClient() - >>> client.get_trades('BTC/USD', 1, datetime.datetime(2020,8,20).timestamp()) - [{'id': 88953674, 'liquidation': False, 'price': 11861.0, 'side': 'sell', 'size': 0.0105, 'time': '2020-08-20T17:33:19.115690+00:00'}] - - ### Authenticated endpoints - Private endpoints require authentication. Clients authenticate with an API key. For more information, see:[API keys](https://help.ftx.com/hc/en-us/articles/360044411911-FTX-Features-Overview#h_6a76d63d-e6cd-45db-87ab-5778af4e3b07) - - To get an authenticated client instance: - - >>> client = ftx.FtxClient(api_key=, api_secret=) - - If you try to access a private endpoint with an unauthenticated client, an error is raised. Calls - to private endpoints work the same as regular ones: - - client.get_open_orders('BTC/USD') - - - ## Advanced usage - - ### Placing orders - An order can be placed through the `place_order()` function. See - [the API Documentation](https://docs.ftx.com/#place-order) for required and optional parameters. - - client.place_order('BTC/USD', 'sell', 12345.0, 10) - - ### Modifying orders - Orders can be modified by providing the original order ID. - - >>> client.place_order('BTC/USD', 'sell', 12345.0, 10) - {"createdAt": "2020-08-20T17:33:19.115690+00:00","filledSize": 0,"id": 9596912,"market": "BTC/USD"... - - >>> client.modify_order(9596912, 12500.0, 15).result() - - ### Canceling orders - An order can be canceled given the order ID: - - client.cancel_order(9596912).result() - -Keywords: ftx,bitcoin,crypto-api,api-connector,exchange-api,crypto-exchange,digital-currency,trading -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Financial and Insurance Industry -Classifier: Topic :: Software Development -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Operating System :: OS Independent diff --git a/ftx.egg-info/SOURCES.txt b/ftx.egg-info/SOURCES.txt deleted file mode 100644 index c0132b7..0000000 --- a/ftx.egg-info/SOURCES.txt +++ /dev/null @@ -1,9 +0,0 @@ -README.md -setup.py -ftx/__init__.py -ftx/api.py -ftx.egg-info/PKG-INFO -ftx.egg-info/SOURCES.txt -ftx.egg-info/dependency_links.txt -ftx.egg-info/requires.txt -ftx.egg-info/top_level.txt \ No newline at end of file diff --git a/ftx.egg-info/dependency_links.txt b/ftx.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/ftx.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ftx.egg-info/requires.txt b/ftx.egg-info/requires.txt deleted file mode 100644 index b58d75d..0000000 --- a/ftx.egg-info/requires.txt +++ /dev/null @@ -1,3 +0,0 @@ -requests==2.23.0 -satoshi==0.1.3 -schedule==0.6.0 diff --git a/ftx.egg-info/top_level.txt b/ftx.egg-info/top_level.txt deleted file mode 100644 index d2ac2e2..0000000 --- a/ftx.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -ftx