From 7ccc3b306c0701925eeb03d36b5d0ec108b98e9e Mon Sep 17 00:00:00 2001 From: Pourya Moghadam Date: Fri, 12 Aug 2022 21:23:59 +0430 Subject: [PATCH 1/8] - bug fix file imports - update requirements.txt file - bug fix require packages --- requirements.txt | 7 +++++++ setup.cfg | 4 ++-- setup.py | 4 ++-- src/wallex/client.py | 6 +++--- src/wallex/request.py | 2 +- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/requirements.txt b/requirements.txt index e69de29..079167b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,7 @@ +certifi==2022.6.15 +charset-normalizer==2.1.0 +idna==3.3 +pydantic==1.9.2 +requests==2.28.1 +typing_extensions==4.3.0 +urllib3==1.26.11 diff --git a/setup.cfg b/setup.cfg index 7a1f31d..ab8d84c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = wallex-python -version = 0.0.1 +version = 0.0.2 author = Pourya Moghadam author_email = p.moghadam@msn.com description = Wallex Exchange Unofficial API Python Client @@ -9,7 +9,7 @@ long_description_content_type = text/markdown url = https://github.com/wallexchange/wallex-python license = MIT keywords = wallex exchange api bitcoin ethereum btc eth python client -dependencies= pydantic requests +install_requires= pydantic requests project_urls = Bug Tracker = https://github.com/wallexchange/wallex-python/issues Documentation = https://api-docs.wallex.ir/ diff --git a/setup.py b/setup.py index 36f93da..6d12e08 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setuptools.setup( name="wallex-python", - version="0.0.1", + version="0.0.2", author="Pourya Moghadam", author_email="p.moghadam@msn.com", description="Wallex Exchange Unofficial API Python Client", @@ -15,7 +15,7 @@ url="https://github.com/wallexchange/wallex-python", license="MIT", keywords='wallex exchange api bitcoin ethereum btc eth python', - dependencies=['pydantic', 'requests'], + install_requires=['pydantic', 'requests'], project_urls={ "Bug Tracker": "https://github.com/wallexchange/wallex-python/issues", "Documentation": "https://api-docs.wallex.ir/", diff --git a/src/wallex/client.py b/src/wallex/client.py index 0f534cb..9491a5b 100644 --- a/src/wallex/client.py +++ b/src/wallex/client.py @@ -1,9 +1,9 @@ from pydantic import validate_arguments -from src.wallex.request import RequestsApi -from src.wallex.schema import MarketsResponseModel, CurrenciesResponseModel, MarketOrderDetailModel, ClientSymbolInput, \ +from wallex.request import RequestsApi +from wallex.schema import MarketsResponseModel, CurrenciesResponseModel, MarketOrderDetailModel, ClientSymbolInput, \ MarketTradesModel, MarketCandlesRequestModel, MarketCandlesResponseModel, AccountFeeLevelsResponseModel, \ AccountBalancesResponseModel, PlaceOrderRequestModel, PlaceOrderResponseModel, LastTradesResponseModel -from src.wallex.utils import create_list_by_symbol, create_list +from wallex.utils import create_list_by_symbol, create_list class Client: diff --git a/src/wallex/request.py b/src/wallex/request.py index d1a0a01..960a9d9 100644 --- a/src/wallex/request.py +++ b/src/wallex/request.py @@ -1,5 +1,5 @@ import requests -from src.wallex.utils import error_handler +from wallex.utils import error_handler class RequestsApi: From 6859c50a538e5d5b0e8adc23871caef0e1fcd1a4 Mon Sep 17 00:00:00 2001 From: Pourya Moghadam Date: Fri, 12 Aug 2022 21:33:16 +0430 Subject: [PATCH 2/8] - bug fix require packages --- setup.cfg | 4 ++-- setup.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.cfg b/setup.cfg index ab8d84c..344f721 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = wallex-python -version = 0.0.2 +version = 0.0.3 author = Pourya Moghadam author_email = p.moghadam@msn.com description = Wallex Exchange Unofficial API Python Client @@ -9,7 +9,7 @@ long_description_content_type = text/markdown url = https://github.com/wallexchange/wallex-python license = MIT keywords = wallex exchange api bitcoin ethereum btc eth python client -install_requires= pydantic requests +install_requires= pydantic requests certifi charset-normalizer idna typing_extensions urllib3 project_urls = Bug Tracker = https://github.com/wallexchange/wallex-python/issues Documentation = https://api-docs.wallex.ir/ diff --git a/setup.py b/setup.py index 6d12e08..45c8daf 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setuptools.setup( name="wallex-python", - version="0.0.2", + version="0.0.3", author="Pourya Moghadam", author_email="p.moghadam@msn.com", description="Wallex Exchange Unofficial API Python Client", @@ -15,7 +15,7 @@ url="https://github.com/wallexchange/wallex-python", license="MIT", keywords='wallex exchange api bitcoin ethereum btc eth python', - install_requires=['pydantic', 'requests'], + install_requires=['pydantic', 'requests', 'certifi', 'charset-normalizer', 'idna', 'typing_extensions', 'urllib3'], project_urls={ "Bug Tracker": "https://github.com/wallexchange/wallex-python/issues", "Documentation": "https://api-docs.wallex.ir/", From 47fd40d139543d1dcaaded9f804bebe3228d15bc Mon Sep 17 00:00:00 2001 From: Pourya Moghadam Date: Fri, 12 Aug 2022 22:00:38 +0430 Subject: [PATCH 3/8] - bug fix require packages versions --- README.md | 2 +- setup.cfg | 5 ++--- setup.py | 9 ++++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 51e67e4..9fb3a1d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Wallex-python v.0.0.1 +Wallex-python v.0.0.5 =========================================================== ## Wallex Python SDK diff --git a/setup.cfg b/setup.cfg index 344f721..d86c5f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = wallex-python -version = 0.0.3 +version = 0.0.5 author = Pourya Moghadam author_email = p.moghadam@msn.com description = Wallex Exchange Unofficial API Python Client @@ -8,8 +8,7 @@ long_description = file: README.md long_description_content_type = text/markdown url = https://github.com/wallexchange/wallex-python license = MIT -keywords = wallex exchange api bitcoin ethereum btc eth python client -install_requires= pydantic requests certifi charset-normalizer idna typing_extensions urllib3 +keywords = wallex exchange crypto api bitcoin ethereum btc eth python client project_urls = Bug Tracker = https://github.com/wallexchange/wallex-python/issues Documentation = https://api-docs.wallex.ir/ diff --git a/setup.py b/setup.py index 45c8daf..caa92a0 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setuptools.setup( name="wallex-python", - version="0.0.3", + version="0.0.5", author="Pourya Moghadam", author_email="p.moghadam@msn.com", description="Wallex Exchange Unofficial API Python Client", @@ -14,8 +14,11 @@ long_description_content_type="text/markdown", url="https://github.com/wallexchange/wallex-python", license="MIT", - keywords='wallex exchange api bitcoin ethereum btc eth python', - install_requires=['pydantic', 'requests', 'certifi', 'charset-normalizer', 'idna', 'typing_extensions', 'urllib3'], + keywords='wallex crypto exchange api bitcoin ethereum btc eth python', + install_requires=[ + 'requests==2.28.1', + 'pydantic==1.9.2' + ], project_urls={ "Bug Tracker": "https://github.com/wallexchange/wallex-python/issues", "Documentation": "https://api-docs.wallex.ir/", From a3a07f75188bb3a4a8c0eca70fd7506fe4bd62df Mon Sep 17 00:00:00 2001 From: Pourya Moghadam Date: Fri, 12 Aug 2022 22:03:51 +0430 Subject: [PATCH 4/8] - update md file and version --- README.md | 2 +- setup.cfg | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9fb3a1d..5402d9f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Wallex-python v.0.0.5 +Wallex-python v.0.0.6 =========================================================== ## Wallex Python SDK diff --git a/setup.cfg b/setup.cfg index d86c5f3..28d64f4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = wallex-python -version = 0.0.5 +version = 0.0.6 author = Pourya Moghadam author_email = p.moghadam@msn.com description = Wallex Exchange Unofficial API Python Client diff --git a/setup.py b/setup.py index caa92a0..449da53 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setuptools.setup( name="wallex-python", - version="0.0.5", + version="0.0.6", author="Pourya Moghadam", author_email="p.moghadam@msn.com", description="Wallex Exchange Unofficial API Python Client", From 86f8672c0d5ca99f37b3acd2c2e972a0e5244a9a Mon Sep 17 00:00:00 2001 From: amiwrpremium Date: Wed, 17 Aug 2022 16:51:45 +0430 Subject: [PATCH 5/8] async client --- setup.cfg | 2 +- setup.py | 2 +- src/wallex/async_client.py | 163 +++++++++++++++++++++++++++++++++++++ src/wallex/request.py | 42 ++++++++++ src/wallex/utils.py | 19 ++++- 5 files changed, 223 insertions(+), 5 deletions(-) create mode 100644 src/wallex/async_client.py diff --git a/setup.cfg b/setup.cfg index 28d64f4..9e9eea6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = wallex-python -version = 0.0.6 +version = 0.0.7 author = Pourya Moghadam author_email = p.moghadam@msn.com description = Wallex Exchange Unofficial API Python Client diff --git a/setup.py b/setup.py index 449da53..832c30d 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setuptools.setup( name="wallex-python", - version="0.0.6", + version="0.0.7", author="Pourya Moghadam", author_email="p.moghadam@msn.com", description="Wallex Exchange Unofficial API Python Client", diff --git a/src/wallex/async_client.py b/src/wallex/async_client.py new file mode 100644 index 0000000..feb9a6f --- /dev/null +++ b/src/wallex/async_client.py @@ -0,0 +1,163 @@ +from pydantic import validate_arguments + +from wallex.request import AsyncRequestsApi +from wallex.schema import MarketsResponseModel, CurrenciesResponseModel, MarketOrderDetailModel, ClientSymbolInput, \ + MarketTradesModel, MarketCandlesRequestModel, MarketCandlesResponseModel, AccountFeeLevelsResponseModel, \ + AccountBalancesResponseModel, PlaceOrderRequestModel, PlaceOrderResponseModel, LastTradesResponseModel +from wallex.utils import create_list_by_symbol, create_list + + +class AsyncClient: + """ + :param api_key: str = Wallex API key (required) + :method host_is_online: bool = Returns True if Wallex API is online + :method get_profile: dict = Returns user info + :return: WallexClient + """ + + @validate_arguments + def __init__(self, api_key: str, loop=None) -> None: + self.client_user = None + self.loop = loop + self.consumer = AsyncRequestsApi( + base_url='https://api.wallex.ir', + headers={"X-API-Key": api_key}, + loop=loop + ) + + @classmethod + async def create_client(cls, api_key: str = None, loop=None): + self = cls(api_key, loop) + + if api_key: + try: + self.client_user = await self.get_profile() + print('client user:', self.client_user['first_name'] + ' ' + self.client_user['last_name']) + except Exception as e: + raise Exception('can not access wallex api online server', e) + + return self + + async def get_markets(self): + res = await self.consumer.get('/v1/markets') + json_res = await res.json() + symbols = json_res['result']['symbols'] + return create_list_by_symbol(symbols, MarketsResponseModel) + + async def get_currencies(self): + res = await self.consumer.get('/v1/currencies/stats') + json_res = await res.json() + return create_list(json_res['result'], CurrenciesResponseModel) + + async def get_market_orders(self, symbol: str): + params = ClientSymbolInput(symbol=symbol) + res = await self.consumer.get('/v1/depth', params=params.dict()) + json_res = await res.json() + return { + 'ask': create_list(json_res['result']['ask'], MarketOrderDetailModel), + 'bid': create_list(json_res['result']['bid'], MarketOrderDetailModel) + } + + async def get_market_trades(self, symbol: str): + params = ClientSymbolInput(symbol=symbol) + res = await self.consumer.get('/v1/trades?', params=params.dict()) + json_res = await res.json() + return { + 'latestTrades': create_list(json_res['result']['latestTrades'], MarketTradesModel) + } + + async def get_market_candles(self, symbol: str, resolution: str, _from, _to): + params = MarketCandlesRequestModel(symbol=symbol, resolution=resolution, start_time=_from, end_time=_to).dict() + res = await self.consumer.get('/v1/udf/history?', params={ + 'symbol': params['symbol'], + 'resolution': params['resolution'], + 'from': int(round(params['start_time'].timestamp())), + 'to': int(round(params['end_time'].timestamp())) + }) + json_res = await res.json() + checked_r = MarketCandlesResponseModel(**json_res) + return checked_r.dict() + + async def get_profile(self): + res = await self.consumer.get('/v1/account/profile') + json_res = await res.json() + return json_res['result'] + + async def get_fee_levels(self): + res = await self.consumer.get('/v1/account/fee') + json_res = await res.json() + return create_list_by_symbol(json_res['result'], AccountFeeLevelsResponseModel) + + # TODO: get 401 auth error when calling this method + async def get_banking_cards(self): + res = await self.consumer.get('/v1/account/card-numbers') + json_res = await res.json() + return json_res['result'] + + # TODO: get 500 server error when calling this method + async def get_banking_accounts(self): + res = await self.consumer.get('/v1/account/ibans') + json_res = await res.json() + return json_res['result'] + + async def get_balances(self): + temp_balances = {} + res = await self.consumer.get('/v1/account/balances') + json_res = await res.json() + balances = create_list_by_symbol(json_res['result']['balances'], AccountBalancesResponseModel) + for balance in balances: + temp_balances.update(balance) + return { + 'balances': temp_balances + } + + async def get_crypto_withdrawal_list(self): + res = await self.consumer.get('/v1/account/crypto-withdrawal') + json_res = await res.json() + return json_res['result'] + + async def get_crypto_deposit_list(self): + res = await self.consumer.get('/v1/account/crypto-deposit') + json_res = await res.json() + return json_res['result'] + + async def place_order( + self, symbol: str, order_type: str, side: str, quantity: float, price: float, client_id: str = None + ): + params = PlaceOrderRequestModel( + symbol=symbol, order_type=order_type, side=side, + quantity=quantity, price=price, client_id=client_id + ).dict(exclude_none=True) + res = await self.consumer.post('/v1/account/orders', json=params) + json_res = await res.json() + return PlaceOrderResponseModel(**json_res['result']).dict() + + @validate_arguments + async def get_order_detail(self, order_id: str): + res = await self.consumer.get('/v1/account/orders/' + order_id) + json_res = await res.json() + return PlaceOrderResponseModel(**json_res['result']).dict() + + @validate_arguments + async def cancel_order(self, order_id: str): + res = await self.consumer.delete('/v1/account/orders/' + order_id) + json_res = await res.json() + return json_res['result'] + + @validate_arguments + async def get_open_orders(self, symbol: str = None): + res = await self.consumer.get('/v1/account/openOrders', params={'symbol': symbol}) + json_res = await res.json() + return json_res['result'] + + @validate_arguments + async def get_trades(self, symbol: str = None, side: str = None): + res = await self.consumer.get('/v1/account/trades', params={'symbol': symbol, 'side': side}) + json_res = await res.json() + last_trades = create_list(json_res['result']['AccountLatestTrades'], LastTradesResponseModel) + return { + 'AccountLatestTrades': last_trades + } + + async def close(self): + return await self.consumer.close() diff --git a/src/wallex/request.py b/src/wallex/request.py index 960a9d9..f9d49ea 100644 --- a/src/wallex/request.py +++ b/src/wallex/request.py @@ -1,5 +1,8 @@ import requests +import aiohttp + from wallex.utils import error_handler +from wallex.utils import async_error_handler class RequestsApi: @@ -40,3 +43,42 @@ def __deep_merge(source, destination): else: destination[key] = value return destination + + +class AsyncRequestsApi: + def __init__(self, base_url, **kwargs): + self.base_url = base_url + self.session = aiohttp.ClientSession(**kwargs) + + @async_error_handler + async def get(self, url, **kwargs): + return await self.session.get(self.base_url + url, **kwargs) + + @async_error_handler + async def post(self, url, **kwargs): + return await self.session.post(self.base_url + url, **kwargs) + + @async_error_handler + async def put(self, url, **kwargs): + return await self.session.put(self.base_url + url, **kwargs) + + @async_error_handler + async def patch(self, url, **kwargs): + return await self.session.patch(self.base_url + url, **kwargs) + + @async_error_handler + async def delete(self, url, **kwargs): + return await self.session.delete(self.base_url + url, **kwargs) + + @staticmethod + def __deep_merge(source, destination): + for key, value in source.items(): + if isinstance(value, dict): + node = destination.setdefault(key, {}) + AsyncRequestsApi.__deep_merge(value, node) + else: + destination[key] = value + return destination + + async def close(self): + await self.session.close() diff --git a/src/wallex/utils.py b/src/wallex/utils.py index 53a1089..2259a19 100644 --- a/src/wallex/utils.py +++ b/src/wallex/utils.py @@ -1,9 +1,12 @@ -from typing import Any +from typing import Callable, Awaitable +from requests import Response +from aiohttp import ClientResponse -def error_handler(func: Any) -> Any: + +def error_handler(func: Callable[[...], Response]) -> ...: def wrapper(*args, **kwargs): - response = func(*args, **kwargs) + response: Response = func(*args, **kwargs) accepted_status_codes = [200, 201, 202, 204] if response.status_code not in accepted_status_codes: raise Exception('call api error', response.json()) @@ -11,6 +14,16 @@ def wrapper(*args, **kwargs): return wrapper +def async_error_handler(func: Callable[[...], Awaitable[ClientResponse]]) -> ...: + async def wrapper(*args, **kwargs): + response: ClientResponse = await func(*args, **kwargs) + accepted_status_codes = [200, 201, 202, 204] + if response.status not in accepted_status_codes: + raise Exception('call api error', await response.json()) + return response + return wrapper + + def create_list_by_symbol(dict_list: list, model) -> list: result = [] for item in dict_list: From 6e164dd647de3946e6d0bf4c11574aa4f41f07bb Mon Sep 17 00:00:00 2001 From: amiwrpremium Date: Wed, 17 Aug 2022 17:24:54 +0430 Subject: [PATCH 6/8] examples updated --- examples/async/private/cancel_order.py | 12 +++++++++++ examples/async/private/create_new_order.py | 19 ++++++++++++++++++ .../async/private/get_account_balances.py | 12 +++++++++++ .../get_account_crypto_deposit_list.py | 12 +++++++++++ .../get_account_crypto_withdrawal_list.py | 12 +++++++++++ .../async/private/get_account_open_orders.py | 16 +++++++++++++++ .../private/get_account_recent_trades.py | 20 +++++++++++++++++++ examples/async/private/get_order_status.py | 12 +++++++++++ .../private/get_user_banking_accounts.py | 12 +++++++++++ .../async/private/get_user_banking_cards.py | 12 +++++++++++ examples/async/private/get_user_fee_data.py | 12 +++++++++++ .../async/private/get_user_profile_data.py | 12 +++++++++++ examples/async/public/get_currencies.py | 12 +++++++++++ examples/async/public/get_market_stats.py | 12 +++++++++++ examples/async/public/get_ohlc_data.py | 20 +++++++++++++++++++ examples/async/public/get_orderbook.py | 12 +++++++++++ examples/async/public/get_recent_trades.py | 12 +++++++++++ examples/sync/private/cancel_order.py | 11 ++++++++++ examples/sync/private/create_new_order.py | 18 +++++++++++++++++ .../private/get_account_balances.py} | 4 ++-- .../get_account_crypto_deposit_list.py | 11 ++++++++++ .../get_account_crypto_withdrawal_list.py | 11 ++++++++++ .../sync/private/get_account_open_orders.py | 13 ++++++++++++ .../sync/private/get_account_recent_trades.py | 18 +++++++++++++++++ examples/sync/private/get_order_status.py | 11 ++++++++++ .../sync/private/get_user_banking_accounts.py | 11 ++++++++++ .../sync/private/get_user_banking_cards.py | 11 ++++++++++ examples/sync/private/get_user_fee_data.py | 11 ++++++++++ .../sync/private/get_user_profile_data.py | 11 ++++++++++ examples/sync/public/get_currencies.py | 11 ++++++++++ examples/sync/public/get_market_stats.py | 11 ++++++++++ examples/sync/public/get_ohlc_data.py | 17 ++++++++++++++++ examples/sync/public/get_orderbook.py | 11 ++++++++++ examples/sync/public/get_recent_trades.py | 11 ++++++++++ 34 files changed, 431 insertions(+), 2 deletions(-) create mode 100644 examples/async/private/cancel_order.py create mode 100644 examples/async/private/create_new_order.py create mode 100644 examples/async/private/get_account_balances.py create mode 100644 examples/async/private/get_account_crypto_deposit_list.py create mode 100644 examples/async/private/get_account_crypto_withdrawal_list.py create mode 100644 examples/async/private/get_account_open_orders.py create mode 100644 examples/async/private/get_account_recent_trades.py create mode 100644 examples/async/private/get_order_status.py create mode 100644 examples/async/private/get_user_banking_accounts.py create mode 100644 examples/async/private/get_user_banking_cards.py create mode 100644 examples/async/private/get_user_fee_data.py create mode 100644 examples/async/private/get_user_profile_data.py create mode 100644 examples/async/public/get_currencies.py create mode 100644 examples/async/public/get_market_stats.py create mode 100644 examples/async/public/get_ohlc_data.py create mode 100644 examples/async/public/get_orderbook.py create mode 100644 examples/async/public/get_recent_trades.py create mode 100644 examples/sync/private/cancel_order.py create mode 100644 examples/sync/private/create_new_order.py rename examples/{get_wallex_markets.py => sync/private/get_account_balances.py} (72%) create mode 100644 examples/sync/private/get_account_crypto_deposit_list.py create mode 100644 examples/sync/private/get_account_crypto_withdrawal_list.py create mode 100644 examples/sync/private/get_account_open_orders.py create mode 100644 examples/sync/private/get_account_recent_trades.py create mode 100644 examples/sync/private/get_order_status.py create mode 100644 examples/sync/private/get_user_banking_accounts.py create mode 100644 examples/sync/private/get_user_banking_cards.py create mode 100644 examples/sync/private/get_user_fee_data.py create mode 100644 examples/sync/private/get_user_profile_data.py create mode 100644 examples/sync/public/get_currencies.py create mode 100644 examples/sync/public/get_market_stats.py create mode 100644 examples/sync/public/get_ohlc_data.py create mode 100644 examples/sync/public/get_orderbook.py create mode 100644 examples/sync/public/get_recent_trades.py diff --git a/examples/async/private/cancel_order.py b/examples/async/private/cancel_order.py new file mode 100644 index 0000000..a266ed2 --- /dev/null +++ b/examples/async/private/cancel_order.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.cancel_order(order_id='ORDER_ID') + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/create_new_order.py b/examples/async/private/create_new_order.py new file mode 100644 index 0000000..e8ee4db --- /dev/null +++ b/examples/async/private/create_new_order.py @@ -0,0 +1,19 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.place_order( + symbol='USDTTMN', + side='buy', + order_type='limit', + quantity=11, + price=25000, + client_id='CLIENT_ID', + ) + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_account_balances.py b/examples/async/private/get_account_balances.py new file mode 100644 index 0000000..e701eea --- /dev/null +++ b/examples/async/private/get_account_balances.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_balances() + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_account_crypto_deposit_list.py b/examples/async/private/get_account_crypto_deposit_list.py new file mode 100644 index 0000000..88254da --- /dev/null +++ b/examples/async/private/get_account_crypto_deposit_list.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_crypto_deposit_list() + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_account_crypto_withdrawal_list.py b/examples/async/private/get_account_crypto_withdrawal_list.py new file mode 100644 index 0000000..dd922a3 --- /dev/null +++ b/examples/async/private/get_account_crypto_withdrawal_list.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_crypto_withdrawal_list() + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_account_open_orders.py b/examples/async/private/get_account_open_orders.py new file mode 100644 index 0000000..72e09b1 --- /dev/null +++ b/examples/async/private/get_account_open_orders.py @@ -0,0 +1,16 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + + data = await client.get_open_orders() + data2 = await client.get_open_orders(symbol='USDTTMN') + + print(data) + print(data2) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_account_recent_trades.py b/examples/async/private/get_account_recent_trades.py new file mode 100644 index 0000000..a3fa3e1 --- /dev/null +++ b/examples/async/private/get_account_recent_trades.py @@ -0,0 +1,20 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + + data = await client.get_trades() + data2 = await client.get_trades(symbol='USDTTMN') + data3 = await client.get_trades(side='buy') + data4 = await client.get_trades(symbol='USDTTMN', side='buy') + + print(data) + print(data2) + print(data3) + print(data4) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_order_status.py b/examples/async/private/get_order_status.py new file mode 100644 index 0000000..9afb940 --- /dev/null +++ b/examples/async/private/get_order_status.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_order_detail(order_id='ORDER_ID') + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_user_banking_accounts.py b/examples/async/private/get_user_banking_accounts.py new file mode 100644 index 0000000..973044b --- /dev/null +++ b/examples/async/private/get_user_banking_accounts.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_banking_accounts() + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_user_banking_cards.py b/examples/async/private/get_user_banking_cards.py new file mode 100644 index 0000000..e7ee709 --- /dev/null +++ b/examples/async/private/get_user_banking_cards.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_banking_cards() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/async/private/get_user_fee_data.py b/examples/async/private/get_user_fee_data.py new file mode 100644 index 0000000..7c89003 --- /dev/null +++ b/examples/async/private/get_user_fee_data.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_fee_levels() + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/private/get_user_profile_data.py b/examples/async/private/get_user_profile_data.py new file mode 100644 index 0000000..49dc9e3 --- /dev/null +++ b/examples/async/private/get_user_profile_data.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_profile() + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/public/get_currencies.py b/examples/async/public/get_currencies.py new file mode 100644 index 0000000..b1b6968 --- /dev/null +++ b/examples/async/public/get_currencies.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_currencies() + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/public/get_market_stats.py b/examples/async/public/get_market_stats.py new file mode 100644 index 0000000..8d5bda5 --- /dev/null +++ b/examples/async/public/get_market_stats.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_markets() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/async/public/get_ohlc_data.py b/examples/async/public/get_ohlc_data.py new file mode 100644 index 0000000..2497d3e --- /dev/null +++ b/examples/async/public/get_ohlc_data.py @@ -0,0 +1,20 @@ +import asyncio +from wallex.async_client import AsyncClient +import datetime + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + + data = await client.get_market_candles( + symbol='USDTTMN', + resolution='1', + _from=datetime.datetime(2022, 7, 1), + _to=datetime.datetime(2022, 7, 10) + ) + + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/public/get_orderbook.py b/examples/async/public/get_orderbook.py new file mode 100644 index 0000000..0f509b1 --- /dev/null +++ b/examples/async/public/get_orderbook.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_market_orders(symbol='USDTTMN') + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/public/get_recent_trades.py b/examples/async/public/get_recent_trades.py new file mode 100644 index 0000000..91ac414 --- /dev/null +++ b/examples/async/public/get_recent_trades.py @@ -0,0 +1,12 @@ +import asyncio +from wallex.async_client import AsyncClient + + +async def main(): + client = await AsyncClient.create_client(api_key='PUT YOUR API KEY HERE') + data = await client.get_market_trades(symbol='USDTTMN') + print(data) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/sync/private/cancel_order.py b/examples/sync/private/cancel_order.py new file mode 100644 index 0000000..68c12d6 --- /dev/null +++ b/examples/sync/private/cancel_order.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.cancel_order(order_id='ORDER_ID') + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/create_new_order.py b/examples/sync/private/create_new_order.py new file mode 100644 index 0000000..129cabd --- /dev/null +++ b/examples/sync/private/create_new_order.py @@ -0,0 +1,18 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.place_order( + symbol='USDTTMN', + side='buy', + order_type='limit', + quantity=11, + price=25000, + client_id='CLIENT_ID', + ) + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/get_wallex_markets.py b/examples/sync/private/get_account_balances.py similarity index 72% rename from examples/get_wallex_markets.py rename to examples/sync/private/get_account_balances.py index 07a7d71..1636eea 100644 --- a/examples/get_wallex_markets.py +++ b/examples/sync/private/get_account_balances.py @@ -3,8 +3,8 @@ def main(): client = Client(api_key='PUT YOUR API KEY HERE') - markets = client.get_markets() - print(markets) + data = client.get_balances() + print(data) if __name__ == '__main__': diff --git a/examples/sync/private/get_account_crypto_deposit_list.py b/examples/sync/private/get_account_crypto_deposit_list.py new file mode 100644 index 0000000..99ce79d --- /dev/null +++ b/examples/sync/private/get_account_crypto_deposit_list.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_crypto_deposit_list() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/get_account_crypto_withdrawal_list.py b/examples/sync/private/get_account_crypto_withdrawal_list.py new file mode 100644 index 0000000..002636b --- /dev/null +++ b/examples/sync/private/get_account_crypto_withdrawal_list.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_crypto_withdrawal_list() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/get_account_open_orders.py b/examples/sync/private/get_account_open_orders.py new file mode 100644 index 0000000..a7b1126 --- /dev/null +++ b/examples/sync/private/get_account_open_orders.py @@ -0,0 +1,13 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_open_orders() + data2 = client.get_open_orders(symbol='USDTTMN') + print(data) + print(data2) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/get_account_recent_trades.py b/examples/sync/private/get_account_recent_trades.py new file mode 100644 index 0000000..76e361d --- /dev/null +++ b/examples/sync/private/get_account_recent_trades.py @@ -0,0 +1,18 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_trades() + data2 = client.get_trades(symbol='USDTTMN') + data3 = client.get_trades(side='buy') + data4 = client.get_trades(symbol='USDTTMN', side='buy') + + print(data) + print(data2) + print(data3) + print(data4) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/get_order_status.py b/examples/sync/private/get_order_status.py new file mode 100644 index 0000000..9d08f0b --- /dev/null +++ b/examples/sync/private/get_order_status.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_order_detail(order_id='ORDER_ID') + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/get_user_banking_accounts.py b/examples/sync/private/get_user_banking_accounts.py new file mode 100644 index 0000000..911cedf --- /dev/null +++ b/examples/sync/private/get_user_banking_accounts.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_banking_accounts() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/get_user_banking_cards.py b/examples/sync/private/get_user_banking_cards.py new file mode 100644 index 0000000..1d29d12 --- /dev/null +++ b/examples/sync/private/get_user_banking_cards.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_banking_cards() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/get_user_fee_data.py b/examples/sync/private/get_user_fee_data.py new file mode 100644 index 0000000..e70fde8 --- /dev/null +++ b/examples/sync/private/get_user_fee_data.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_fee_levels() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/private/get_user_profile_data.py b/examples/sync/private/get_user_profile_data.py new file mode 100644 index 0000000..70b69ab --- /dev/null +++ b/examples/sync/private/get_user_profile_data.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_profile() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/public/get_currencies.py b/examples/sync/public/get_currencies.py new file mode 100644 index 0000000..593135b --- /dev/null +++ b/examples/sync/public/get_currencies.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_currencies() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/public/get_market_stats.py b/examples/sync/public/get_market_stats.py new file mode 100644 index 0000000..d29aa58 --- /dev/null +++ b/examples/sync/public/get_market_stats.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_markets() + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/public/get_ohlc_data.py b/examples/sync/public/get_ohlc_data.py new file mode 100644 index 0000000..a447b58 --- /dev/null +++ b/examples/sync/public/get_ohlc_data.py @@ -0,0 +1,17 @@ +from wallex.client import Client +import datetime + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_market_candles( + symbol='USDTTMN', + resolution='1', + _from=datetime.datetime(2022, 7, 1), + _to=datetime.datetime(2022, 7, 10) + ) + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/public/get_orderbook.py b/examples/sync/public/get_orderbook.py new file mode 100644 index 0000000..032c493 --- /dev/null +++ b/examples/sync/public/get_orderbook.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_market_orders(symbol='USDTTMN') + print(data) + + +if __name__ == '__main__': + main() diff --git a/examples/sync/public/get_recent_trades.py b/examples/sync/public/get_recent_trades.py new file mode 100644 index 0000000..1c38951 --- /dev/null +++ b/examples/sync/public/get_recent_trades.py @@ -0,0 +1,11 @@ +from wallex.client import Client + + +def main(): + client = Client(api_key='PUT YOUR API KEY HERE') + data = client.get_market_trades(symbol='USDTTMN') + print(data) + + +if __name__ == '__main__': + main() From 0fa9e502d66c894f525945c14dd9ca249de7bb58 Mon Sep 17 00:00:00 2001 From: amiwrpremium Date: Wed, 17 Aug 2022 17:41:48 +0430 Subject: [PATCH 7/8] abstraction --- setup.cfg | 2 +- setup.py | 2 +- src/wallex/__init__.py | 9 +++++ src/wallex/_base_client.py | 73 ++++++++++++++++++++++++++++++++++++++ src/wallex/async_client.py | 43 +++++++++++----------- src/wallex/client.py | 42 +++++++++++----------- src/wallex/request.py | 45 ++++++++++++++++------- 7 files changed, 161 insertions(+), 55 deletions(-) create mode 100644 src/wallex/_base_client.py diff --git a/setup.cfg b/setup.cfg index 9e9eea6..5f46be2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = wallex-python -version = 0.0.7 +version = 0.0.8 author = Pourya Moghadam author_email = p.moghadam@msn.com description = Wallex Exchange Unofficial API Python Client diff --git a/setup.py b/setup.py index 832c30d..f344cf6 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setuptools.setup( name="wallex-python", - version="0.0.7", + version="0.0.8", author="Pourya Moghadam", author_email="p.moghadam@msn.com", description="Wallex Exchange Unofficial API Python Client", diff --git a/src/wallex/__init__.py b/src/wallex/__init__.py index e69de29..adaa095 100644 --- a/src/wallex/__init__.py +++ b/src/wallex/__init__.py @@ -0,0 +1,9 @@ +from wallex.client import Client +from wallex.async_client import AsyncClient + + +__all__ = ['Client', 'AsyncClient'] + + +__version__ = '0.0.8' +__author__ = 'Pourya Moghadam' diff --git a/src/wallex/_base_client.py b/src/wallex/_base_client.py new file mode 100644 index 0000000..c44dc43 --- /dev/null +++ b/src/wallex/_base_client.py @@ -0,0 +1,73 @@ +from abc import ABC, abstractmethod + + +class _Base(ABC): + @abstractmethod + def get_markets(self): + raise NotImplementedError + + @abstractmethod + def get_currencies(self): + raise NotImplementedError + + @abstractmethod + def get_market_orders(self, symbol: str): + raise NotImplementedError + + @abstractmethod + def get_market_trades(self, symbol: str): + raise NotImplementedError + + @abstractmethod + def get_market_candles(self, symbol: str, resolution: str, _from, _to): + raise NotImplementedError + + @abstractmethod + def get_profile(self): + raise NotImplementedError + + @abstractmethod + def get_fee_levels(self): + raise NotImplementedError + + @abstractmethod + def get_banking_cards(self): + raise NotImplementedError + + @abstractmethod + def get_banking_accounts(self): + raise NotImplementedError + + @abstractmethod + def get_balances(self): + raise NotImplementedError + + @abstractmethod + def get_crypto_withdrawal_list(self): + raise NotImplementedError + + @abstractmethod + def get_crypto_deposit_list(self): + raise NotImplementedError + + @abstractmethod + def place_order( + self, symbol: str, order_type: str, side: str, quantity: float, price: float, client_id: str = None + ): + raise NotImplementedError + + @abstractmethod + def get_order_detail(self, order_id: str): + raise NotImplementedError + + @abstractmethod + def cancel_order(self, order_id: str): + raise NotImplementedError + + @abstractmethod + def get_open_orders(self, symbol: str = None): + raise NotImplementedError + + @abstractmethod + def get_trades(self, symbol: str = None, side: str = None): + raise NotImplementedError diff --git a/src/wallex/async_client.py b/src/wallex/async_client.py index feb9a6f..0705571 100644 --- a/src/wallex/async_client.py +++ b/src/wallex/async_client.py @@ -6,8 +6,10 @@ AccountBalancesResponseModel, PlaceOrderRequestModel, PlaceOrderResponseModel, LastTradesResponseModel from wallex.utils import create_list_by_symbol, create_list +from wallex._base_client import _Base -class AsyncClient: + +class AsyncClient(_Base): """ :param api_key: str = Wallex API key (required) :method host_is_online: bool = Returns True if Wallex API is online @@ -17,9 +19,8 @@ class AsyncClient: @validate_arguments def __init__(self, api_key: str, loop=None) -> None: - self.client_user = None self.loop = loop - self.consumer = AsyncRequestsApi( + self._consumer = AsyncRequestsApi( base_url='https://api.wallex.ir', headers={"X-API-Key": api_key}, loop=loop @@ -39,19 +40,19 @@ async def create_client(cls, api_key: str = None, loop=None): return self async def get_markets(self): - res = await self.consumer.get('/v1/markets') + res = await self._consumer.get('/v1/markets') json_res = await res.json() symbols = json_res['result']['symbols'] return create_list_by_symbol(symbols, MarketsResponseModel) async def get_currencies(self): - res = await self.consumer.get('/v1/currencies/stats') + res = await self._consumer.get('/v1/currencies/stats') json_res = await res.json() return create_list(json_res['result'], CurrenciesResponseModel) async def get_market_orders(self, symbol: str): params = ClientSymbolInput(symbol=symbol) - res = await self.consumer.get('/v1/depth', params=params.dict()) + res = await self._consumer.get('/v1/depth', params=params.dict()) json_res = await res.json() return { 'ask': create_list(json_res['result']['ask'], MarketOrderDetailModel), @@ -60,7 +61,7 @@ async def get_market_orders(self, symbol: str): async def get_market_trades(self, symbol: str): params = ClientSymbolInput(symbol=symbol) - res = await self.consumer.get('/v1/trades?', params=params.dict()) + res = await self._consumer.get('/v1/trades?', params=params.dict()) json_res = await res.json() return { 'latestTrades': create_list(json_res['result']['latestTrades'], MarketTradesModel) @@ -68,7 +69,7 @@ async def get_market_trades(self, symbol: str): async def get_market_candles(self, symbol: str, resolution: str, _from, _to): params = MarketCandlesRequestModel(symbol=symbol, resolution=resolution, start_time=_from, end_time=_to).dict() - res = await self.consumer.get('/v1/udf/history?', params={ + res = await self._consumer.get('/v1/udf/history?', params={ 'symbol': params['symbol'], 'resolution': params['resolution'], 'from': int(round(params['start_time'].timestamp())), @@ -79,30 +80,30 @@ async def get_market_candles(self, symbol: str, resolution: str, _from, _to): return checked_r.dict() async def get_profile(self): - res = await self.consumer.get('/v1/account/profile') + res = await self._consumer.get('/v1/account/profile') json_res = await res.json() return json_res['result'] async def get_fee_levels(self): - res = await self.consumer.get('/v1/account/fee') + res = await self._consumer.get('/v1/account/fee') json_res = await res.json() return create_list_by_symbol(json_res['result'], AccountFeeLevelsResponseModel) # TODO: get 401 auth error when calling this method async def get_banking_cards(self): - res = await self.consumer.get('/v1/account/card-numbers') + res = await self._consumer.get('/v1/account/card-numbers') json_res = await res.json() return json_res['result'] # TODO: get 500 server error when calling this method async def get_banking_accounts(self): - res = await self.consumer.get('/v1/account/ibans') + res = await self._consumer.get('/v1/account/ibans') json_res = await res.json() return json_res['result'] async def get_balances(self): temp_balances = {} - res = await self.consumer.get('/v1/account/balances') + res = await self._consumer.get('/v1/account/balances') json_res = await res.json() balances = create_list_by_symbol(json_res['result']['balances'], AccountBalancesResponseModel) for balance in balances: @@ -112,12 +113,12 @@ async def get_balances(self): } async def get_crypto_withdrawal_list(self): - res = await self.consumer.get('/v1/account/crypto-withdrawal') + res = await self._consumer.get('/v1/account/crypto-withdrawal') json_res = await res.json() return json_res['result'] async def get_crypto_deposit_list(self): - res = await self.consumer.get('/v1/account/crypto-deposit') + res = await self._consumer.get('/v1/account/crypto-deposit') json_res = await res.json() return json_res['result'] @@ -128,31 +129,31 @@ async def place_order( symbol=symbol, order_type=order_type, side=side, quantity=quantity, price=price, client_id=client_id ).dict(exclude_none=True) - res = await self.consumer.post('/v1/account/orders', json=params) + res = await self._consumer.post('/v1/account/orders', json=params) json_res = await res.json() return PlaceOrderResponseModel(**json_res['result']).dict() @validate_arguments async def get_order_detail(self, order_id: str): - res = await self.consumer.get('/v1/account/orders/' + order_id) + res = await self._consumer.get('/v1/account/orders/' + order_id) json_res = await res.json() return PlaceOrderResponseModel(**json_res['result']).dict() @validate_arguments async def cancel_order(self, order_id: str): - res = await self.consumer.delete('/v1/account/orders/' + order_id) + res = await self._consumer.delete('/v1/account/orders/' + order_id) json_res = await res.json() return json_res['result'] @validate_arguments async def get_open_orders(self, symbol: str = None): - res = await self.consumer.get('/v1/account/openOrders', params={'symbol': symbol}) + res = await self._consumer.get('/v1/account/openOrders', params={'symbol': symbol}) json_res = await res.json() return json_res['result'] @validate_arguments async def get_trades(self, symbol: str = None, side: str = None): - res = await self.consumer.get('/v1/account/trades', params={'symbol': symbol, 'side': side}) + res = await self._consumer.get('/v1/account/trades', params={'symbol': symbol, 'side': side}) json_res = await res.json() last_trades = create_list(json_res['result']['AccountLatestTrades'], LastTradesResponseModel) return { @@ -160,4 +161,4 @@ async def get_trades(self, symbol: str = None, side: str = None): } async def close(self): - return await self.consumer.close() + return await self._consumer.close() diff --git a/src/wallex/client.py b/src/wallex/client.py index 9491a5b..7ebcd00 100644 --- a/src/wallex/client.py +++ b/src/wallex/client.py @@ -5,8 +5,10 @@ AccountBalancesResponseModel, PlaceOrderRequestModel, PlaceOrderResponseModel, LastTradesResponseModel from wallex.utils import create_list_by_symbol, create_list +from wallex._base_client import _Base -class Client: + +class Client(_Base): """ :param api_key: str = Wallex API key (required) :method host_is_online: bool = Returns True if Wallex API is online @@ -16,11 +18,11 @@ class Client: @validate_arguments def __init__(self, api_key: str) -> None: - self.client_user = None - self.consumer = RequestsApi( + self._consumer = RequestsApi( base_url='https://api.wallex.ir', headers={"X-API-Key": api_key} ) + try: self.client_user = self.get_profile() print('client user:', self.client_user['first_name'] + ' ' + self.client_user['last_name']) @@ -28,17 +30,17 @@ def __init__(self, api_key: str) -> None: raise Exception('can not access wallex api online server', e) def get_markets(self): - res = self.consumer.get('/v1/markets') + res = self._consumer.get('/v1/markets') symbols = res.json()['result']['symbols'] return create_list_by_symbol(symbols, MarketsResponseModel) def get_currencies(self): - res = self.consumer.get('/v1/currencies/stats') + res = self._consumer.get('/v1/currencies/stats') return create_list(res.json()['result'], CurrenciesResponseModel) def get_market_orders(self, symbol: str): params = ClientSymbolInput(symbol=symbol) - res = self.consumer.get('/v1/depth?', params=params.dict()) + res = self._consumer.get('/v1/depth?', params=params.dict()) return { 'ask': create_list(res.json()['result']['ask'], MarketOrderDetailModel), 'bid': create_list(res.json()['result']['bid'], MarketOrderDetailModel) @@ -46,14 +48,14 @@ def get_market_orders(self, symbol: str): def get_market_trades(self, symbol: str): params = ClientSymbolInput(symbol=symbol) - res = self.consumer.get('/v1/trades?', params=params.dict()) + res = self._consumer.get('/v1/trades?', params=params.dict()) return { 'latestTrades': create_list(res.json()['result']['latestTrades'], MarketTradesModel) } def get_market_candles(self, symbol: str, resolution: str, _from, _to): params = MarketCandlesRequestModel(symbol=symbol, resolution=resolution, start_time=_from, end_time=_to).dict() - res = self.consumer.get('/v1/udf/history?', params={ + res = self._consumer.get('/v1/udf/history?', params={ 'symbol': params['symbol'], 'resolution': params['resolution'], 'from': int(round(params['start_time'].timestamp())), @@ -63,26 +65,26 @@ def get_market_candles(self, symbol: str, resolution: str, _from, _to): return checked_r.dict() def get_profile(self): - res = self.consumer.get('/v1/account/profile') + res = self._consumer.get('/v1/account/profile') return res.json()['result'] def get_fee_levels(self): - res = self.consumer.get('/v1/account/fee') + res = self._consumer.get('/v1/account/fee') return create_list_by_symbol(res.json()['result'], AccountFeeLevelsResponseModel) # TODO: get 401 auth error when calling this method def get_banking_cards(self): - res = self.consumer.get('/v1/account/card-numbers') + res = self._consumer.get('/v1/account/card-numbers') return res.json()['result'] # TODO: get 500 server error when calling this method def get_banking_accounts(self): - res = self.consumer.get('/v1/account/ibans') + res = self._consumer.get('/v1/account/ibans') return res.json()['result'] def get_balances(self): temp_balances = {} - res = self.consumer.get('/v1/account/balances') + res = self._consumer.get('/v1/account/balances') balances = create_list_by_symbol(res.json()['result']['balances'], AccountBalancesResponseModel) for balance in balances: temp_balances.update(balance) @@ -91,11 +93,11 @@ def get_balances(self): } def get_crypto_withdrawal_list(self): - res = self.consumer.get('/v1/account/crypto-withdrawal') + res = self._consumer.get('/v1/account/crypto-withdrawal') return res.json()['result'] def get_crypto_deposit_list(self): - res = self.consumer.get('/v1/account/crypto-deposit') + res = self._consumer.get('/v1/account/crypto-deposit') return res.json()['result'] def place_order(self, @@ -104,27 +106,27 @@ def place_order(self, params = PlaceOrderRequestModel(symbol=symbol, order_type=order_type, side=side, quantity=quantity, price=price, client_id=client_id ).dict(exclude_none=True) - res = self.consumer.post('/v1/account/orders', json=params) + res = self._consumer.post('/v1/account/orders', json=params) return PlaceOrderResponseModel(**res.json()['result']).dict() @validate_arguments def get_order_detail(self, order_id: str): - res = self.consumer.get('/v1/account/orders/' + order_id) + res = self._consumer.get('/v1/account/orders/' + order_id) return PlaceOrderResponseModel(**res.json()['result']).dict() @validate_arguments def cancel_order(self, order_id: str): - res = self.consumer.delete('/v1/account/orders/' + order_id) + res = self._consumer.delete('/v1/account/orders/' + order_id) return res.json()['result'] @validate_arguments def get_open_orders(self, symbol: str = None): - res = self.consumer.get('/v1/account/openOrders', params={'symbol': symbol}) + res = self._consumer.get('/v1/account/openOrders', params={'symbol': symbol}) return res.json()['result'] @validate_arguments def get_trades(self, symbol: str = None, side: str = None): - res = self.consumer.get('/v1/account/trades', params={'symbol': symbol, 'side': side}) + res = self._consumer.get('/v1/account/trades', params={'symbol': symbol, 'side': side}) last_trades = create_list(res.json()['result']['AccountLatestTrades'], LastTradesResponseModel) return { 'AccountLatestTrades': last_trades diff --git a/src/wallex/request.py b/src/wallex/request.py index f9d49ea..e4104e6 100644 --- a/src/wallex/request.py +++ b/src/wallex/request.py @@ -1,3 +1,5 @@ +from abc import ABC, abstractmethod + import requests import aiohttp @@ -5,7 +7,33 @@ from wallex.utils import async_error_handler -class RequestsApi: +class _Base(ABC): + @abstractmethod + def get(self, url, **kwargs): + raise NotImplementedError + + @abstractmethod + def post(self, url, **kwargs): + raise NotImplementedError + + @abstractmethod + def put(self, url, **kwargs): + raise NotImplementedError + + @abstractmethod + def patch(self, url, **kwargs): + raise NotImplementedError + + @abstractmethod + def delete(self, url, **kwargs): + raise NotImplementedError + + @abstractmethod + def close(self): + raise NotImplementedError + + +class RequestsApi(_Base): def __init__(self, base_url, **kwargs): self.base_url = base_url self.session = requests.Session() @@ -44,8 +72,11 @@ def __deep_merge(source, destination): destination[key] = value return destination + def close(self): + self.session.close() + -class AsyncRequestsApi: +class AsyncRequestsApi(_Base): def __init__(self, base_url, **kwargs): self.base_url = base_url self.session = aiohttp.ClientSession(**kwargs) @@ -70,15 +101,5 @@ async def patch(self, url, **kwargs): async def delete(self, url, **kwargs): return await self.session.delete(self.base_url + url, **kwargs) - @staticmethod - def __deep_merge(source, destination): - for key, value in source.items(): - if isinstance(value, dict): - node = destination.setdefault(key, {}) - AsyncRequestsApi.__deep_merge(value, node) - else: - destination[key] = value - return destination - async def close(self): await self.session.close() From 5e30e4f52f5fd0f951d5f4ab8d266b5cf7572881 Mon Sep 17 00:00:00 2001 From: amiwrpremium Date: Wed, 17 Aug 2022 17:51:22 +0430 Subject: [PATCH 8/8] order helper --- setup.cfg | 2 +- setup.py | 2 +- src/wallex/__init__.py | 2 +- src/wallex/_base_client.py | 30 ++++++++++++++++++++++++++++++ src/wallex/async_client.py | 33 ++++++++++++++++++++++++++++++++- src/wallex/client.py | 33 ++++++++++++++++++++++++++++++++- src/wallex/schema.py | 2 +- 7 files changed, 98 insertions(+), 6 deletions(-) diff --git a/setup.cfg b/setup.cfg index 5f46be2..62b6647 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = wallex-python -version = 0.0.8 +version = 0.0.9 author = Pourya Moghadam author_email = p.moghadam@msn.com description = Wallex Exchange Unofficial API Python Client diff --git a/setup.py b/setup.py index f344cf6..46c16d4 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setuptools.setup( name="wallex-python", - version="0.0.8", + version="0.0.9", author="Pourya Moghadam", author_email="p.moghadam@msn.com", description="Wallex Exchange Unofficial API Python Client", diff --git a/src/wallex/__init__.py b/src/wallex/__init__.py index adaa095..aebbac3 100644 --- a/src/wallex/__init__.py +++ b/src/wallex/__init__.py @@ -5,5 +5,5 @@ __all__ = ['Client', 'AsyncClient'] -__version__ = '0.0.8' +__version__ = '0.0.9' __author__ = 'Pourya Moghadam' diff --git a/src/wallex/_base_client.py b/src/wallex/_base_client.py index c44dc43..bf56866 100644 --- a/src/wallex/_base_client.py +++ b/src/wallex/_base_client.py @@ -2,6 +2,12 @@ class _Base(ABC): + ORDER_TYPE_LIMIT = 'LIMIT' + ORDER_TYPE_MARKET = 'MARKET' + + ORDER_SIDE_BUY = 'BUY' + ORDER_SIDE_SELL = 'SELL' + @abstractmethod def get_markets(self): raise NotImplementedError @@ -71,3 +77,27 @@ def get_open_orders(self, symbol: str = None): @abstractmethod def get_trades(self, symbol: str = None, side: str = None): raise NotImplementedError + + @abstractmethod + def order_market(self, symbol: str, side: str, quantity: float, client_id: str = None): + raise NotImplementedError + + @abstractmethod + def order_limit(self, symbol: str, side: str, quantity: float, price: float, client_id: str = None): + raise NotImplementedError + + @abstractmethod + def order_market_buy(self, symbol: str, quantity: float, client_id: str = None): + raise NotImplementedError + + @abstractmethod + def order_market_sell(self, symbol: str, quantity: float, client_id: str = None): + raise NotImplementedError + + @abstractmethod + def order_limit_buy(self, symbol: str, quantity: float, price: float, client_id: str = None): + raise NotImplementedError + + @abstractmethod + def order_limit_sell(self, symbol: str, quantity: float, price: float, client_id: str = None): + raise NotImplementedError diff --git a/src/wallex/async_client.py b/src/wallex/async_client.py index 0705571..ee29e4f 100644 --- a/src/wallex/async_client.py +++ b/src/wallex/async_client.py @@ -123,7 +123,7 @@ async def get_crypto_deposit_list(self): return json_res['result'] async def place_order( - self, symbol: str, order_type: str, side: str, quantity: float, price: float, client_id: str = None + self, symbol: str, order_type: str, side: str, quantity: float, price: float = None, client_id: str = None ): params = PlaceOrderRequestModel( symbol=symbol, order_type=order_type, side=side, @@ -133,6 +133,37 @@ async def place_order( json_res = await res.json() return PlaceOrderResponseModel(**json_res['result']).dict() + async def order_market(self, symbol: str, side: str, quantity: float, client_id: str = None): + return await self.place_order( + symbol=symbol, order_type=self.ORDER_TYPE_MARKET, side=side, quantity=quantity, client_id=client_id + ) + + async def order_limit(self, symbol: str, side: str, quantity: float, price: float, client_id: str = None): + return await self.place_order( + symbol=symbol, order_type=self.ORDER_TYPE_LIMIT, side=side, + quantity=quantity, price=price, client_id=client_id + ) + + async def order_market_buy(self, symbol: str, quantity: float, client_id: str = None): + return await self.order_market( + symbol=symbol, side=self.ORDER_SIDE_BUY, quantity=quantity, client_id=client_id + ) + + async def order_market_sell(self, symbol: str, quantity: float, client_id: str = None): + return await self.order_market( + symbol=symbol, side=self.ORDER_SIDE_SELL, quantity=quantity, client_id=client_id + ) + + async def order_limit_buy(self, symbol: str, quantity: float, price: float, client_id: str = None): + return await self.order_limit( + symbol=symbol, side=self.ORDER_SIDE_BUY, quantity=quantity, price=price, client_id=client_id + ) + + async def order_limit_sell(self, symbol: str, quantity: float, price: float, client_id: str = None): + return await self.order_limit( + symbol=symbol, side=self.ORDER_SIDE_SELL, quantity=quantity, price=price, client_id=client_id + ) + @validate_arguments async def get_order_detail(self, order_id: str): res = await self._consumer.get('/v1/account/orders/' + order_id) diff --git a/src/wallex/client.py b/src/wallex/client.py index 7ebcd00..ab08c00 100644 --- a/src/wallex/client.py +++ b/src/wallex/client.py @@ -102,13 +102,44 @@ def get_crypto_deposit_list(self): def place_order(self, symbol: str, order_type: str, side: str, - quantity: float, price: float, client_id: str = None): + quantity: float, price: float = None, client_id: str = None): params = PlaceOrderRequestModel(symbol=symbol, order_type=order_type, side=side, quantity=quantity, price=price, client_id=client_id ).dict(exclude_none=True) res = self._consumer.post('/v1/account/orders', json=params) return PlaceOrderResponseModel(**res.json()['result']).dict() + def order_market(self, symbol: str, side: str, quantity: float, client_id: str = None): + return self.place_order( + symbol=symbol, order_type=self.ORDER_TYPE_MARKET, side=side, quantity=quantity, client_id=client_id + ) + + def order_limit(self, symbol: str, side: str, quantity: float, price: float, client_id: str = None): + return self.place_order( + symbol=symbol, order_type=self.ORDER_TYPE_LIMIT, side=side, + quantity=quantity, price=price, client_id=client_id + ) + + def order_market_buy(self, symbol: str, quantity: float, client_id: str = None): + return self.order_market( + symbol=symbol, side=self.ORDER_SIDE_BUY, quantity=quantity, client_id=client_id + ) + + def order_market_sell(self, symbol: str, quantity: float, client_id: str = None): + return self.order_market( + symbol=symbol, side=self.ORDER_SIDE_SELL, quantity=quantity, client_id=client_id + ) + + def order_limit_buy(self, symbol: str, quantity: float, price: float, client_id: str = None): + return self.order_limit( + symbol=symbol, side=self.ORDER_SIDE_BUY, quantity=quantity, price=price, client_id=client_id + ) + + def order_limit_sell(self, symbol: str, quantity: float, price: float, client_id: str = None): + return self.order_limit( + symbol=symbol, side=self.ORDER_SIDE_SELL, quantity=quantity, price=price, client_id=client_id + ) + @validate_arguments def get_order_detail(self, order_id: str): res = self._consumer.get('/v1/account/orders/' + order_id) diff --git a/src/wallex/schema.py b/src/wallex/schema.py index 783d972..5e67b4e 100644 --- a/src/wallex/schema.py +++ b/src/wallex/schema.py @@ -149,7 +149,7 @@ class PlaceOrderRequestModel(BaseModel): type: str = 'LIMIT' or 'MARKET' side: str = 'BUY' or 'SELL' quantity: float - price: float + price: float = None client_id: str = None class Config: