pax-api 2.0.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.
- pax_api-2.0.0/LICENSE +21 -0
- pax_api-2.0.0/PKG-INFO +209 -0
- pax_api-2.0.0/README.md +169 -0
- pax_api-2.0.0/pyproject.toml +72 -0
- pax_api-2.0.0/setup.cfg +4 -0
- pax_api-2.0.0/src/pax_api/__init__.py +60 -0
- pax_api-2.0.0/src/pax_api/auth.py +66 -0
- pax_api-2.0.0/src/pax_api/client.py +349 -0
- pax_api-2.0.0/src/pax_api/errors.py +146 -0
- pax_api-2.0.0/src/pax_api/py.typed +0 -0
- pax_api-2.0.0/src/pax_api/retry.py +97 -0
- pax_api-2.0.0/src/pax_api/ws_client.py +195 -0
- pax_api-2.0.0/src/pax_api.egg-info/PKG-INFO +209 -0
- pax_api-2.0.0/src/pax_api.egg-info/SOURCES.txt +19 -0
- pax_api-2.0.0/src/pax_api.egg-info/dependency_links.txt +1 -0
- pax_api-2.0.0/src/pax_api.egg-info/requires.txt +11 -0
- pax_api-2.0.0/src/pax_api.egg-info/top_level.txt +1 -0
- pax_api-2.0.0/tests/test_auth.py +48 -0
- pax_api-2.0.0/tests/test_client.py +110 -0
- pax_api-2.0.0/tests/test_errors.py +72 -0
- pax_api-2.0.0/tests/test_retry.py +89 -0
pax_api-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PredictAsiaX
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pax_api-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pax-api
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Official Python SDK for the PredictAsiaX Trader Track API — Web3-native prediction markets
|
|
5
|
+
Author-email: PredictAsiaX <support@predictasiax.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://predictasiax.com/developer
|
|
8
|
+
Project-URL: Documentation, https://docs.predictasiax.com
|
|
9
|
+
Project-URL: Repository, https://github.com/predictasiax/pax-python-sdk
|
|
10
|
+
Project-URL: Issues, https://github.com/predictasiax/pax-python-sdk/issues
|
|
11
|
+
Project-URL: Changelog, https://docs.predictasiax.com/changelog
|
|
12
|
+
Keywords: predictasiax,pax,prediction-market,trading-api,web3,hmac,polymarket-compatible
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Requires-Python: >=3.8
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: requests>=2.28
|
|
30
|
+
Requires-Dist: websocket-client>=1.5
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov>=4; extra == "dev"
|
|
34
|
+
Requires-Dist: responses>=0.23; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.1; extra == "dev"
|
|
36
|
+
Requires-Dist: mypy>=1; extra == "dev"
|
|
37
|
+
Requires-Dist: build>=1; extra == "dev"
|
|
38
|
+
Requires-Dist: twine>=4; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# pax-api — Official Python SDK for PredictAsiaX
|
|
42
|
+
|
|
43
|
+
Web3-native prediction market REST + WebSocket API client. Polymarket-compatible HMAC signing pattern.
|
|
44
|
+
|
|
45
|
+
**Version 1.0.0** · MIT license · Python 3.8+
|
|
46
|
+
|
|
47
|
+
- **Docs**: https://docs.predictasiax.com
|
|
48
|
+
- **Developer landing**: https://predictasiax.com/developer
|
|
49
|
+
- **Get API key**: https://predictasiax.com/settings/api-keys
|
|
50
|
+
- **Support**: support@predictasiax.com
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Direct install from PredictAsiaX-hosted wheel
|
|
56
|
+
pip install https://docs.predictasiax.com/downloads/sdk/python/pax_api-1.0.0-py3-none-any.whl
|
|
57
|
+
|
|
58
|
+
# Or download tarball + install locally
|
|
59
|
+
curl -O https://docs.predictasiax.com/downloads/sdk/python/pax_api-1.0.0.tar.gz
|
|
60
|
+
pip install pax_api-1.0.0.tar.gz
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
(PyPI publish coming soon — install methods above work today.)
|
|
64
|
+
|
|
65
|
+
## Quickstart (sandbox — no real money)
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from pax_api import PaxClient
|
|
69
|
+
|
|
70
|
+
with PaxClient(api_key="sk_test_YOUR_KEY", env="sandbox") as pax:
|
|
71
|
+
faucet = pax.faucet() # get 10k test USDT
|
|
72
|
+
print(faucet["data"]["balance_free"]) # → "10000.000000"
|
|
73
|
+
|
|
74
|
+
templates = pax.list_templates()
|
|
75
|
+
markets = pax.list_markets(category="crypto", limit=10)
|
|
76
|
+
|
|
77
|
+
market = pax.create_market(
|
|
78
|
+
template_id="crypto_price_binary_60s",
|
|
79
|
+
params={"asset": "BTC"},
|
|
80
|
+
)
|
|
81
|
+
print(market["data"]["market"]["market_id"]) # → "m_..."
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## HMAC-signed requests (production)
|
|
85
|
+
|
|
86
|
+
Machine-to-machine trading bots should use HMAC signing (Polymarket-compatible 5-header pattern).
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from pax_api import PaxClient
|
|
90
|
+
|
|
91
|
+
pax = PaxClient(
|
|
92
|
+
api_key="sk_live_YOUR_KEY",
|
|
93
|
+
secret="<64-hex secret>",
|
|
94
|
+
passphrase="<passphrase>",
|
|
95
|
+
env="production",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
pax.place_order(
|
|
99
|
+
market_id="m_...",
|
|
100
|
+
outcome_id="yes",
|
|
101
|
+
side="buy",
|
|
102
|
+
order_type="limit",
|
|
103
|
+
size="100",
|
|
104
|
+
price="0.55",
|
|
105
|
+
client_order_id="unique-per-intent-id", # retry-safe within 24h
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## WebSocket streams
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from pax_api import PaxWSClient
|
|
113
|
+
|
|
114
|
+
ws = PaxWSClient(
|
|
115
|
+
api_key="sk_test_...",
|
|
116
|
+
env="sandbox",
|
|
117
|
+
subscribe_on_connect=["fast_tick", "trade_executed", "account"],
|
|
118
|
+
)
|
|
119
|
+
ws.on("fast_tick", lambda e: print("tick:", e))
|
|
120
|
+
ws.on("trade_executed", lambda e: print("trade:", e))
|
|
121
|
+
ws.on("account", lambda e: print("balance:", e.get("balance_free")))
|
|
122
|
+
ws.run_forever() # blocks; Ctrl+C to exit
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Auto-reconnect + exponential backoff built-in. All 4 client methods supported:
|
|
126
|
+
`subscribe`, `unsubscribe`, `auth`, `set_locale`.
|
|
127
|
+
|
|
128
|
+
## Error handling
|
|
129
|
+
|
|
130
|
+
Every response error becomes a typed exception. Catch the specific type
|
|
131
|
+
you want to handle:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from pax_api import (
|
|
135
|
+
PaxClient,
|
|
136
|
+
PaxRateLimitError,
|
|
137
|
+
PaxReadOnlyModeError,
|
|
138
|
+
PaxValidationError,
|
|
139
|
+
PaxWrongEnvKeyError,
|
|
140
|
+
PaxError, # base class — catch-all
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
pax.place_order(...)
|
|
145
|
+
except PaxRateLimitError as e:
|
|
146
|
+
time.sleep(e.retry_after or 5)
|
|
147
|
+
# then retry
|
|
148
|
+
except PaxValidationError as e:
|
|
149
|
+
print(f"Bad request: {e.details}") # {'field': 'size', ...}
|
|
150
|
+
except PaxReadOnlyModeError:
|
|
151
|
+
print("Trading paused by ops")
|
|
152
|
+
except PaxWrongEnvKeyError:
|
|
153
|
+
print("Wrong environment key")
|
|
154
|
+
except PaxError as e:
|
|
155
|
+
print(f"[{e.code}] {e.message} (request_id={e.request_id})")
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Automatic retry
|
|
159
|
+
|
|
160
|
+
Built-in exponential backoff on `429`, `500`, `502`, `504` responses. `Retry-After`
|
|
161
|
+
header respected on rate limits. Non-idempotent creates are safe when you send
|
|
162
|
+
`client_order_id`.
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
pax = PaxClient(api_key="sk_test_...", env="sandbox", max_retries=5)
|
|
166
|
+
# max_retries=0 disables retries entirely
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Environments
|
|
170
|
+
|
|
171
|
+
| Env | Base URL | Keys |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| `production` | `https://api.predictasiax.com/v1` | `sk_live_*` |
|
|
174
|
+
| `sandbox` | `https://api.predictasiax.com/v1` | `sk_test_*` |
|
|
175
|
+
|
|
176
|
+
`sk_test_*` on production returns `401 WRONG_ENV_KEY`. Same the other way. See
|
|
177
|
+
[docs auth guide](https://docs.predictasiax.com/auth#env-separation).
|
|
178
|
+
|
|
179
|
+
## Custom base URL
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
pax = PaxClient(api_key="...", base_url="https://your-mirror/api")
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Development
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Get source (tarball)
|
|
189
|
+
curl -O https://docs.predictasiax.com/downloads/sdk/python/pax_api-1.0.0.tar.gz
|
|
190
|
+
tar -xzf pax_api-1.0.0.tar.gz && cd pax_api-1.0.0
|
|
191
|
+
pip install -e ".[dev]"
|
|
192
|
+
pytest # run all tests
|
|
193
|
+
ruff check src tests # lint
|
|
194
|
+
mypy src # type-check
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Links
|
|
198
|
+
|
|
199
|
+
- [OpenAPI spec](https://docs.predictasiax.com/openapi)
|
|
200
|
+
- [AsyncAPI (WebSocket) spec](https://docs.predictasiax.com/asyncapi)
|
|
201
|
+
- [Auth guide](https://docs.predictasiax.com/auth)
|
|
202
|
+
- [Error codes](https://docs.predictasiax.com/errors)
|
|
203
|
+
- [Rate limits](https://docs.predictasiax.com/rate-limits)
|
|
204
|
+
- [FAQ](https://docs.predictasiax.com/faq)
|
|
205
|
+
- [API Terms](https://docs.predictasiax.com/api-terms)
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT — see [LICENSE](LICENSE).
|
pax_api-2.0.0/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# pax-api — Official Python SDK for PredictAsiaX
|
|
2
|
+
|
|
3
|
+
Web3-native prediction market REST + WebSocket API client. Polymarket-compatible HMAC signing pattern.
|
|
4
|
+
|
|
5
|
+
**Version 1.0.0** · MIT license · Python 3.8+
|
|
6
|
+
|
|
7
|
+
- **Docs**: https://docs.predictasiax.com
|
|
8
|
+
- **Developer landing**: https://predictasiax.com/developer
|
|
9
|
+
- **Get API key**: https://predictasiax.com/settings/api-keys
|
|
10
|
+
- **Support**: support@predictasiax.com
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Direct install from PredictAsiaX-hosted wheel
|
|
16
|
+
pip install https://docs.predictasiax.com/downloads/sdk/python/pax_api-1.0.0-py3-none-any.whl
|
|
17
|
+
|
|
18
|
+
# Or download tarball + install locally
|
|
19
|
+
curl -O https://docs.predictasiax.com/downloads/sdk/python/pax_api-1.0.0.tar.gz
|
|
20
|
+
pip install pax_api-1.0.0.tar.gz
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
(PyPI publish coming soon — install methods above work today.)
|
|
24
|
+
|
|
25
|
+
## Quickstart (sandbox — no real money)
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from pax_api import PaxClient
|
|
29
|
+
|
|
30
|
+
with PaxClient(api_key="sk_test_YOUR_KEY", env="sandbox") as pax:
|
|
31
|
+
faucet = pax.faucet() # get 10k test USDT
|
|
32
|
+
print(faucet["data"]["balance_free"]) # → "10000.000000"
|
|
33
|
+
|
|
34
|
+
templates = pax.list_templates()
|
|
35
|
+
markets = pax.list_markets(category="crypto", limit=10)
|
|
36
|
+
|
|
37
|
+
market = pax.create_market(
|
|
38
|
+
template_id="crypto_price_binary_60s",
|
|
39
|
+
params={"asset": "BTC"},
|
|
40
|
+
)
|
|
41
|
+
print(market["data"]["market"]["market_id"]) # → "m_..."
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## HMAC-signed requests (production)
|
|
45
|
+
|
|
46
|
+
Machine-to-machine trading bots should use HMAC signing (Polymarket-compatible 5-header pattern).
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from pax_api import PaxClient
|
|
50
|
+
|
|
51
|
+
pax = PaxClient(
|
|
52
|
+
api_key="sk_live_YOUR_KEY",
|
|
53
|
+
secret="<64-hex secret>",
|
|
54
|
+
passphrase="<passphrase>",
|
|
55
|
+
env="production",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
pax.place_order(
|
|
59
|
+
market_id="m_...",
|
|
60
|
+
outcome_id="yes",
|
|
61
|
+
side="buy",
|
|
62
|
+
order_type="limit",
|
|
63
|
+
size="100",
|
|
64
|
+
price="0.55",
|
|
65
|
+
client_order_id="unique-per-intent-id", # retry-safe within 24h
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## WebSocket streams
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from pax_api import PaxWSClient
|
|
73
|
+
|
|
74
|
+
ws = PaxWSClient(
|
|
75
|
+
api_key="sk_test_...",
|
|
76
|
+
env="sandbox",
|
|
77
|
+
subscribe_on_connect=["fast_tick", "trade_executed", "account"],
|
|
78
|
+
)
|
|
79
|
+
ws.on("fast_tick", lambda e: print("tick:", e))
|
|
80
|
+
ws.on("trade_executed", lambda e: print("trade:", e))
|
|
81
|
+
ws.on("account", lambda e: print("balance:", e.get("balance_free")))
|
|
82
|
+
ws.run_forever() # blocks; Ctrl+C to exit
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Auto-reconnect + exponential backoff built-in. All 4 client methods supported:
|
|
86
|
+
`subscribe`, `unsubscribe`, `auth`, `set_locale`.
|
|
87
|
+
|
|
88
|
+
## Error handling
|
|
89
|
+
|
|
90
|
+
Every response error becomes a typed exception. Catch the specific type
|
|
91
|
+
you want to handle:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from pax_api import (
|
|
95
|
+
PaxClient,
|
|
96
|
+
PaxRateLimitError,
|
|
97
|
+
PaxReadOnlyModeError,
|
|
98
|
+
PaxValidationError,
|
|
99
|
+
PaxWrongEnvKeyError,
|
|
100
|
+
PaxError, # base class — catch-all
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
pax.place_order(...)
|
|
105
|
+
except PaxRateLimitError as e:
|
|
106
|
+
time.sleep(e.retry_after or 5)
|
|
107
|
+
# then retry
|
|
108
|
+
except PaxValidationError as e:
|
|
109
|
+
print(f"Bad request: {e.details}") # {'field': 'size', ...}
|
|
110
|
+
except PaxReadOnlyModeError:
|
|
111
|
+
print("Trading paused by ops")
|
|
112
|
+
except PaxWrongEnvKeyError:
|
|
113
|
+
print("Wrong environment key")
|
|
114
|
+
except PaxError as e:
|
|
115
|
+
print(f"[{e.code}] {e.message} (request_id={e.request_id})")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Automatic retry
|
|
119
|
+
|
|
120
|
+
Built-in exponential backoff on `429`, `500`, `502`, `504` responses. `Retry-After`
|
|
121
|
+
header respected on rate limits. Non-idempotent creates are safe when you send
|
|
122
|
+
`client_order_id`.
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
pax = PaxClient(api_key="sk_test_...", env="sandbox", max_retries=5)
|
|
126
|
+
# max_retries=0 disables retries entirely
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Environments
|
|
130
|
+
|
|
131
|
+
| Env | Base URL | Keys |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| `production` | `https://api.predictasiax.com/v1` | `sk_live_*` |
|
|
134
|
+
| `sandbox` | `https://api.predictasiax.com/v1` | `sk_test_*` |
|
|
135
|
+
|
|
136
|
+
`sk_test_*` on production returns `401 WRONG_ENV_KEY`. Same the other way. See
|
|
137
|
+
[docs auth guide](https://docs.predictasiax.com/auth#env-separation).
|
|
138
|
+
|
|
139
|
+
## Custom base URL
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
pax = PaxClient(api_key="...", base_url="https://your-mirror/api")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Development
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Get source (tarball)
|
|
149
|
+
curl -O https://docs.predictasiax.com/downloads/sdk/python/pax_api-1.0.0.tar.gz
|
|
150
|
+
tar -xzf pax_api-1.0.0.tar.gz && cd pax_api-1.0.0
|
|
151
|
+
pip install -e ".[dev]"
|
|
152
|
+
pytest # run all tests
|
|
153
|
+
ruff check src tests # lint
|
|
154
|
+
mypy src # type-check
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Links
|
|
158
|
+
|
|
159
|
+
- [OpenAPI spec](https://docs.predictasiax.com/openapi)
|
|
160
|
+
- [AsyncAPI (WebSocket) spec](https://docs.predictasiax.com/asyncapi)
|
|
161
|
+
- [Auth guide](https://docs.predictasiax.com/auth)
|
|
162
|
+
- [Error codes](https://docs.predictasiax.com/errors)
|
|
163
|
+
- [Rate limits](https://docs.predictasiax.com/rate-limits)
|
|
164
|
+
- [FAQ](https://docs.predictasiax.com/faq)
|
|
165
|
+
- [API Terms](https://docs.predictasiax.com/api-terms)
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pax-api"
|
|
7
|
+
version = "2.0.0"
|
|
8
|
+
description = "Official Python SDK for the PredictAsiaX Trader Track API — Web3-native prediction markets"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "PredictAsiaX", email = "support@predictasiax.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["predictasiax", "pax", "prediction-market", "trading-api", "web3", "hmac", "polymarket-compatible"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.8",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
29
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"requests>=2.28",
|
|
33
|
+
"websocket-client>=1.5",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=7",
|
|
39
|
+
"pytest-cov>=4",
|
|
40
|
+
"responses>=0.23",
|
|
41
|
+
"ruff>=0.1",
|
|
42
|
+
"mypy>=1",
|
|
43
|
+
"build>=1",
|
|
44
|
+
"twine>=4",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Homepage = "https://predictasiax.com/developer"
|
|
49
|
+
Documentation = "https://docs.predictasiax.com"
|
|
50
|
+
Repository = "https://github.com/predictasiax/pax-python-sdk"
|
|
51
|
+
Issues = "https://github.com/predictasiax/pax-python-sdk/issues"
|
|
52
|
+
Changelog = "https://docs.predictasiax.com/changelog"
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.packages.find]
|
|
55
|
+
where = ["src"]
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.package-data]
|
|
58
|
+
pax_api = ["py.typed"]
|
|
59
|
+
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
line-length = 120
|
|
62
|
+
target-version = "py38"
|
|
63
|
+
|
|
64
|
+
[tool.mypy]
|
|
65
|
+
python_version = "3.8"
|
|
66
|
+
strict = true
|
|
67
|
+
warn_return_any = true
|
|
68
|
+
|
|
69
|
+
[tool.pytest.ini_options]
|
|
70
|
+
minversion = "7.0"
|
|
71
|
+
addopts = "-ra -q --strict-markers"
|
|
72
|
+
testpaths = ["tests"]
|
pax_api-2.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""PredictAsiaX (PAX) Python SDK.
|
|
2
|
+
|
|
3
|
+
Web3-native prediction market REST + WebSocket API client.
|
|
4
|
+
Homepage: https://predictasiax.com/developer
|
|
5
|
+
Docs: https://docs.predictasiax.com
|
|
6
|
+
|
|
7
|
+
Quick start (anonymous sandbox mint in 30 sec):
|
|
8
|
+
>>> from pax_api import PaxClient
|
|
9
|
+
>>> boot = PaxClient(api_key="anonymous")
|
|
10
|
+
>>> key = boot.mint_sandbox_key(org_name="my-app")
|
|
11
|
+
>>> print(key["api_key"]) # sk_live_..., shown ONCE — save it
|
|
12
|
+
>>> client = PaxClient(api_key=key["api_key"])
|
|
13
|
+
>>> client.list_markets(category="crypto", limit=10)
|
|
14
|
+
|
|
15
|
+
For HMAC signing (production trading bots):
|
|
16
|
+
>>> client = PaxClient(
|
|
17
|
+
... api_key="sk_live_...",
|
|
18
|
+
... secret="<hex-secret>",
|
|
19
|
+
... passphrase="<passphrase>",
|
|
20
|
+
... )
|
|
21
|
+
>>> client.place_order(market_id="m_...", outcome_id="yes",
|
|
22
|
+
... side="buy", order_type="market", size="100")
|
|
23
|
+
|
|
24
|
+
Environment model: sandbox is a *tier* on the key (tier=self_serve, $10/$100
|
|
25
|
+
caps), not a separate host. Same prefix, same URL — promote to production by
|
|
26
|
+
upgrading the key's tier.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
__version__ = "2.0.0"
|
|
30
|
+
|
|
31
|
+
from pax_api.client import PaxClient # noqa: E402
|
|
32
|
+
from pax_api.ws_client import PaxWSClient # noqa: E402
|
|
33
|
+
from pax_api.errors import ( # noqa: E402
|
|
34
|
+
PaxError,
|
|
35
|
+
PaxAuthError,
|
|
36
|
+
PaxRateLimitError,
|
|
37
|
+
PaxValidationError,
|
|
38
|
+
PaxNotFoundError,
|
|
39
|
+
PaxConflictError,
|
|
40
|
+
PaxServerError,
|
|
41
|
+
PaxReadOnlyModeError,
|
|
42
|
+
PaxSandboxOnlyError,
|
|
43
|
+
PaxWrongEnvKeyError,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"PaxClient",
|
|
48
|
+
"PaxWSClient",
|
|
49
|
+
"PaxError",
|
|
50
|
+
"PaxAuthError",
|
|
51
|
+
"PaxRateLimitError",
|
|
52
|
+
"PaxValidationError",
|
|
53
|
+
"PaxNotFoundError",
|
|
54
|
+
"PaxConflictError",
|
|
55
|
+
"PaxServerError",
|
|
56
|
+
"PaxReadOnlyModeError",
|
|
57
|
+
"PaxSandboxOnlyError",
|
|
58
|
+
"PaxWrongEnvKeyError",
|
|
59
|
+
"__version__",
|
|
60
|
+
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""HMAC signing helpers — Polymarket-compatible 5-header pattern.
|
|
2
|
+
|
|
3
|
+
Signature construction:
|
|
4
|
+
message = timestamp_ms + method_upper + path + body
|
|
5
|
+
signature = base64(HMAC-SHA256(secret, message))
|
|
6
|
+
|
|
7
|
+
Headers sent:
|
|
8
|
+
POLY_ACCESS_KEY: <key_id>
|
|
9
|
+
POLY_TIMESTAMP: <ms epoch>
|
|
10
|
+
POLY_PASSPHRASE: <passphrase>
|
|
11
|
+
POLY_SIGNATURE: <base64 sig>
|
|
12
|
+
|
|
13
|
+
Server rejects with 401 INVALID_SIGNATURE if timestamp is more than
|
|
14
|
+
±30 seconds from server clock. Sync your machine via NTP.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import base64
|
|
20
|
+
import hashlib
|
|
21
|
+
import hmac
|
|
22
|
+
import time
|
|
23
|
+
from typing import Dict, Optional
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def sign_request(
|
|
27
|
+
method: str,
|
|
28
|
+
path: str,
|
|
29
|
+
body: str,
|
|
30
|
+
key_id: str,
|
|
31
|
+
secret: str,
|
|
32
|
+
passphrase: str,
|
|
33
|
+
timestamp_ms: Optional[int] = None,
|
|
34
|
+
) -> Dict[str, str]:
|
|
35
|
+
"""Build the 5 POLY_* headers for an HMAC-signed request.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
method: HTTP method (GET/POST/DELETE/etc.). Case-normalized to upper.
|
|
39
|
+
path: URL path INCLUDING leading slash and query string, e.g.
|
|
40
|
+
``/v1/markets?category=crypto``.
|
|
41
|
+
body: Raw request body as string (empty string for GET/DELETE
|
|
42
|
+
without body). Must be the exact bytes sent on the wire.
|
|
43
|
+
key_id: Your ``sk_live_*`` key ID.
|
|
44
|
+
secret: HMAC secret (hex string) obtained at key mint time.
|
|
45
|
+
passphrase: Passphrase obtained at key mint time.
|
|
46
|
+
timestamp_ms: Override timestamp for testing. Defaults to now.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Dict of 5 headers to merge into the request.
|
|
50
|
+
"""
|
|
51
|
+
ts = str(timestamp_ms if timestamp_ms is not None else int(time.time() * 1000))
|
|
52
|
+
method_u = method.upper()
|
|
53
|
+
message = ts + method_u + path + (body or "")
|
|
54
|
+
digest = hmac.new(secret.encode("utf-8"), message.encode("utf-8"), hashlib.sha256).digest()
|
|
55
|
+
signature = base64.b64encode(digest).decode("ascii")
|
|
56
|
+
return {
|
|
57
|
+
"POLY_ACCESS_KEY": key_id,
|
|
58
|
+
"POLY_TIMESTAMP": ts,
|
|
59
|
+
"POLY_PASSPHRASE": passphrase,
|
|
60
|
+
"POLY_SIGNATURE": signature,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def build_message(method: str, path: str, body: str, timestamp_ms: int) -> str:
|
|
65
|
+
"""Return the canonical signing message (exposed for debugging)."""
|
|
66
|
+
return f"{timestamp_ms}{method.upper()}{path}{body or ''}"
|