phemex-py 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. phemex_py-0.1.0/.claude/settings.json +18 -0
  2. phemex_py-0.1.0/.coverage +0 -0
  3. phemex_py-0.1.0/.env.example +3 -0
  4. phemex_py-0.1.0/.gitignore +17 -0
  5. phemex_py-0.1.0/.python-version +1 -0
  6. phemex_py-0.1.0/CHANGELOG.md +20 -0
  7. phemex_py-0.1.0/JUSTFILE +27 -0
  8. phemex_py-0.1.0/LICENSE.txt +14 -0
  9. phemex_py-0.1.0/PKG-INFO +135 -0
  10. phemex_py-0.1.0/README.md +109 -0
  11. phemex_py-0.1.0/pyproject.toml +57 -0
  12. phemex_py-0.1.0/src/phemex_py/__init__.py +10 -0
  13. phemex_py-0.1.0/src/phemex_py/client.py +196 -0
  14. phemex_py-0.1.0/src/phemex_py/core/__init__.py +0 -0
  15. phemex_py-0.1.0/src/phemex_py/core/datetime.py +70 -0
  16. phemex_py-0.1.0/src/phemex_py/core/fields.py +1808 -0
  17. phemex_py-0.1.0/src/phemex_py/core/models.py +351 -0
  18. phemex_py-0.1.0/src/phemex_py/core/products.py +11 -0
  19. phemex_py-0.1.0/src/phemex_py/core/requests.py +135 -0
  20. phemex_py-0.1.0/src/phemex_py/exceptions.py +31 -0
  21. phemex_py-0.1.0/src/phemex_py/products.json +65736 -0
  22. phemex_py-0.1.0/src/phemex_py/py.typed +0 -0
  23. phemex_py-0.1.0/src/phemex_py/usdm_rest/__init__.py +3 -0
  24. phemex_py-0.1.0/src/phemex_py/usdm_rest/endpoints.py +696 -0
  25. phemex_py-0.1.0/src/phemex_py/usdm_rest/models.py +1098 -0
  26. phemex_py-0.1.0/tests/__integration__/conftest.py +51 -0
  27. phemex_py-0.1.0/tests/__integration__/usdm/test_async.py +252 -0
  28. phemex_py-0.1.0/tests/__integration__/usdm/test_sync.py +249 -0
  29. phemex_py-0.1.0/tests/conftest.py +8 -0
  30. phemex_py-0.1.0/tests/core/test_datetime.py +63 -0
  31. phemex_py-0.1.0/tests/core/test_models.py +89 -0
  32. phemex_py-0.1.0/tests/core/test_requests.py +22 -0
  33. phemex_py-0.1.0/uv.lock +399 -0
@@ -0,0 +1,18 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(just:*)",
5
+ "Bash(pytest:*)",
6
+ "Bash(PYTHONPATH=src pytest:*)",
7
+ "Bash(python:*)",
8
+ "Bash(PYTHONPATH=src python -m pytest:*)",
9
+ "Bash(PYTHONPATH=src python:*)",
10
+ "Bash(find:*)",
11
+ "Bash(PYTHONPATH=src python3:*)",
12
+ "Bash(test:*)",
13
+ "Bash(source .venv/bin/activate)",
14
+ "Bash(PYTHONPATH=src .venv/bin/python -m pytest:*)",
15
+ "Bash(PYTHONPATH=src .venv/bin/python:*)"
16
+ ]
17
+ }
18
+ }
Binary file
@@ -0,0 +1,3 @@
1
+ PHEMEX_URL=https://testnet-api.phemex.com
2
+ PHEMEX_KEY=
3
+ PHEMEX_SECRET=
@@ -0,0 +1,17 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # IDE files
13
+ .idea/
14
+
15
+ # Environment variables
16
+ .env
17
+ *.env
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-02-22)
4
+
5
+ Initial release.
6
+
7
+ ### Features
8
+
9
+ - Sync and async clients for the Phemex API (`PhemexClient`, `AsyncPhemexClient`)
10
+ - HMAC-SHA256 request signing with configurable expiry
11
+ - USD-M Perpetual REST API coverage:
12
+ - Market data: product information, order book, klines, trades, tickers
13
+ - Orders: place, amend, cancel, bulk cancel, cancel all
14
+ - Positions: query, query with PnL, switch mode, set leverage, assign balance
15
+ - Account: risk units
16
+ - History: open/closed orders, closed positions, user trades, order history, trade history
17
+ - Funding: fee history, funding rates
18
+ - Fully typed request/response models via Pydantic v2
19
+ - Structured error handling with `PhemexError`
20
+ - PEP 561 typed package support (`py.typed`)
@@ -0,0 +1,27 @@
1
+ # Default recipe - list all available recipes
2
+ list:
3
+ @just --list
4
+
5
+ # Run all tests with coverage reporting
6
+ test:
7
+ PYTHONPATH=src pytest -v --cov
8
+
9
+ # Run unit tests (excluding integration tests) with verbose output and fail-fast
10
+ test-unit:
11
+ pytest -m "not integration" -v --ff
12
+
13
+ # Run integration tests with verbose output and fail-fast
14
+ test-integration:
15
+ pytest -m "integration" -v --ff
16
+
17
+ # Run all tests in debug mode, stopping after the first failure and showing the full traceback
18
+ test-debug:
19
+ pytest -x --ff -v -m "not integration" && pytest -x --ff -v -m "integration"
20
+
21
+ # Run only the tests that failed in the previous test run, with verbose output and fail-fast
22
+ test-failed:
23
+ pytest --lf -x -v
24
+
25
+ # Analyze the codebase using cloc, excluding certain directories
26
+ cloc:
27
+ @cloc . --vcs=git --exclude-dir=products,tests
@@ -0,0 +1,14 @@
1
+ Copyright 2026 Connor Stone
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
5
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ persons to whom the Software is furnished to do so, subject to the following conditions:
7
+
8
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ Software.
10
+
11
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: phemex-py
3
+ Version: 0.1.0
4
+ Summary: Typed, production-grade Python SDK for the Phemex crypto exchange API
5
+ Project-URL: Homepage, https://github.com/cstone/phemex-py
6
+ Project-URL: Repository, https://github.com/cstone/phemex-py
7
+ Project-URL: Issues, https://github.com/cstone/phemex-py/issues
8
+ Project-URL: Changelog, https://github.com/cstone/phemex-py/blob/main/CHANGELOG.md
9
+ Author: Connor Stone
10
+ License: MIT
11
+ License-File: LICENSE.txt
12
+ Keywords: api,crypto,exchange,futures,phemex,sdk,trading
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Office/Business :: Financial
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.12
23
+ Requires-Dist: httpx>=0.28.1
24
+ Requires-Dist: pydantic>=2.12.5
25
+ Description-Content-Type: text/markdown
26
+
27
+ # phemex-py
28
+
29
+ [![PyPI version](https://img.shields.io/pypi/v/phemex-py)](https://pypi.org/project/phemex-py/)
30
+ [![Python](https://img.shields.io/pypi/pyversions/phemex-py)](https://pypi.org/project/phemex-py/)
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+
33
+ Typed, production-grade Python SDK for the [Phemex](https://phemex.com) crypto exchange API.
34
+
35
+ - Sync and async clients (built on [httpx](https://www.python-httpx.org/))
36
+ - Fully typed request/response models (built on [Pydantic](https://docs.pydantic.dev/))
37
+ - USD-M perpetual futures: orders, positions, market data, funding rates, and more
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install phemex-py
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ### Authentication
48
+
49
+ You need a Phemex API key and secret. Create one from your [Phemex account settings](https://phemex.com/account/apiKeys).
50
+
51
+ Set them as environment variables or pass them directly:
52
+
53
+ ```bash
54
+ export PHEMEX_API_KEY="your-api-key"
55
+ export PHEMEX_API_SECRET="your-api-secret"
56
+ ```
57
+
58
+ ### Sync Client
59
+
60
+ ```python
61
+ from phemex_py import PhemexClient
62
+
63
+ with PhemexClient(
64
+ base_url="https://api.phemex.com",
65
+ api_key="your-api-key",
66
+ api_secret="your-api-secret",
67
+ ) as client:
68
+ # Get server time
69
+ server_time = client.server_time()
70
+
71
+ # Get product info
72
+ products = client.usdm_rest.product_information()
73
+
74
+ # Get ticker
75
+ ticker = client.usdm_rest.ticker(symbol="BTCUSDT")
76
+
77
+ # Get open orders
78
+ orders = client.usdm_rest.open_orders(symbol="BTCUSDT")
79
+
80
+ # Get account positions
81
+ positions = client.usdm_rest.positions()
82
+ ```
83
+
84
+ ### Async Client
85
+
86
+ ```python
87
+ import asyncio
88
+ from phemex_py import AsyncPhemexClient
89
+
90
+ async def main():
91
+ async with AsyncPhemexClient(
92
+ base_url="https://api.phemex.com",
93
+ api_key="your-api-key",
94
+ api_secret="your-api-secret",
95
+ ) as client:
96
+ ticker = await client.usdm_rest.ticker(symbol="BTCUSDT")
97
+ positions = await client.usdm_rest.positions()
98
+
99
+ asyncio.run(main())
100
+ ```
101
+
102
+ ### Testnet
103
+
104
+ Use the testnet base URL for paper trading:
105
+
106
+ ```python
107
+ client = PhemexClient(
108
+ base_url="https://testnet-api.phemex.com",
109
+ api_key="your-testnet-key",
110
+ api_secret="your-testnet-secret",
111
+ )
112
+ ```
113
+
114
+ ## API Coverage
115
+
116
+ ### USD-M Perpetual REST API
117
+
118
+ | Category | Endpoints |
119
+ |----------|-----------|
120
+ | Market Data | `product_information`, `order_book`, `klines`, `trades`, `ticker`, `tickers` |
121
+ | Orders | `place_order`, `amend_order`, `cancel_order`, `bulk_cancel`, `cancel_all` |
122
+ | Positions | `positions`, `positions_with_pnl`, `switch_position_mode`, `set_leverage`, `assign_position_balance` |
123
+ | Account | `risk_units` |
124
+ | History | `open_orders`, `closed_orders`, `closed_positions`, `user_trades`, `order_history`, `lookup_order`, `trade_history` |
125
+ | Funding | `funding_fee_history`, `funding_rates` |
126
+
127
+ ## Links
128
+
129
+ - [Phemex API Documentation](https://phemex-docs.github.io/)
130
+ - [GitHub Repository](https://github.com/cstone/phemex-py)
131
+ - [PyPI Package](https://pypi.org/project/phemex-py/)
132
+
133
+ ## License
134
+
135
+ [MIT](LICENSE.txt)
@@ -0,0 +1,109 @@
1
+ # phemex-py
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/phemex-py)](https://pypi.org/project/phemex-py/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/phemex-py)](https://pypi.org/project/phemex-py/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ Typed, production-grade Python SDK for the [Phemex](https://phemex.com) crypto exchange API.
8
+
9
+ - Sync and async clients (built on [httpx](https://www.python-httpx.org/))
10
+ - Fully typed request/response models (built on [Pydantic](https://docs.pydantic.dev/))
11
+ - USD-M perpetual futures: orders, positions, market data, funding rates, and more
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install phemex-py
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ### Authentication
22
+
23
+ You need a Phemex API key and secret. Create one from your [Phemex account settings](https://phemex.com/account/apiKeys).
24
+
25
+ Set them as environment variables or pass them directly:
26
+
27
+ ```bash
28
+ export PHEMEX_API_KEY="your-api-key"
29
+ export PHEMEX_API_SECRET="your-api-secret"
30
+ ```
31
+
32
+ ### Sync Client
33
+
34
+ ```python
35
+ from phemex_py import PhemexClient
36
+
37
+ with PhemexClient(
38
+ base_url="https://api.phemex.com",
39
+ api_key="your-api-key",
40
+ api_secret="your-api-secret",
41
+ ) as client:
42
+ # Get server time
43
+ server_time = client.server_time()
44
+
45
+ # Get product info
46
+ products = client.usdm_rest.product_information()
47
+
48
+ # Get ticker
49
+ ticker = client.usdm_rest.ticker(symbol="BTCUSDT")
50
+
51
+ # Get open orders
52
+ orders = client.usdm_rest.open_orders(symbol="BTCUSDT")
53
+
54
+ # Get account positions
55
+ positions = client.usdm_rest.positions()
56
+ ```
57
+
58
+ ### Async Client
59
+
60
+ ```python
61
+ import asyncio
62
+ from phemex_py import AsyncPhemexClient
63
+
64
+ async def main():
65
+ async with AsyncPhemexClient(
66
+ base_url="https://api.phemex.com",
67
+ api_key="your-api-key",
68
+ api_secret="your-api-secret",
69
+ ) as client:
70
+ ticker = await client.usdm_rest.ticker(symbol="BTCUSDT")
71
+ positions = await client.usdm_rest.positions()
72
+
73
+ asyncio.run(main())
74
+ ```
75
+
76
+ ### Testnet
77
+
78
+ Use the testnet base URL for paper trading:
79
+
80
+ ```python
81
+ client = PhemexClient(
82
+ base_url="https://testnet-api.phemex.com",
83
+ api_key="your-testnet-key",
84
+ api_secret="your-testnet-secret",
85
+ )
86
+ ```
87
+
88
+ ## API Coverage
89
+
90
+ ### USD-M Perpetual REST API
91
+
92
+ | Category | Endpoints |
93
+ |----------|-----------|
94
+ | Market Data | `product_information`, `order_book`, `klines`, `trades`, `ticker`, `tickers` |
95
+ | Orders | `place_order`, `amend_order`, `cancel_order`, `bulk_cancel`, `cancel_all` |
96
+ | Positions | `positions`, `positions_with_pnl`, `switch_position_mode`, `set_leverage`, `assign_position_balance` |
97
+ | Account | `risk_units` |
98
+ | History | `open_orders`, `closed_orders`, `closed_positions`, `user_trades`, `order_history`, `lookup_order`, `trade_history` |
99
+ | Funding | `funding_fee_history`, `funding_rates` |
100
+
101
+ ## Links
102
+
103
+ - [Phemex API Documentation](https://phemex-docs.github.io/)
104
+ - [GitHub Repository](https://github.com/cstone/phemex-py)
105
+ - [PyPI Package](https://pypi.org/project/phemex-py/)
106
+
107
+ ## License
108
+
109
+ [MIT](LICENSE.txt)
@@ -0,0 +1,57 @@
1
+ [project]
2
+ name = "phemex-py"
3
+ version = "0.1.0"
4
+ description = "Typed, production-grade Python SDK for the Phemex crypto exchange API"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ authors = [
8
+ { name = "Connor Stone" }
9
+ ]
10
+ requires-python = ">=3.12"
11
+ keywords = ["phemex", "crypto", "exchange", "api", "sdk", "trading", "futures"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Office/Business :: Financial",
20
+ "Topic :: Software Development :: Libraries :: Python Modules",
21
+ "Typing :: Typed",
22
+ ]
23
+ dependencies = [
24
+ "httpx>=0.28.1",
25
+ "pydantic>=2.12.5",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/cstone/phemex-py"
30
+ Repository = "https://github.com/cstone/phemex-py"
31
+ Issues = "https://github.com/cstone/phemex-py/issues"
32
+ Changelog = "https://github.com/cstone/phemex-py/blob/main/CHANGELOG.md"
33
+
34
+ [build-system]
35
+ requires = ["hatchling"]
36
+ build-backend = "hatchling.build"
37
+
38
+ [tool.hatch.build.targets.wheel]
39
+ packages = ["src/phemex_py"]
40
+
41
+ [tool.uv]
42
+ package = true
43
+
44
+ [tool.pytest.ini_options]
45
+ pythonpath = ["src"]
46
+ testpaths = ["tests"]
47
+ addopts = []
48
+ markers = ["integration: marks tests as hitting external APIs (run with -m integration)"]
49
+ asyncio_mode = "strict"
50
+
51
+ [dependency-groups]
52
+ dev = [
53
+ "pytest>=9.0.2",
54
+ "pytest-asyncio>=0.24.0",
55
+ "pytest-cov>=7.0.0",
56
+ "python-dotenv>=1.2.1",
57
+ ]
@@ -0,0 +1,10 @@
1
+ import logging
2
+
3
+ from .client import PhemexClient, AsyncPhemexClient
4
+ from .exceptions import PhemexError
5
+
6
+ logging.getLogger("phemex_py").addHandler(logging.NullHandler())
7
+ logging.getLogger("phemex_py").setLevel(logging.WARNING)
8
+
9
+ __version__ = "0.1.0"
10
+ __all__ = ["PhemexClient", "AsyncPhemexClient", "PhemexError"]
@@ -0,0 +1,196 @@
1
+ import hmac
2
+ import hashlib
3
+ import logging
4
+ import time
5
+
6
+ import httpx
7
+
8
+ from .core.requests import Request, Extractor
9
+ from .exceptions import PhemexError
10
+
11
+ from .usdm_rest import USDMRest, AsyncUSDMRest
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ _SENSITIVE_HEADERS = {"x-phemex-access-token", "x-phemex-request-signature"}
16
+ _EXPIRY = 60 # default expiry time in seconds for request signatures
17
+
18
+
19
+ class BasePhemexClient:
20
+ """
21
+ Shared state and request preparation for sync and async Phemex clients.
22
+ """
23
+
24
+ def __init__(self, base_url: str, api_key: str, api_secret: str, expiry: int = _EXPIRY):
25
+ self.base_url = base_url.rstrip("/")
26
+ self.api_key = api_key
27
+ self.api_secret = api_secret.encode()
28
+ self.expiry = expiry
29
+
30
+ def _prepare(self, req: Request) -> tuple[str, dict, bytes | None]:
31
+ """
32
+ Build the URL, signed headers, and encoded body for a request.
33
+
34
+ :return: (url, headers, content)
35
+ """
36
+ query = req.build_query_string()
37
+ body_json = req.build_body_json()
38
+
39
+ expires = int(time.time()) + self.expiry
40
+ parts = [req.path]
41
+ if query:
42
+ parts.append(query)
43
+ parts.append(str(expires))
44
+ if body_json:
45
+ parts.append(body_json)
46
+
47
+ payload = "".join(parts)
48
+ signature = hmac.new(
49
+ self.api_secret,
50
+ payload.encode("utf-8"),
51
+ hashlib.sha256,
52
+ ).hexdigest()
53
+
54
+ headers = {
55
+ "x-phemex-access-token": self.api_key,
56
+ "x-phemex-request-expiry": str(expires),
57
+ "x-phemex-request-signature": signature,
58
+ }
59
+
60
+ url = f"{self.base_url}{req.path}"
61
+ if query:
62
+ url = f"{url}?{query}"
63
+
64
+ if body_json:
65
+ headers["Content-Type"] = "application/json"
66
+
67
+ safe_headers = {k: v for k, v in headers.items() if k not in _SENSITIVE_HEADERS}
68
+ logger.debug("REQUEST")
69
+ logger.debug(f"Request: {req.method} {url}")
70
+ logger.debug(f"Headers: {safe_headers}")
71
+ logger.debug(f"Body: {body_json or None}")
72
+
73
+ content = body_json.encode("utf-8") if body_json else None
74
+ return url, headers, content
75
+
76
+ @staticmethod
77
+ def _handle_response(resp: httpx.Response, req: Request, url: str, body_json: str | None):
78
+ """
79
+ Raise PhemexError on HTTP errors and return parsed JSON on success.
80
+ """
81
+ logger.debug("RESPONSE")
82
+ logger.debug(f"Status Code: {resp.status_code}")
83
+ logger.debug(f"Response Text: {resp.text}")
84
+
85
+ try:
86
+ resp.raise_for_status()
87
+ except httpx.HTTPStatusError as e:
88
+ raise PhemexError(
89
+ message="Phemex API request failed",
90
+ cause=e,
91
+ context={
92
+ "request": {
93
+ "method": req.method,
94
+ "url": url,
95
+ "body": body_json or None,
96
+ },
97
+ "response": {
98
+ "status_code": resp.status_code,
99
+ "text": resp.text,
100
+ },
101
+ }
102
+ )
103
+
104
+ return resp.json()
105
+
106
+
107
+ class PhemexClient(BasePhemexClient):
108
+ """
109
+ Sync client for Phemex API (https://phemex-docs.github.io/). Built using httpx.Client.
110
+ """
111
+
112
+ def __init__(self, base_url: str, api_key: str, api_secret: str, expiry: int = 60):
113
+ super().__init__(base_url, api_key, api_secret, expiry)
114
+ self.session = httpx.Client()
115
+ self.usdm_rest = USDMRest(self)
116
+
117
+ def __enter__(self):
118
+ return self
119
+
120
+ def __exit__(self, *args):
121
+ self.close()
122
+
123
+ def close(self):
124
+ """Close the underlying HTTP session."""
125
+ self.session.close()
126
+
127
+ def request(self, req: Request):
128
+ """
129
+ Make an authenticated request to Phemex API.
130
+
131
+ :param req: Request object
132
+ :return: Parsed JSON response.
133
+ """
134
+ url, headers, content = self._prepare(req)
135
+ resp = self.session.request(method=req.method, url=url, headers=headers, content=content)
136
+ return self._handle_response(resp, req, url, req.build_body_json())
137
+
138
+ # ----------------------------------------
139
+ # Common endpoints shared across APIs
140
+ # ----------------------------------------
141
+
142
+ def server_time(self, ms: bool = True) -> int:
143
+ """
144
+ Fetch current Phemex server time (ms by default). For details, see:
145
+ https://phemex-docs.github.io/#query-server-time-2
146
+ """
147
+ req = Request.get("/public/time")
148
+ resp = self.request(req)
149
+ timestamp = Extractor(resp).key("data", "serverTime").extract()
150
+ return timestamp if ms else timestamp // 1000
151
+
152
+
153
+ class AsyncPhemexClient(BasePhemexClient):
154
+ """
155
+ Async client for Phemex API (https://phemex-docs.github.io/). Built using httpx.AsyncClient.
156
+ """
157
+
158
+ def __init__(self, base_url: str, api_key: str, api_secret: str, expiry: int = 60):
159
+ super().__init__(base_url, api_key, api_secret, expiry)
160
+ self.session = httpx.AsyncClient()
161
+ self.usdm_rest = AsyncUSDMRest(self)
162
+
163
+ async def __aenter__(self):
164
+ return self
165
+
166
+ async def __aexit__(self, *args):
167
+ await self.close()
168
+
169
+ async def close(self):
170
+ """Close the underlying async HTTP session."""
171
+ await self.session.aclose()
172
+
173
+ async def request(self, req: Request):
174
+ """
175
+ Make an authenticated request to Phemex API.
176
+
177
+ :param req: Request object
178
+ :return: Parsed JSON response.
179
+ """
180
+ url, headers, content = self._prepare(req)
181
+ resp = await self.session.request(method=req.method, url=url, headers=headers, content=content)
182
+ return self._handle_response(resp, req, url, req.build_body_json())
183
+
184
+ # ----------------------------------------
185
+ # Common endpoints shared across APIs
186
+ # ----------------------------------------
187
+
188
+ async def server_time(self, ms: bool = True) -> int:
189
+ """
190
+ Fetch current Phemex server time (ms by default). For details, see:
191
+ https://phemex-docs.github.io/#query-server-time-2
192
+ """
193
+ req = Request.get("/public/time")
194
+ resp = await self.request(req)
195
+ timestamp = Extractor(resp).key("data", "serverTime").extract()
196
+ return timestamp if ms else timestamp // 1000
File without changes