polymarket-apis 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl
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.
Potentially problematic release.
This version of polymarket-apis might be problematic. Click here for more details.
- polymarket_apis/clients/clob_client.py +37 -3
- polymarket_apis/clients/gamma_client.py +84 -64
- polymarket_apis/clients/graphql_client.py +182 -0
- polymarket_apis/clients/web3_client.py +1 -1
- polymarket_apis/clients/websockets_client.py +102 -29
- polymarket_apis/types/clob_types.py +1 -1
- polymarket_apis/types/common.py +4 -2
- polymarket_apis/types/gamma_types.py +183 -142
- polymarket_apis/types/websockets_types.py +156 -42
- polymarket_apis/utilities/config.py +12 -0
- polymarket_apis/utilities/endpoints.py +1 -0
- polymarket_apis/utilities/exceptions.py +6 -0
- polymarket_apis/utilities/headers.py +1 -1
- {polymarket_apis-0.2.2.dist-info → polymarket_apis-0.2.4.dist-info}/METADATA +1 -1
- {polymarket_apis-0.2.2.dist-info → polymarket_apis-0.2.4.dist-info}/RECORD +16 -15
- {polymarket_apis-0.2.2.dist-info → polymarket_apis-0.2.4.dist-info}/WHEEL +0 -0
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
from collections.abc import Callable
|
|
2
|
-
from
|
|
2
|
+
from json import JSONDecodeError
|
|
3
|
+
from typing import Any, Optional
|
|
3
4
|
|
|
4
5
|
from lomond import WebSocket
|
|
5
6
|
from lomond.persist import persist
|
|
6
7
|
from pydantic import ValidationError
|
|
7
8
|
|
|
9
|
+
from polymarket_apis.utilities.exceptions import AuthenticationRequiredError
|
|
10
|
+
|
|
8
11
|
from ..types.clob_types import ApiCreds
|
|
9
12
|
from ..types.websockets_types import (
|
|
13
|
+
ActivityOrderMatchEvent,
|
|
14
|
+
ActivityTradeEvent,
|
|
10
15
|
CommentEvent,
|
|
11
|
-
|
|
16
|
+
CryptoPriceSubscribeEvent,
|
|
17
|
+
CryptoPriceUpdateEvent,
|
|
18
|
+
LastTradePriceEvent,
|
|
19
|
+
LiveDataLastTradePriceEvent,
|
|
20
|
+
LiveDataOrderBookSummaryEvent,
|
|
21
|
+
LiveDataOrderEvent,
|
|
22
|
+
LiveDataPriceChangeEvent,
|
|
23
|
+
LiveDataTickSizeChangeEvent,
|
|
12
24
|
LiveDataTradeEvent,
|
|
25
|
+
MarketStatusChangeEvent,
|
|
13
26
|
OrderBookSummaryEvent,
|
|
14
27
|
OrderEvent,
|
|
15
28
|
PriceChangeEvent,
|
|
@@ -23,28 +36,42 @@ from ..types.websockets_types import (
|
|
|
23
36
|
|
|
24
37
|
def _process_market_event(event):
|
|
25
38
|
try:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
print(OrderBookSummaryEvent(**
|
|
31
|
-
|
|
32
|
-
print(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
message = event.json
|
|
40
|
+
if isinstance(message, list):
|
|
41
|
+
for item in message:
|
|
42
|
+
try:
|
|
43
|
+
print(OrderBookSummaryEvent(**item), "\n")
|
|
44
|
+
except ValidationError as e:
|
|
45
|
+
print(item.text)
|
|
46
|
+
print(e.errors())
|
|
47
|
+
return
|
|
48
|
+
match message["event_type"]:
|
|
49
|
+
case "book":
|
|
50
|
+
print(OrderBookSummaryEvent(**message), "\n")
|
|
51
|
+
case "price_change":
|
|
52
|
+
print(PriceChangeEvent(**message), "\n")
|
|
53
|
+
case "tick_size_change":
|
|
54
|
+
print(TickSizeChangeEvent(**message), "\n")
|
|
55
|
+
case "last_trade_price":
|
|
56
|
+
print(LastTradePriceEvent(**message), "\n")
|
|
57
|
+
case _:
|
|
58
|
+
print(message)
|
|
59
|
+
except JSONDecodeError:
|
|
36
60
|
print(event.text)
|
|
37
|
-
|
|
61
|
+
except ValidationError as e:
|
|
62
|
+
print(e.errors())
|
|
63
|
+
print(event.json)
|
|
38
64
|
|
|
39
65
|
def _process_user_event(event):
|
|
40
66
|
try:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
message = event.json
|
|
68
|
+
match message["event_type"]:
|
|
69
|
+
case "order":
|
|
70
|
+
print(OrderEvent(**message), "\n")
|
|
71
|
+
case "trade":
|
|
72
|
+
print(TradeEvent(**message), "\n")
|
|
73
|
+
except JSONDecodeError:
|
|
74
|
+
print(event.text)
|
|
48
75
|
except ValidationError as e:
|
|
49
76
|
print(event.text)
|
|
50
77
|
print(e.errors(), "\n")
|
|
@@ -54,9 +81,9 @@ def _process_live_data_event(event):
|
|
|
54
81
|
message = event.json
|
|
55
82
|
match message["type"]:
|
|
56
83
|
case "trades":
|
|
57
|
-
print(
|
|
84
|
+
print(ActivityTradeEvent(**message), "\n")
|
|
58
85
|
case "orders_matched":
|
|
59
|
-
print(
|
|
86
|
+
print(ActivityOrderMatchEvent(**message), "\n")
|
|
60
87
|
case "comment_created" | "comment_removed":
|
|
61
88
|
print(CommentEvent(**message), "\n")
|
|
62
89
|
case "reaction_created" | "reaction_removed":
|
|
@@ -65,9 +92,31 @@ def _process_live_data_event(event):
|
|
|
65
92
|
print(RequestEvent(**message), "\n")
|
|
66
93
|
case "quote_created" | "quote_edited" | "quote_canceled" | "quote_expired":
|
|
67
94
|
print(QuoteEvent(**message), "\n")
|
|
68
|
-
|
|
95
|
+
case "subscribe":
|
|
96
|
+
print(CryptoPriceSubscribeEvent(**message), "\n")
|
|
97
|
+
case "update":
|
|
98
|
+
print(CryptoPriceUpdateEvent(**message), "\n")
|
|
99
|
+
case "agg_orderbook":
|
|
100
|
+
print(LiveDataOrderBookSummaryEvent(**message), "\n")
|
|
101
|
+
case "price_change":
|
|
102
|
+
print(LiveDataPriceChangeEvent(**message), "\n")
|
|
103
|
+
case "last_trade_price":
|
|
104
|
+
print(LiveDataLastTradePriceEvent(**message), "\n")
|
|
105
|
+
case "tick_size_change":
|
|
106
|
+
print(LiveDataTickSizeChangeEvent(**message), "\n")
|
|
107
|
+
case "market_created" | "market_resolved":
|
|
108
|
+
print(MarketStatusChangeEvent(**message), "\n")
|
|
109
|
+
case "order":
|
|
110
|
+
print(LiveDataOrderEvent(**message), "\n")
|
|
111
|
+
case "trade":
|
|
112
|
+
print(LiveDataTradeEvent(**message), "\n")
|
|
113
|
+
case _:
|
|
114
|
+
print(message)
|
|
115
|
+
except JSONDecodeError:
|
|
69
116
|
print(event.text)
|
|
117
|
+
except ValidationError as e:
|
|
70
118
|
print(e.errors(), "\n")
|
|
119
|
+
print(event.text)
|
|
71
120
|
|
|
72
121
|
class PolymarketWebsocketsClient:
|
|
73
122
|
def __init__(self):
|
|
@@ -85,6 +134,7 @@ class PolymarketWebsocketsClient:
|
|
|
85
134
|
|
|
86
135
|
"""
|
|
87
136
|
websocket = WebSocket(self.url_market)
|
|
137
|
+
|
|
88
138
|
for event in persist(websocket): # persist automatically reconnects
|
|
89
139
|
if event.name == "ready":
|
|
90
140
|
websocket.send_json(
|
|
@@ -103,29 +153,52 @@ class PolymarketWebsocketsClient:
|
|
|
103
153
|
|
|
104
154
|
"""
|
|
105
155
|
websocket = WebSocket(self.url_user)
|
|
156
|
+
|
|
106
157
|
for event in persist(websocket):
|
|
107
158
|
if event.name == "ready":
|
|
108
159
|
websocket.send_json(
|
|
109
|
-
auth
|
|
160
|
+
auth=creds.model_dump(by_alias=True),
|
|
110
161
|
)
|
|
111
162
|
elif event.name == "text":
|
|
112
163
|
process_event(event)
|
|
113
164
|
|
|
114
|
-
def live_data_socket(self, subscriptions: list[dict[str, Any]], process_event: Callable = _process_live_data_event):
|
|
165
|
+
def live_data_socket(self, subscriptions: list[dict[str, Any]], process_event: Callable = _process_live_data_event, creds: Optional[ApiCreds] = None):
|
|
166
|
+
# info on how to subscribe found at https://github.com/Polymarket/real-time-data-client?tab=readme-ov-file#subscribe
|
|
115
167
|
"""
|
|
116
168
|
Connect to the live data websocket and subscribe to specified events.
|
|
117
169
|
|
|
118
170
|
Args:
|
|
119
171
|
subscriptions: List of subscription configurations
|
|
120
172
|
process_event: Callback function to process received events
|
|
173
|
+
creds: ApiCreds for authentication if subscribing to clob_user topic
|
|
121
174
|
|
|
122
175
|
"""
|
|
123
176
|
websocket = WebSocket(self.url_live_data)
|
|
177
|
+
|
|
178
|
+
needs_auth = any(sub.get("topic") == "clob_user" for sub in subscriptions)
|
|
179
|
+
if needs_auth and creds is None:
|
|
180
|
+
msg = "ApiCreds credentials are required for the clob_user topic subscriptions"
|
|
181
|
+
raise AuthenticationRequiredError(msg)
|
|
182
|
+
|
|
124
183
|
for event in persist(websocket):
|
|
125
184
|
if event.name == "ready":
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
subscriptions
|
|
129
|
-
|
|
185
|
+
if needs_auth:
|
|
186
|
+
subscriptions_with_creds = []
|
|
187
|
+
for sub in subscriptions:
|
|
188
|
+
if sub.get("topic") == "clob_user":
|
|
189
|
+
sub_copy = sub.copy()
|
|
190
|
+
sub_copy["clob_auth"] = creds.model_dump()
|
|
191
|
+
subscriptions_with_creds.append(sub_copy)
|
|
192
|
+
else:
|
|
193
|
+
subscriptions_with_creds.append(sub)
|
|
194
|
+
subscriptions = subscriptions_with_creds
|
|
195
|
+
|
|
196
|
+
payload = {
|
|
197
|
+
"action": "subscribe",
|
|
198
|
+
"subscriptions": subscriptions,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
websocket.send_json(**payload)
|
|
202
|
+
|
|
130
203
|
elif event.name == "text":
|
|
131
204
|
process_event(event)
|
polymarket_apis/types/common.py
CHANGED
|
@@ -12,6 +12,8 @@ def validate_keccak256(v: str) -> str:
|
|
|
12
12
|
return v
|
|
13
13
|
|
|
14
14
|
def parse_timestamp(v: str) -> datetime:
|
|
15
|
+
if isinstance(v, datetime):
|
|
16
|
+
return v
|
|
15
17
|
# Normalize '+00' to '+0000' for timezone
|
|
16
18
|
if v.endswith("+00"):
|
|
17
19
|
v = v[:-3] + "+0000"
|
|
@@ -45,5 +47,5 @@ Keccak256 = Annotated[str, AfterValidator(validate_keccak256)]
|
|
|
45
47
|
EmptyString = Annotated[str, Field(pattern=r"^$", description="An empty string")]
|
|
46
48
|
|
|
47
49
|
class TimeseriesPoint(BaseModel):
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
value: float
|
|
51
|
+
timestamp: datetime
|