piaa-sdk 1.0.1__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.
piaa_sdk-1.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Merrr <wign@wign.dev>
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.
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: piaa-sdk
3
+ Version: 1.0.1
4
+ Summary: Official Python SDK for PIA Market Intelligence & Realtime Financial Platform
5
+ Home-page: https://pia.wign.dev/portal/docs
6
+ Author: Merrr
7
+ Author-email: Merrr <wign@wign.dev>
8
+ License: MIT
9
+ Project-URL: Homepage, https://pia.wign.dev/portal/docs
10
+ Project-URL: Repository, https://github.com/wignn/pia-sdk
11
+ Project-URL: Issues, https://github.com/wignn/pia-sdk/issues
12
+ Keywords: pia,atlsd,market-data,finance,crypto,trading,sdk,websocket
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: Intended Audience :: Developers
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 :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.8
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: httpx>=0.24.0
30
+ Provides-Extra: realtime
31
+ Requires-Dist: websockets>=11.0.0; extra == "realtime"
32
+ Provides-Extra: all
33
+ Requires-Dist: websockets>=11.0.0; extra == "all"
34
+ Dynamic: author
35
+ Dynamic: home-page
36
+ Dynamic: license-file
37
+ Dynamic: requires-python
38
+
39
+ # piaa-sdk (Official Python SDK)
40
+
41
+ Official, production-grade Python SDK for the **PIA Market Intelligence & Realtime Financial Platform**.
42
+
43
+ Designed for institutional quantitative trading bots, financial analytics, fintech backends, and data science workflows.
44
+
45
+ ---
46
+
47
+ ## Key Features
48
+
49
+ - ⚡ **Simple, Intuitive API**: Start fetching market data in under 3 lines of code with zero unnecessary ceremony.
50
+ - 🔁 **Enterprise Resiliency**: Automatic exponential backoff with full jitter on transient network errors (`5xx`, `408`, `429`) and respect for `Retry-After` headers.
51
+ - 📡 **Cross-Platform Realtime Streaming**: Resilient WebSocket client featuring **In-Band Message Authentication**, ping/pong keep-alives, auto-reconnect, and dynamic symbol subscriptions.
52
+ - 🛡️ **Typed Exception Hierarchy**: Actionable exceptions (`AuthenticationError`, `RateLimitError`, `TimeoutError`, `ValidationError`, `NetworkError`) with detailed quota telemetry attributes.
53
+ - 🔒 **Zero Sensitive Data Leaks**: Automatic regex redaction of `wi_live_...` API keys and Bearer tokens in error strings and logs.
54
+ - 🚀 **Dual Sync & Async Support**: Both synchronous (`PiaClient`) and modern asyncio (`AsyncPiaClient`) interfaces available.
55
+ - 🏷️ **Type Hinting**: Fully typed with PEP 561 `py.typed` marker for flawless IDE autocompletion and MyPy verification.
56
+
57
+ ---
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ # Core REST client
63
+ pip install piaa-sdk
64
+
65
+ # With WebSocket realtime streaming support
66
+ pip install "piaa-sdk[realtime]"
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Quickstart
72
+
73
+ ### 1. Synchronous REST API
74
+
75
+ ```python
76
+ from pia import PiaClient, RateLimitError, AuthenticationError
77
+
78
+ # Automatically picks up os.environ["PIA_API_KEY"] if omitted
79
+ client = PiaClient(api_key="wi_live_your_key")
80
+
81
+ try:
82
+ # 1. Fetch live multi-asset snapshot (105+ symbols)
83
+ prices = client.market.get_prices()
84
+ print(f"Total instruments tracked: {prices.total}")
85
+
86
+ for item in prices.items[:5]:
87
+ print(f"[{item.symbol}] ${item.price:.2f} (bid: {item.bid}, ask: {item.ask})")
88
+
89
+ # 2. Fetch historical candlestick bars
90
+ candles = client.market.get_candles("XAUUSD", timeframe="1h", limit=100)
91
+ print(f"Fetched {candles.count} candles for {candles.symbol}")
92
+
93
+ # 3. Check rate limit telemetry
94
+ quota = client.get_rate_limit_info()
95
+ print(f"Remaining daily requests: {quota.daily_remaining}/{quota.daily_limit}")
96
+
97
+ except AuthenticationError:
98
+ print("Invalid or expired API key.")
99
+ except RateLimitError as e:
100
+ print(f"Rate limited! Retry after {e.retry_after_seconds} seconds.")
101
+ except Exception as e:
102
+ print(f"Unexpected error: {e}")
103
+ finally:
104
+ client.close()
105
+ ```
106
+
107
+ ---
108
+
109
+ ### 2. Asynchronous REST API (`asyncio` / FastAPI)
110
+
111
+ ```python
112
+ import asyncio
113
+ from pia import AsyncPiaClient
114
+
115
+ async def main():
116
+ async with AsyncPiaClient(api_key="wi_live_...") as client:
117
+ prices = await client.market.get_prices()
118
+ print(f"Total instruments: {prices.total}")
119
+
120
+ asyncio.run(main())
121
+ ```
122
+
123
+ ---
124
+
125
+ ### 3. Realtime WebSocket Streaming (In-Band Message Auth)
126
+
127
+ Cross-platform streaming without URL query-token leaks.
128
+
129
+ #### Asynchronous Streaming (Async Generator):
130
+
131
+ ```python
132
+ import asyncio
133
+ from pia import AsyncPiaClient
134
+
135
+ async def stream_prices():
136
+ async with AsyncPiaClient(api_key="wi_live_...") as client:
137
+ print("Connecting to live ticker feed...")
138
+ async for tick in client.realtime.stream(["XAUUSD", "BTCUSDT"]):
139
+ print(f"[TICK] {tick.symbol} -> ${tick.price:.2f} (bid: {tick.bid}, ask: {tick.ask})")
140
+
141
+ asyncio.run(stream_prices())
142
+ ```
143
+
144
+ #### Synchronous / Callback-based (Background Thread):
145
+
146
+ ```python
147
+ from pia import PiaClient
148
+
149
+ client = PiaClient(api_key="wi_live_...")
150
+
151
+ # Register event callbacks
152
+ client.realtime.on("connect", lambda: print("WebSocket TCP connected."))
153
+ client.realtime.on("authenticated", lambda info: print("Authenticated successfully:", info))
154
+ client.realtime.on("tick", lambda tick: print(f"[TICK] {tick.symbol} -> {tick.price}"))
155
+ client.realtime.on("error", lambda err: print(f"Error: {err}"))
156
+
157
+ # Subscribe to target instruments
158
+ client.realtime.subscribe(["XAUUSD", "BTCUSDT"])
159
+
160
+ # Run in foreground (or call client.realtime.start() for non-blocking background thread)
161
+ client.realtime.run_forever()
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Configuration Reference
167
+
168
+ ```python
169
+ from pia import PiaClient
170
+
171
+ client = PiaClient(
172
+ # API key (defaults to os.environ["PIA_API_KEY"])
173
+ api_key="wi_live_...",
174
+
175
+ # Unified REST gateway (Default: "https://api-engine.wign.dev")
176
+ base_url="https://api-engine.wign.dev",
177
+
178
+ # Realtime WebSocket stream (Default: "wss://api-engine.wign.dev/api/v1/ws")
179
+ ws_url="wss://api-engine.wign.dev/api/v1/ws",
180
+
181
+ # Request timeout in seconds (Default: 15.0)
182
+ timeout=10.0,
183
+
184
+ # Maximum retry attempts on 5xx / 429 errors (Default: 3)
185
+ max_retries=3,
186
+
187
+ # Base retry delay for exponential backoff (Default: 0.5s)
188
+ retry_delay=0.5,
189
+
190
+ # Custom headers injected into all requests
191
+ headers={"X-Trader-Id": "bot-algo-alpha"},
192
+
193
+ # Enable debug logging (Default: False)
194
+ debug=False,
195
+ )
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Typed Exception Hierarchy
201
+
202
+ All exceptions thrown by the SDK inherit from `PiaError`:
203
+
204
+ | Exception Class | HTTP Code | Description | Key Attributes |
205
+ |---|---|---|---|
206
+ | `ConfigurationError` | N/A | Missing or invalid client options | `message` |
207
+ | `ValidationError` | N/A | Invalid input argument (e.g. empty symbol) | `param_name` |
208
+ | `AuthenticationError` | 401 | Invalid, missing, or revoked API key | `status_code`, `endpoint` |
209
+ | `PermissionError` | 403 | Missing required scope/tier | `required_scope` |
210
+ | `RateLimitError` | 429 | Minute rate limit or daily quota exhausted | `retry_after_seconds`, `daily_remaining`, `minute_remaining` |
211
+ | `TimeoutError` | 408 / N/A | Request exceeded configured timeout | `timeout_seconds` |
212
+ | `NetworkError` | N/A | Connection refused, DNS failure, drop | `cause` |
213
+ | `ParseError` | N/A | Malformed non-JSON server response | `raw_text` |
214
+ | `ApiError` | Other | Unexpected HTTP status code | `status_code`, `raw_response` |
215
+
216
+ ---
217
+
218
+ ## Running Unit Tests
219
+
220
+ ```bash
221
+ python3 -m unittest discover -s tests -p "*_test.py"
222
+ ```
@@ -0,0 +1,184 @@
1
+ # piaa-sdk (Official Python SDK)
2
+
3
+ Official, production-grade Python SDK for the **PIA Market Intelligence & Realtime Financial Platform**.
4
+
5
+ Designed for institutional quantitative trading bots, financial analytics, fintech backends, and data science workflows.
6
+
7
+ ---
8
+
9
+ ## Key Features
10
+
11
+ - ⚡ **Simple, Intuitive API**: Start fetching market data in under 3 lines of code with zero unnecessary ceremony.
12
+ - 🔁 **Enterprise Resiliency**: Automatic exponential backoff with full jitter on transient network errors (`5xx`, `408`, `429`) and respect for `Retry-After` headers.
13
+ - 📡 **Cross-Platform Realtime Streaming**: Resilient WebSocket client featuring **In-Band Message Authentication**, ping/pong keep-alives, auto-reconnect, and dynamic symbol subscriptions.
14
+ - 🛡️ **Typed Exception Hierarchy**: Actionable exceptions (`AuthenticationError`, `RateLimitError`, `TimeoutError`, `ValidationError`, `NetworkError`) with detailed quota telemetry attributes.
15
+ - 🔒 **Zero Sensitive Data Leaks**: Automatic regex redaction of `wi_live_...` API keys and Bearer tokens in error strings and logs.
16
+ - 🚀 **Dual Sync & Async Support**: Both synchronous (`PiaClient`) and modern asyncio (`AsyncPiaClient`) interfaces available.
17
+ - 🏷️ **Type Hinting**: Fully typed with PEP 561 `py.typed` marker for flawless IDE autocompletion and MyPy verification.
18
+
19
+ ---
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ # Core REST client
25
+ pip install piaa-sdk
26
+
27
+ # With WebSocket realtime streaming support
28
+ pip install "piaa-sdk[realtime]"
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Quickstart
34
+
35
+ ### 1. Synchronous REST API
36
+
37
+ ```python
38
+ from pia import PiaClient, RateLimitError, AuthenticationError
39
+
40
+ # Automatically picks up os.environ["PIA_API_KEY"] if omitted
41
+ client = PiaClient(api_key="wi_live_your_key")
42
+
43
+ try:
44
+ # 1. Fetch live multi-asset snapshot (105+ symbols)
45
+ prices = client.market.get_prices()
46
+ print(f"Total instruments tracked: {prices.total}")
47
+
48
+ for item in prices.items[:5]:
49
+ print(f"[{item.symbol}] ${item.price:.2f} (bid: {item.bid}, ask: {item.ask})")
50
+
51
+ # 2. Fetch historical candlestick bars
52
+ candles = client.market.get_candles("XAUUSD", timeframe="1h", limit=100)
53
+ print(f"Fetched {candles.count} candles for {candles.symbol}")
54
+
55
+ # 3. Check rate limit telemetry
56
+ quota = client.get_rate_limit_info()
57
+ print(f"Remaining daily requests: {quota.daily_remaining}/{quota.daily_limit}")
58
+
59
+ except AuthenticationError:
60
+ print("Invalid or expired API key.")
61
+ except RateLimitError as e:
62
+ print(f"Rate limited! Retry after {e.retry_after_seconds} seconds.")
63
+ except Exception as e:
64
+ print(f"Unexpected error: {e}")
65
+ finally:
66
+ client.close()
67
+ ```
68
+
69
+ ---
70
+
71
+ ### 2. Asynchronous REST API (`asyncio` / FastAPI)
72
+
73
+ ```python
74
+ import asyncio
75
+ from pia import AsyncPiaClient
76
+
77
+ async def main():
78
+ async with AsyncPiaClient(api_key="wi_live_...") as client:
79
+ prices = await client.market.get_prices()
80
+ print(f"Total instruments: {prices.total}")
81
+
82
+ asyncio.run(main())
83
+ ```
84
+
85
+ ---
86
+
87
+ ### 3. Realtime WebSocket Streaming (In-Band Message Auth)
88
+
89
+ Cross-platform streaming without URL query-token leaks.
90
+
91
+ #### Asynchronous Streaming (Async Generator):
92
+
93
+ ```python
94
+ import asyncio
95
+ from pia import AsyncPiaClient
96
+
97
+ async def stream_prices():
98
+ async with AsyncPiaClient(api_key="wi_live_...") as client:
99
+ print("Connecting to live ticker feed...")
100
+ async for tick in client.realtime.stream(["XAUUSD", "BTCUSDT"]):
101
+ print(f"[TICK] {tick.symbol} -> ${tick.price:.2f} (bid: {tick.bid}, ask: {tick.ask})")
102
+
103
+ asyncio.run(stream_prices())
104
+ ```
105
+
106
+ #### Synchronous / Callback-based (Background Thread):
107
+
108
+ ```python
109
+ from pia import PiaClient
110
+
111
+ client = PiaClient(api_key="wi_live_...")
112
+
113
+ # Register event callbacks
114
+ client.realtime.on("connect", lambda: print("WebSocket TCP connected."))
115
+ client.realtime.on("authenticated", lambda info: print("Authenticated successfully:", info))
116
+ client.realtime.on("tick", lambda tick: print(f"[TICK] {tick.symbol} -> {tick.price}"))
117
+ client.realtime.on("error", lambda err: print(f"Error: {err}"))
118
+
119
+ # Subscribe to target instruments
120
+ client.realtime.subscribe(["XAUUSD", "BTCUSDT"])
121
+
122
+ # Run in foreground (or call client.realtime.start() for non-blocking background thread)
123
+ client.realtime.run_forever()
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Configuration Reference
129
+
130
+ ```python
131
+ from pia import PiaClient
132
+
133
+ client = PiaClient(
134
+ # API key (defaults to os.environ["PIA_API_KEY"])
135
+ api_key="wi_live_...",
136
+
137
+ # Unified REST gateway (Default: "https://api-engine.wign.dev")
138
+ base_url="https://api-engine.wign.dev",
139
+
140
+ # Realtime WebSocket stream (Default: "wss://api-engine.wign.dev/api/v1/ws")
141
+ ws_url="wss://api-engine.wign.dev/api/v1/ws",
142
+
143
+ # Request timeout in seconds (Default: 15.0)
144
+ timeout=10.0,
145
+
146
+ # Maximum retry attempts on 5xx / 429 errors (Default: 3)
147
+ max_retries=3,
148
+
149
+ # Base retry delay for exponential backoff (Default: 0.5s)
150
+ retry_delay=0.5,
151
+
152
+ # Custom headers injected into all requests
153
+ headers={"X-Trader-Id": "bot-algo-alpha"},
154
+
155
+ # Enable debug logging (Default: False)
156
+ debug=False,
157
+ )
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Typed Exception Hierarchy
163
+
164
+ All exceptions thrown by the SDK inherit from `PiaError`:
165
+
166
+ | Exception Class | HTTP Code | Description | Key Attributes |
167
+ |---|---|---|---|
168
+ | `ConfigurationError` | N/A | Missing or invalid client options | `message` |
169
+ | `ValidationError` | N/A | Invalid input argument (e.g. empty symbol) | `param_name` |
170
+ | `AuthenticationError` | 401 | Invalid, missing, or revoked API key | `status_code`, `endpoint` |
171
+ | `PermissionError` | 403 | Missing required scope/tier | `required_scope` |
172
+ | `RateLimitError` | 429 | Minute rate limit or daily quota exhausted | `retry_after_seconds`, `daily_remaining`, `minute_remaining` |
173
+ | `TimeoutError` | 408 / N/A | Request exceeded configured timeout | `timeout_seconds` |
174
+ | `NetworkError` | N/A | Connection refused, DNS failure, drop | `cause` |
175
+ | `ParseError` | N/A | Malformed non-JSON server response | `raw_text` |
176
+ | `ApiError` | Other | Unexpected HTTP status code | `status_code`, `raw_response` |
177
+
178
+ ---
179
+
180
+ ## Running Unit Tests
181
+
182
+ ```bash
183
+ python3 -m unittest discover -s tests -p "*_test.py"
184
+ ```
@@ -0,0 +1,78 @@
1
+ """Official PIA SDK for Python.
2
+
3
+ Enterprise market intelligence and realtime financial streaming library.
4
+ """
5
+
6
+ from .client import AsyncPiaClient, PiaClient
7
+ from .config import (
8
+ DEFAULT_BASE_URL,
9
+ DEFAULT_MAX_RETRIES,
10
+ DEFAULT_TIMEOUT_SECONDS,
11
+ DEFAULT_WS_URL,
12
+ PiaConfig,
13
+ )
14
+ from .errors import (
15
+ ApiError,
16
+ AuthenticationError,
17
+ ConfigurationError,
18
+ NetworkError,
19
+ ParseError,
20
+ PermissionError,
21
+ PiaError,
22
+ RateLimitError,
23
+ TimeoutError,
24
+ ValidationError,
25
+ redact_sensitive,
26
+ )
27
+ from .realtime import AsyncRealtimeClient, RealtimeClient
28
+ from .types import (
29
+ Candle,
30
+ CandleResponse,
31
+ MarketPrice,
32
+ MarketPricesResponse,
33
+ NewsArticle,
34
+ NewsFeedResponse,
35
+ OrderBook,
36
+ OrderBookLevel,
37
+ RateLimitInfo,
38
+ SocialFeedResponse,
39
+ SocialPost,
40
+ WsTicketResponse,
41
+ )
42
+
43
+ __version__ = "1.0.1"
44
+
45
+ __all__ = [
46
+ "PiaClient",
47
+ "AsyncPiaClient",
48
+ "PiaConfig",
49
+ "PiaError",
50
+ "ConfigurationError",
51
+ "ValidationError",
52
+ "AuthenticationError",
53
+ "PermissionError",
54
+ "RateLimitError",
55
+ "TimeoutError",
56
+ "NetworkError",
57
+ "ParseError",
58
+ "ApiError",
59
+ "redact_sensitive",
60
+ "RealtimeClient",
61
+ "AsyncRealtimeClient",
62
+ "MarketPrice",
63
+ "MarketPricesResponse",
64
+ "Candle",
65
+ "CandleResponse",
66
+ "OrderBook",
67
+ "OrderBookLevel",
68
+ "SocialPost",
69
+ "SocialFeedResponse",
70
+ "NewsArticle",
71
+ "NewsFeedResponse",
72
+ "RateLimitInfo",
73
+ "WsTicketResponse",
74
+ "DEFAULT_BASE_URL",
75
+ "DEFAULT_WS_URL",
76
+ "DEFAULT_TIMEOUT_SECONDS",
77
+ "DEFAULT_MAX_RETRIES",
78
+ ]
@@ -0,0 +1,145 @@
1
+ """Official PIA SDK - Main Client Facades (PiaClient & AsyncPiaClient)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import Any, Dict, Optional
7
+
8
+ import httpx
9
+
10
+ from .config import PiaConfig
11
+ from .logger import setup_logger
12
+ from .realtime import AsyncRealtimeClient, RealtimeClient
13
+ from .resources.market import AsyncMarketResource, MarketResource
14
+ from .resources.news import AsyncNewsResource, NewsResource
15
+ from .resources.social import AsyncSocialResource, SocialResource
16
+ from .resources.ws import AsyncWsResource, WsResource
17
+ from .transport import AsyncTransport, SyncTransport
18
+ from .types import RateLimitInfo
19
+
20
+
21
+ class PiaClient:
22
+ """Official synchronous client for the PIA Financial & Market Intelligence Platform.
23
+
24
+ Example:
25
+ ```python
26
+ from pia import PiaClient
27
+
28
+ client = PiaClient(api_key="wi_live_...")
29
+ prices = client.market.get_prices()
30
+ for item in prices.items:
31
+ print(item.symbol, item.price)
32
+ ```
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ api_key: Optional[str] = None,
38
+ *,
39
+ base_url: Optional[str] = None,
40
+ ws_url: Optional[str] = None,
41
+ timeout: Optional[float] = None,
42
+ max_retries: Optional[int] = None,
43
+ retry_delay: Optional[float] = None,
44
+ headers: Optional[Dict[str, str]] = None,
45
+ debug: bool = False,
46
+ http_client: Optional[httpx.Client] = None,
47
+ logger: Optional[logging.Logger] = None,
48
+ ) -> None:
49
+ self.config = PiaConfig.resolve(
50
+ api_key=api_key,
51
+ base_url=base_url,
52
+ ws_url=ws_url,
53
+ timeout=timeout,
54
+ max_retries=max_retries,
55
+ retry_delay=retry_delay,
56
+ headers=headers,
57
+ debug=debug,
58
+ )
59
+ self.logger = logger or setup_logger(self.config.debug)
60
+ self._transport = SyncTransport(self.config, client=http_client, logger=self.logger)
61
+
62
+ self.market = MarketResource(self._transport)
63
+ self.social = SocialResource(self._transport)
64
+ self.news = NewsResource(self._transport)
65
+ self.ws = WsResource(self._transport)
66
+ self.realtime = RealtimeClient(self.config, logger=self.logger)
67
+
68
+ def get_rate_limit_info(self) -> RateLimitInfo:
69
+ """Returns the most recent rate limit and daily quota telemetry."""
70
+ return self._transport.get_rate_limit_info()
71
+
72
+ def close(self) -> None:
73
+ self._transport.close()
74
+ self.realtime.stop()
75
+
76
+ def __enter__(self) -> PiaClient:
77
+ return self
78
+
79
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
80
+ self.close()
81
+
82
+
83
+ class AsyncPiaClient:
84
+ """Official asynchronous client for the PIA Financial & Market Intelligence Platform.
85
+
86
+ Example:
87
+ ```python
88
+ import asyncio
89
+ from pia import AsyncPiaClient
90
+
91
+ async def main():
92
+ async with AsyncPiaClient(api_key="wi_live_...") as client:
93
+ prices = await client.market.get_prices()
94
+ print(f"Tracked assets: {prices.total}")
95
+
96
+ asyncio.run(main())
97
+ ```
98
+ """
99
+
100
+ def __init__(
101
+ self,
102
+ api_key: Optional[str] = None,
103
+ *,
104
+ base_url: Optional[str] = None,
105
+ ws_url: Optional[str] = None,
106
+ timeout: Optional[float] = None,
107
+ max_retries: Optional[int] = None,
108
+ retry_delay: Optional[float] = None,
109
+ headers: Optional[Dict[str, str]] = None,
110
+ debug: bool = False,
111
+ http_client: Optional[httpx.AsyncClient] = None,
112
+ logger: Optional[logging.Logger] = None,
113
+ ) -> None:
114
+ self.config = PiaConfig.resolve(
115
+ api_key=api_key,
116
+ base_url=base_url,
117
+ ws_url=ws_url,
118
+ timeout=timeout,
119
+ max_retries=max_retries,
120
+ retry_delay=retry_delay,
121
+ headers=headers,
122
+ debug=debug,
123
+ )
124
+ self.logger = logger or setup_logger(self.config.debug)
125
+ self._transport = AsyncTransport(self.config, client=http_client, logger=self.logger)
126
+
127
+ self.market = AsyncMarketResource(self._transport)
128
+ self.social = AsyncSocialResource(self._transport)
129
+ self.news = AsyncNewsResource(self._transport)
130
+ self.ws = AsyncWsResource(self._transport)
131
+ self.realtime = AsyncRealtimeClient(self.config, logger=self.logger)
132
+
133
+ def get_rate_limit_info(self) -> RateLimitInfo:
134
+ """Returns the most recent rate limit and daily quota telemetry."""
135
+ return self._transport.get_rate_limit_info()
136
+
137
+ async def aclose(self) -> None:
138
+ await self._transport.aclose()
139
+ await self.realtime.close()
140
+
141
+ async def __aenter__(self) -> AsyncPiaClient:
142
+ return self
143
+
144
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
145
+ await self.aclose()