polynode 0.11.0__tar.gz → 0.12.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.
Files changed (48) hide show
  1. {polynode-0.11.0 → polynode-0.12.1}/PKG-INFO +87 -3
  2. {polynode-0.11.0 → polynode-0.12.1}/README.md +85 -2
  3. polynode-0.12.1/core-contract-v1.json +1026 -0
  4. polynode-0.12.1/core-fixtures-v1.json +442 -0
  5. {polynode-0.11.0 → polynode-0.12.1}/polynode/__init__.py +40 -0
  6. polynode-0.12.1/polynode/_version.py +1 -0
  7. {polynode-0.11.0 → polynode-0.12.1}/polynode/client.py +50 -0
  8. {polynode-0.11.0 → polynode-0.12.1}/polynode/engine.py +89 -11
  9. {polynode-0.11.0 → polynode-0.12.1}/polynode/errors.py +24 -3
  10. {polynode-0.11.0 → polynode-0.12.1}/polynode/orderbook.py +62 -3
  11. polynode-0.12.1/polynode/orderbook_integrity.py +77 -0
  12. polynode-0.12.1/polynode/orderbook_state.py +334 -0
  13. polynode-0.12.1/polynode/perps.py +539 -0
  14. {polynode-0.11.0 → polynode-0.12.1}/polynode/subscription.py +161 -8
  15. {polynode-0.11.0 → polynode-0.12.1}/polynode/types/__init__.py +1 -0
  16. {polynode-0.11.0 → polynode-0.12.1}/polynode/types/events.py +14 -2
  17. {polynode-0.11.0 → polynode-0.12.1}/polynode/types/orderbook.py +47 -1
  18. polynode-0.12.1/polynode/types/perps.py +106 -0
  19. {polynode-0.11.0 → polynode-0.12.1}/polynode/types/ws.py +32 -0
  20. polynode-0.12.1/polynode/v3.py +499 -0
  21. polynode-0.12.1/polynode/v3_operations.py +149 -0
  22. {polynode-0.11.0 → polynode-0.12.1}/polynode/ws.py +223 -40
  23. {polynode-0.11.0 → polynode-0.12.1}/pyproject.toml +6 -1
  24. polynode-0.11.0/polynode/_version.py +0 -1
  25. polynode-0.11.0/polynode/orderbook_state.py +0 -83
  26. {polynode-0.11.0 → polynode-0.12.1}/.gitignore +0 -0
  27. {polynode-0.11.0 → polynode-0.12.1}/polynode/cache/__init__.py +0 -0
  28. {polynode-0.11.0 → polynode-0.12.1}/polynode/redemption_watcher.py +0 -0
  29. {polynode-0.11.0 → polynode-0.12.1}/polynode/short_form.py +0 -0
  30. {polynode-0.11.0 → polynode-0.12.1}/polynode/testing.py +0 -0
  31. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/V2_ORDER_FLOW.md +0 -0
  32. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/__init__.py +0 -0
  33. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/clob_api.py +0 -0
  34. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/constants.py +0 -0
  35. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/cosigner.py +0 -0
  36. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/eip712.py +0 -0
  37. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/escrow.py +0 -0
  38. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/onboarding.py +0 -0
  39. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/position_management.py +0 -0
  40. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/privy.py +0 -0
  41. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/relayer.py +0 -0
  42. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/signer.py +0 -0
  43. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/sqlite_backend.py +0 -0
  44. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/trader.py +0 -0
  45. {polynode-0.11.0 → polynode-0.12.1}/polynode/trading/types.py +0 -0
  46. {polynode-0.11.0 → polynode-0.12.1}/polynode/types/enums.py +0 -0
  47. {polynode-0.11.0 → polynode-0.12.1}/polynode/types/rest.py +0 -0
  48. {polynode-0.11.0 → polynode-0.12.1}/polynode/types/short_form.py +0 -0
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polynode
3
- Version: 0.11.0
3
+ Version: 0.12.1
4
4
  Summary: Python SDK for the PolyNode real-time prediction market data platform
5
5
  Project-URL: Homepage, https://polynode.dev
6
6
  Project-URL: Documentation, https://docs.polynode.dev
7
+ Project-URL: Repository, https://github.com/Polynode-Dev/sdk-python
7
8
  Author-email: PolyNode <josh@quantish.live>
8
9
  License: MIT
9
10
  Keywords: polymarket,polynode,prediction-markets,trading,websocket
@@ -35,6 +36,8 @@ Description-Content-Type: text/markdown
35
36
 
36
37
  Python SDK for the [PolyNode](https://polynode.dev) real-time prediction market data platform.
37
38
 
39
+ **Current in v0.12.1:** Python provides the same core capabilities as the TypeScript and Rust SDKs: complete V3 API access, the V3 perps WebSocket, reconnect-aware settlement delivery, and PN1 orderbook integrity. Unknown additive events remain available as raw payloads, decimal values remain precision-safe, and any local queue eviction is reported.
40
+
38
41
  **New in v0.11.0:** Current-production parity. Trading now defaults to CLOB V2 on `clob.polymarket.com`, uses PolyNode's public builder attribution unless overridden, omits removed V1 wire fields, and supports V2 GTD expiration. Managed 5-minute, 15-minute, and 4-hour streams select the required 30/60-second Chainlink TWAP lookbacks on a dedicated connection and reconnect/resubscribe at every market rotation. WebSocket models, presets, and filters now cover current redemption, position-conversion, dome/fill, and PM2 combo events. REST position queries now include redeemable/condition filters, multi-wallet batches, and market-holder views; connection and status observability match the current public API.
39
42
 
40
43
  **New in v0.10.8:** POLY_1271 V2 order signatures now normalize the ERC-7739 `TypedDataSign` recovery byte to Ethereum `v=27/28` for on-chain ERC-1271 validation.
@@ -49,7 +52,7 @@ pip install polynode
49
52
 
50
53
  For trading support:
51
54
  ```bash
52
- pip install polynode[trading]
55
+ pip install 'polynode[trading]'
53
56
  ```
54
57
 
55
58
  ## Quick Start
@@ -116,6 +119,34 @@ async def main():
116
119
  asyncio.run(main())
117
120
  ```
118
121
 
122
+ ### Complete V3 API
123
+
124
+ V3 includes wallets, combos, rewards, credits, identities, markets, builders, profiles, perps, crypto, sports, backtesting, and other current product families. `execute()` gives you access to all 120 current V3 operations through one consistent Python interface.
125
+
126
+ ```python
127
+ import asyncio
128
+ from polynode import AsyncPolyNode
129
+
130
+ async def read_v3(address: str):
131
+ async with AsyncPolyNode(api_key="pn_live_...") as pn:
132
+ print(len(pn.v3.operations)) # 120
133
+
134
+ combo_activity = await pn.v3.execute(
135
+ "GET /v3/combos/activity",
136
+ query={"limit": 25},
137
+ )
138
+ wallet_rewards = await pn.v3.execute(
139
+ "GET /v3/wallets/{address}/rewards",
140
+ path_params={"address": address},
141
+ query={"limit": 100},
142
+ )
143
+ return combo_activity, wallet_rewards
144
+
145
+ asyncio.run(read_v3("0xabc..."))
146
+ ```
147
+
148
+ The SDK encodes path parameters for you. Read requests that are safe to repeat retry transient failures and honor `Retry-After`; requests that change data are never retried automatically. JSON decimals decode as `Decimal`, and `ApiError` exposes the status, request ID, retry details, and a request URL with credentials removed.
149
+
119
150
  Current presets include `dome`, `fills`, `combos`, `redemptions`, and `deposits`. Current filters include `since()`, `combo_condition_ids()`, `leg_position_ids()`, `event_ids()`, `module_ids()`, `action()`, and `direction()`.
120
151
 
121
152
  `dome` and `fills` change settlement delivery into a flat, per-fill wire
@@ -123,6 +154,22 @@ format. Use one of those presets on a dedicated `PolyNodeWS` connection when
123
154
  also consuming non-fill events; the server deduplicates delivery per
124
155
  connection and cannot deliver both wire formats for the same settlement.
125
156
 
157
+ ### Reconnect and delivery behavior
158
+
159
+ Why: a reconnect can overlap the last event or exceed the server's retained history. The SDK resubscribes with the latest accepted timestamp, deduplicates the overlap, preserves unknown additive events, and reports replay state. Replay is best effort, not an unbounded gapless guarantee.
160
+
161
+ ```python
162
+ pn.ws.on_replay(
163
+ lambda notice: print(
164
+ notice.phase, notice.since, notice.guaranteed, notice.warning
165
+ )
166
+ )
167
+
168
+ sub.on_overflow(
169
+ lambda overflow: print("local iterator queue evicted", overflow.dropped_events)
170
+ )
171
+ ```
172
+
126
173
  ### Chainlink TWAP and short-form markets
127
174
 
128
175
  The TWAP values are lookback windows, not update cadence: 5-minute markets use 30 seconds; 15-minute and 4-hour markets use 60 seconds.
@@ -146,6 +193,40 @@ async def stream_short_markets(pn):
146
193
 
147
194
  A Chainlink selection is scoped to its WebSocket connection, so combine feeds and windows into one Chainlink subscription per connection. The resolved subscription exposes the server acknowledgement through `price_source`, `twap_windows`, and `warnings`. `short_form()` handles rotation safely with its own socket. At each market boundary it closes that socket, discovers the new slugs, reconnects, and subscribes to the exact settlement and TWAP filters again.
148
195
 
196
+ ### V3 perps WebSocket
197
+
198
+ The V3 perps WebSocket streams tickers, best bid/offer, full books, trades, statistics, and klines. The managed client confirms which channels were accepted, reconnects and resubscribes, and emits an explicit gap notice because the perps stream cannot replay missed messages.
199
+
200
+ ```python
201
+ import asyncio
202
+ from polynode import AsyncPolyNode, PerpsEvent, perps_channels
203
+
204
+ async def stream_perps():
205
+ async with AsyncPolyNode(api_key="pn_live_...") as pn:
206
+ perps = pn.perps
207
+ hello = await perps.connect()
208
+ ack = await perps.subscribe([
209
+ perps_channels.tickers,
210
+ perps_channels.book("BTC-USD"),
211
+ perps_channels.trades("BTC-USD"),
212
+ ])
213
+ print(hello.max_subscriptions, ack.channels, ack.rejected)
214
+
215
+ try:
216
+ async for message in perps:
217
+ if isinstance(message, PerpsEvent) and message.channel == "perps_tickers":
218
+ # Prices, quantities, funding, and equity values stay exact strings.
219
+ print(message.data["mark_price"], message.data["funding_rate"])
220
+ elif message.type in ("lag_warning", "reconnect"):
221
+ print(message)
222
+ finally:
223
+ await perps.disconnect()
224
+
225
+ asyncio.run(stream_perps())
226
+ ```
227
+
228
+ Use `perps_channels.bbo()`, `.book()`, `.trades()`, and `.klines(instrument, "1m" | "1h")` for scoped channels. Each `perps_book` event is a complete replacement snapshot; `perps.book("BTC-USD")` returns the latest complete book. Authentication (`4401`) and connection-cap (`4429`) closes are terminal. Queue eviction is observable through `on_overflow()`.
229
+
149
230
  ### WebSocket Streaming
150
231
 
151
232
  ```python
@@ -169,15 +250,18 @@ import asyncio
169
250
  from polynode import OrderbookEngine
170
251
 
171
252
  async def main():
172
- engine = OrderbookEngine(api_key="pn_live_...")
253
+ engine = OrderbookEngine(api_key="pn_live_...", integrity=True)
173
254
  await engine.subscribe(["token_id_1", "token_id_2"])
174
255
 
175
256
  engine.on("ready", lambda: print(f"Tracking {engine.size} books"))
176
257
  engine.on("update", lambda u: print(f"{u.asset_id}: {engine.midpoint(u.asset_id)}"))
258
+ engine.on("integrity_error", lambda error: print(error.token, error.code))
177
259
 
178
260
  asyncio.run(main())
179
261
  ```
180
262
 
263
+ With PN1 integrity enabled, the engine validates sequence continuity and deterministic checksums, fails stale or invalid books closed by default, and requests a fresh anchor before making them readable again. Integrity mode requires explicit markets; wildcard subscriptions are unavailable. Set `allow_stale_reads=True` only when your application explicitly prefers availability over verified state.
264
+
181
265
  ### Trading
182
266
 
183
267
  ```python
@@ -2,6 +2,8 @@
2
2
 
3
3
  Python SDK for the [PolyNode](https://polynode.dev) real-time prediction market data platform.
4
4
 
5
+ **Current in v0.12.1:** Python provides the same core capabilities as the TypeScript and Rust SDKs: complete V3 API access, the V3 perps WebSocket, reconnect-aware settlement delivery, and PN1 orderbook integrity. Unknown additive events remain available as raw payloads, decimal values remain precision-safe, and any local queue eviction is reported.
6
+
5
7
  **New in v0.11.0:** Current-production parity. Trading now defaults to CLOB V2 on `clob.polymarket.com`, uses PolyNode's public builder attribution unless overridden, omits removed V1 wire fields, and supports V2 GTD expiration. Managed 5-minute, 15-minute, and 4-hour streams select the required 30/60-second Chainlink TWAP lookbacks on a dedicated connection and reconnect/resubscribe at every market rotation. WebSocket models, presets, and filters now cover current redemption, position-conversion, dome/fill, and PM2 combo events. REST position queries now include redeemable/condition filters, multi-wallet batches, and market-holder views; connection and status observability match the current public API.
6
8
 
7
9
  **New in v0.10.8:** POLY_1271 V2 order signatures now normalize the ERC-7739 `TypedDataSign` recovery byte to Ethereum `v=27/28` for on-chain ERC-1271 validation.
@@ -16,7 +18,7 @@ pip install polynode
16
18
 
17
19
  For trading support:
18
20
  ```bash
19
- pip install polynode[trading]
21
+ pip install 'polynode[trading]'
20
22
  ```
21
23
 
22
24
  ## Quick Start
@@ -83,6 +85,34 @@ async def main():
83
85
  asyncio.run(main())
84
86
  ```
85
87
 
88
+ ### Complete V3 API
89
+
90
+ V3 includes wallets, combos, rewards, credits, identities, markets, builders, profiles, perps, crypto, sports, backtesting, and other current product families. `execute()` gives you access to all 120 current V3 operations through one consistent Python interface.
91
+
92
+ ```python
93
+ import asyncio
94
+ from polynode import AsyncPolyNode
95
+
96
+ async def read_v3(address: str):
97
+ async with AsyncPolyNode(api_key="pn_live_...") as pn:
98
+ print(len(pn.v3.operations)) # 120
99
+
100
+ combo_activity = await pn.v3.execute(
101
+ "GET /v3/combos/activity",
102
+ query={"limit": 25},
103
+ )
104
+ wallet_rewards = await pn.v3.execute(
105
+ "GET /v3/wallets/{address}/rewards",
106
+ path_params={"address": address},
107
+ query={"limit": 100},
108
+ )
109
+ return combo_activity, wallet_rewards
110
+
111
+ asyncio.run(read_v3("0xabc..."))
112
+ ```
113
+
114
+ The SDK encodes path parameters for you. Read requests that are safe to repeat retry transient failures and honor `Retry-After`; requests that change data are never retried automatically. JSON decimals decode as `Decimal`, and `ApiError` exposes the status, request ID, retry details, and a request URL with credentials removed.
115
+
86
116
  Current presets include `dome`, `fills`, `combos`, `redemptions`, and `deposits`. Current filters include `since()`, `combo_condition_ids()`, `leg_position_ids()`, `event_ids()`, `module_ids()`, `action()`, and `direction()`.
87
117
 
88
118
  `dome` and `fills` change settlement delivery into a flat, per-fill wire
@@ -90,6 +120,22 @@ format. Use one of those presets on a dedicated `PolyNodeWS` connection when
90
120
  also consuming non-fill events; the server deduplicates delivery per
91
121
  connection and cannot deliver both wire formats for the same settlement.
92
122
 
123
+ ### Reconnect and delivery behavior
124
+
125
+ Why: a reconnect can overlap the last event or exceed the server's retained history. The SDK resubscribes with the latest accepted timestamp, deduplicates the overlap, preserves unknown additive events, and reports replay state. Replay is best effort, not an unbounded gapless guarantee.
126
+
127
+ ```python
128
+ pn.ws.on_replay(
129
+ lambda notice: print(
130
+ notice.phase, notice.since, notice.guaranteed, notice.warning
131
+ )
132
+ )
133
+
134
+ sub.on_overflow(
135
+ lambda overflow: print("local iterator queue evicted", overflow.dropped_events)
136
+ )
137
+ ```
138
+
93
139
  ### Chainlink TWAP and short-form markets
94
140
 
95
141
  The TWAP values are lookback windows, not update cadence: 5-minute markets use 30 seconds; 15-minute and 4-hour markets use 60 seconds.
@@ -113,6 +159,40 @@ async def stream_short_markets(pn):
113
159
 
114
160
  A Chainlink selection is scoped to its WebSocket connection, so combine feeds and windows into one Chainlink subscription per connection. The resolved subscription exposes the server acknowledgement through `price_source`, `twap_windows`, and `warnings`. `short_form()` handles rotation safely with its own socket. At each market boundary it closes that socket, discovers the new slugs, reconnects, and subscribes to the exact settlement and TWAP filters again.
115
161
 
162
+ ### V3 perps WebSocket
163
+
164
+ The V3 perps WebSocket streams tickers, best bid/offer, full books, trades, statistics, and klines. The managed client confirms which channels were accepted, reconnects and resubscribes, and emits an explicit gap notice because the perps stream cannot replay missed messages.
165
+
166
+ ```python
167
+ import asyncio
168
+ from polynode import AsyncPolyNode, PerpsEvent, perps_channels
169
+
170
+ async def stream_perps():
171
+ async with AsyncPolyNode(api_key="pn_live_...") as pn:
172
+ perps = pn.perps
173
+ hello = await perps.connect()
174
+ ack = await perps.subscribe([
175
+ perps_channels.tickers,
176
+ perps_channels.book("BTC-USD"),
177
+ perps_channels.trades("BTC-USD"),
178
+ ])
179
+ print(hello.max_subscriptions, ack.channels, ack.rejected)
180
+
181
+ try:
182
+ async for message in perps:
183
+ if isinstance(message, PerpsEvent) and message.channel == "perps_tickers":
184
+ # Prices, quantities, funding, and equity values stay exact strings.
185
+ print(message.data["mark_price"], message.data["funding_rate"])
186
+ elif message.type in ("lag_warning", "reconnect"):
187
+ print(message)
188
+ finally:
189
+ await perps.disconnect()
190
+
191
+ asyncio.run(stream_perps())
192
+ ```
193
+
194
+ Use `perps_channels.bbo()`, `.book()`, `.trades()`, and `.klines(instrument, "1m" | "1h")` for scoped channels. Each `perps_book` event is a complete replacement snapshot; `perps.book("BTC-USD")` returns the latest complete book. Authentication (`4401`) and connection-cap (`4429`) closes are terminal. Queue eviction is observable through `on_overflow()`.
195
+
116
196
  ### WebSocket Streaming
117
197
 
118
198
  ```python
@@ -136,15 +216,18 @@ import asyncio
136
216
  from polynode import OrderbookEngine
137
217
 
138
218
  async def main():
139
- engine = OrderbookEngine(api_key="pn_live_...")
219
+ engine = OrderbookEngine(api_key="pn_live_...", integrity=True)
140
220
  await engine.subscribe(["token_id_1", "token_id_2"])
141
221
 
142
222
  engine.on("ready", lambda: print(f"Tracking {engine.size} books"))
143
223
  engine.on("update", lambda u: print(f"{u.asset_id}: {engine.midpoint(u.asset_id)}"))
224
+ engine.on("integrity_error", lambda error: print(error.token, error.code))
144
225
 
145
226
  asyncio.run(main())
146
227
  ```
147
228
 
229
+ With PN1 integrity enabled, the engine validates sequence continuity and deterministic checksums, fails stale or invalid books closed by default, and requests a fresh anchor before making them readable again. Integrity mode requires explicit markets; wildcard subscriptions are unavailable. Set `allow_stale_reads=True` only when your application explicitly prefers availability over verified state.
230
+
148
231
  ### Trading
149
232
 
150
233
  ```python