polymarket-apis 0.3.0__py3-none-any.whl → 0.3.9__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/__init__.py +42 -0
- polymarket_apis/clients/__init__.py +23 -0
- polymarket_apis/clients/clob_client.py +224 -117
- polymarket_apis/clients/data_client.py +220 -67
- polymarket_apis/clients/gamma_client.py +589 -101
- polymarket_apis/clients/graphql_client.py +28 -11
- polymarket_apis/clients/web3_client.py +538 -131
- polymarket_apis/clients/websockets_client.py +24 -7
- polymarket_apis/types/__init__.py +167 -0
- polymarket_apis/types/clob_types.py +35 -14
- polymarket_apis/types/common.py +105 -35
- polymarket_apis/types/data_types.py +48 -3
- polymarket_apis/types/gamma_types.py +529 -257
- polymarket_apis/types/web3_types.py +45 -0
- polymarket_apis/types/websockets_types.py +92 -41
- polymarket_apis/utilities/config.py +1 -0
- polymarket_apis/utilities/constants.py +5 -4
- polymarket_apis/utilities/exceptions.py +9 -0
- polymarket_apis/utilities/order_builder/builder.py +38 -22
- polymarket_apis/utilities/order_builder/helpers.py +0 -1
- polymarket_apis/utilities/signing/hmac.py +5 -1
- polymarket_apis/utilities/signing/signer.py +2 -2
- polymarket_apis/utilities/web3/abis/Safe.json +1138 -0
- polymarket_apis/utilities/web3/abis/SafeProxyFactory.json +224 -0
- polymarket_apis/utilities/web3/abis/custom_contract_errors.py +1 -1
- polymarket_apis/utilities/web3/helpers.py +235 -0
- {polymarket_apis-0.3.0.dist-info → polymarket_apis-0.3.9.dist-info}/METADATA +48 -8
- polymarket_apis-0.3.9.dist-info/RECORD +44 -0
- polymarket_apis/utilities/schemas/activity-subgraph.graphql +0 -86
- polymarket_apis/utilities/schemas/open-interest.graphql +0 -30
- polymarket_apis-0.3.0.dist-info/RECORD +0 -43
- {polymarket_apis-0.3.0.dist-info → polymarket_apis-0.3.9.dist-info}/WHEEL +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
-
from datetime import UTC, datetime
|
|
4
|
-
from typing import Literal,
|
|
3
|
+
from datetime import UTC, datetime, timedelta
|
|
4
|
+
from typing import Literal, cast
|
|
5
5
|
from urllib.parse import urljoin
|
|
6
6
|
|
|
7
7
|
import httpx
|
|
@@ -27,11 +27,11 @@ from ..types.clob_types import (
|
|
|
27
27
|
PaginatedResponse,
|
|
28
28
|
PartialCreateOrderOptions,
|
|
29
29
|
PolygonTrade,
|
|
30
|
-
PolymarketRewardItem,
|
|
31
30
|
PostOrdersArgs,
|
|
32
31
|
Price,
|
|
33
32
|
PriceHistory,
|
|
34
33
|
RequestArgs,
|
|
34
|
+
RewardMarket,
|
|
35
35
|
Spread,
|
|
36
36
|
TickSize,
|
|
37
37
|
TokenBidAskDict,
|
|
@@ -88,17 +88,18 @@ from ..utilities.signing.signer import Signer
|
|
|
88
88
|
|
|
89
89
|
logger = logging.getLogger(__name__)
|
|
90
90
|
|
|
91
|
+
|
|
91
92
|
class PolymarketClobClient:
|
|
92
93
|
def __init__(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
self,
|
|
95
|
+
private_key: str,
|
|
96
|
+
address: EthAddress,
|
|
97
|
+
creds: ApiCreds | None = None,
|
|
98
|
+
chain_id: Literal[137, 80002] = POLYGON,
|
|
99
|
+
signature_type: Literal[0, 1, 2] = 1,
|
|
100
|
+
# 0 - EOA wallet, 1 - Proxy wallet, 2 - Gnosis Safe wallet
|
|
100
101
|
):
|
|
101
|
-
self.
|
|
102
|
+
self.address = address
|
|
102
103
|
self.client = httpx.Client(http2=True, timeout=30.0)
|
|
103
104
|
self.async_client = httpx.AsyncClient(http2=True, timeout=30.0)
|
|
104
105
|
self.base_url: str = "https://clob.polymarket.com"
|
|
@@ -106,14 +107,14 @@ class PolymarketClobClient:
|
|
|
106
107
|
self.builder = OrderBuilder(
|
|
107
108
|
signer=self.signer,
|
|
108
109
|
sig_type=signature_type,
|
|
109
|
-
funder=
|
|
110
|
+
funder=address,
|
|
110
111
|
)
|
|
111
112
|
self.creds = creds if creds else self.create_or_derive_api_creds()
|
|
112
113
|
|
|
113
114
|
# local cache
|
|
114
|
-
self.__tick_sizes = {}
|
|
115
|
-
self.__neg_risk = {}
|
|
116
|
-
self.__fee_rates = {}
|
|
115
|
+
self.__tick_sizes: dict[str, TickSize] = {}
|
|
116
|
+
self.__neg_risk: dict[str, bool] = {}
|
|
117
|
+
self.__fee_rates: dict[str, int] = {}
|
|
117
118
|
|
|
118
119
|
def _build_url(self, endpoint: str) -> str:
|
|
119
120
|
return urljoin(self.base_url, endpoint)
|
|
@@ -123,19 +124,19 @@ class PolymarketClobClient:
|
|
|
123
124
|
response.raise_for_status()
|
|
124
125
|
return response.json()
|
|
125
126
|
|
|
126
|
-
def create_api_creds(self, nonce:
|
|
127
|
+
def create_api_creds(self, nonce: int | None = None) -> ApiCreds:
|
|
127
128
|
headers = create_level_1_headers(self.signer, nonce)
|
|
128
129
|
response = self.client.post(self._build_url(CREATE_API_KEY), headers=headers)
|
|
129
130
|
response.raise_for_status()
|
|
130
131
|
return ApiCreds(**response.json())
|
|
131
132
|
|
|
132
|
-
def derive_api_key(self, nonce:
|
|
133
|
+
def derive_api_key(self, nonce: int | None = None) -> ApiCreds:
|
|
133
134
|
headers = create_level_1_headers(self.signer, nonce)
|
|
134
135
|
response = self.client.get(self._build_url(DERIVE_API_KEY), headers=headers)
|
|
135
136
|
response.raise_for_status()
|
|
136
137
|
return ApiCreds(**response.json())
|
|
137
138
|
|
|
138
|
-
def create_or_derive_api_creds(self, nonce:
|
|
139
|
+
def create_or_derive_api_creds(self, nonce: int | None = None) -> ApiCreds:
|
|
139
140
|
try:
|
|
140
141
|
return self.create_api_creds(nonce)
|
|
141
142
|
except HTTPStatusError:
|
|
@@ -171,7 +172,9 @@ class PolymarketClobClient:
|
|
|
171
172
|
params = {"token_id": token_id}
|
|
172
173
|
response = self.client.get(self._build_url(GET_TICK_SIZE), params=params)
|
|
173
174
|
response.raise_for_status()
|
|
174
|
-
self.__tick_sizes[token_id] =
|
|
175
|
+
self.__tick_sizes[token_id] = cast(
|
|
176
|
+
"TickSize", str(response.json()["minimum_tick_size"])
|
|
177
|
+
)
|
|
175
178
|
|
|
176
179
|
return self.__tick_sizes[token_id]
|
|
177
180
|
|
|
@@ -199,7 +202,9 @@ class PolymarketClobClient:
|
|
|
199
202
|
return fee_rate
|
|
200
203
|
|
|
201
204
|
def __resolve_tick_size(
|
|
202
|
-
|
|
205
|
+
self,
|
|
206
|
+
token_id: str,
|
|
207
|
+
tick_size: TickSize | None = None,
|
|
203
208
|
) -> TickSize:
|
|
204
209
|
min_tick_size = self.get_tick_size(token_id)
|
|
205
210
|
if tick_size is not None:
|
|
@@ -211,12 +216,19 @@ class PolymarketClobClient:
|
|
|
211
216
|
return tick_size
|
|
212
217
|
|
|
213
218
|
def __resolve_fee_rate(
|
|
214
|
-
|
|
219
|
+
self,
|
|
220
|
+
token_id: str,
|
|
221
|
+
user_fee_rate: int | None = None,
|
|
215
222
|
) -> int:
|
|
216
223
|
market_fee_rate_bps = self.get_fee_rate_bps(token_id)
|
|
217
224
|
# If both fee rate on the market and the user supplied fee rate are non-zero, validate that they match
|
|
218
225
|
# else return the market fee rate
|
|
219
|
-
if
|
|
226
|
+
if (
|
|
227
|
+
market_fee_rate_bps > 0
|
|
228
|
+
and user_fee_rate is not None
|
|
229
|
+
and user_fee_rate > 0
|
|
230
|
+
and user_fee_rate != market_fee_rate_bps
|
|
231
|
+
):
|
|
220
232
|
msg = f"invalid user provided fee rate: ({user_fee_rate}), fee rate for the market must be {market_fee_rate_bps}"
|
|
221
233
|
raise InvalidFeeRateError(msg)
|
|
222
234
|
return market_fee_rate_bps
|
|
@@ -291,10 +303,14 @@ class PolymarketClobClient:
|
|
|
291
303
|
response.raise_for_status()
|
|
292
304
|
return [OrderBookSummary(**obs) for obs in response.json()]
|
|
293
305
|
|
|
294
|
-
async def get_order_books_async(
|
|
306
|
+
async def get_order_books_async(
|
|
307
|
+
self, token_ids: list[str]
|
|
308
|
+
) -> list[OrderBookSummary]:
|
|
295
309
|
"""Get the orderbook for a set of tokens asynchronously."""
|
|
296
310
|
body = [{"token_id": token_id} for token_id in token_ids]
|
|
297
|
-
response = await self.async_client.post(
|
|
311
|
+
response = await self.async_client.post(
|
|
312
|
+
self._build_url(GET_ORDER_BOOKS), json=body
|
|
313
|
+
)
|
|
298
314
|
response.raise_for_status()
|
|
299
315
|
return [OrderBookSummary(**obs) for obs in response.json()]
|
|
300
316
|
|
|
@@ -304,7 +320,7 @@ class PolymarketClobClient:
|
|
|
304
320
|
response.raise_for_status()
|
|
305
321
|
return ClobMarket(**response.json())
|
|
306
322
|
|
|
307
|
-
def get_markets(self, next_cursor="MA==")
|
|
323
|
+
def get_markets(self, next_cursor="MA==") -> PaginatedResponse[ClobMarket]:
|
|
308
324
|
"""Get paginated ClobMarkets."""
|
|
309
325
|
params = {"next_cursor": next_cursor}
|
|
310
326
|
response = self.client.get(self._build_url(GET_MARKETS), params=params)
|
|
@@ -333,17 +349,26 @@ class PolymarketClobClient:
|
|
|
333
349
|
return current_markets + next_page_markets
|
|
334
350
|
|
|
335
351
|
def get_recent_history(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
352
|
+
self,
|
|
353
|
+
token_id: str,
|
|
354
|
+
interval: Literal["1h", "6h", "1d", "1w", "1m", "max"] = "1d",
|
|
355
|
+
fidelity: int = 1, # resolution in minutes
|
|
340
356
|
) -> PriceHistory:
|
|
341
|
-
"""Get the recent price history of a token (up to now) - 1h, 6h, 1d."""
|
|
342
|
-
|
|
343
|
-
|
|
357
|
+
"""Get the recent price history of a token (up to now) - 1h, 6h, 1d, 1w, 1m."""
|
|
358
|
+
min_fidelities: dict[str, int] = {
|
|
359
|
+
"1h": 1,
|
|
360
|
+
"6h": 1,
|
|
361
|
+
"1d": 1,
|
|
362
|
+
"1w": 5,
|
|
363
|
+
"1m": 10,
|
|
364
|
+
"max": 2,
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if fidelity < min_fidelities[interval]:
|
|
368
|
+
msg = f"invalid filters: minimum fidelity' for '{interval}' range is {min_fidelities.get(interval)}"
|
|
344
369
|
raise ValueError(msg)
|
|
345
370
|
|
|
346
|
-
params = {
|
|
371
|
+
params: dict[str, int | str] = {
|
|
347
372
|
"market": token_id,
|
|
348
373
|
"interval": interval,
|
|
349
374
|
"fidelity": fidelity,
|
|
@@ -353,43 +378,52 @@ class PolymarketClobClient:
|
|
|
353
378
|
return PriceHistory(**response.json(), token_id=token_id)
|
|
354
379
|
|
|
355
380
|
def get_history(
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
fidelity: Optional[int] = 2, # resolution in minutes
|
|
381
|
+
self,
|
|
382
|
+
token_id: str,
|
|
383
|
+
start_time: datetime | None = None,
|
|
384
|
+
end_time: datetime | None = None,
|
|
385
|
+
fidelity: int = 2, # resolution in minutes
|
|
362
386
|
) -> PriceHistory:
|
|
363
|
-
"""Get the price history of a token between selected
|
|
364
|
-
min_fidelities = {"1m": 10, "1w": 5, "max": 2}
|
|
365
|
-
|
|
366
|
-
if fidelity < min_fidelities[interval]:
|
|
367
|
-
msg = f"invalid filters: minimum 'fidelity' for '{interval}' range is {min_fidelities[interval]}"
|
|
368
|
-
raise ValueError(msg)
|
|
369
|
-
|
|
387
|
+
"""Get the price history of a token between a selected date range of max 15 days or from start_time to now."""
|
|
370
388
|
if start_time is None and end_time is None:
|
|
371
|
-
msg = "At least
|
|
389
|
+
msg = "At least 'start_time' or ('start_time' and 'end_time') must be provided"
|
|
372
390
|
raise ValueError(msg)
|
|
373
391
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
start_time
|
|
378
|
-
|
|
379
|
-
|
|
392
|
+
if (
|
|
393
|
+
start_time
|
|
394
|
+
and end_time
|
|
395
|
+
and start_time + timedelta(days=15, seconds=1) < end_time
|
|
396
|
+
):
|
|
397
|
+
msg = "'start_time' - 'end_time' range cannot exceed 15 days. Remove 'end_time' to get prices up to now or set a shorter range."
|
|
398
|
+
raise ValueError(msg)
|
|
380
399
|
|
|
381
|
-
params = {
|
|
400
|
+
params: dict[str, int | str] = {
|
|
382
401
|
"market": token_id,
|
|
383
|
-
"startTs": int(start_time.timestamp()),
|
|
384
|
-
"endTs": int(end_time.timestamp()),
|
|
385
|
-
"interval": interval,
|
|
386
402
|
"fidelity": fidelity,
|
|
387
403
|
}
|
|
404
|
+
if start_time:
|
|
405
|
+
params["startTs"] = int(start_time.timestamp())
|
|
406
|
+
if end_time:
|
|
407
|
+
params["endTs"] = int(end_time.timestamp())
|
|
408
|
+
|
|
388
409
|
response = self.client.get(self._build_url("/prices-history"), params=params)
|
|
389
410
|
response.raise_for_status()
|
|
390
411
|
return PriceHistory(**response.json(), token_id=token_id)
|
|
391
412
|
|
|
392
|
-
def
|
|
413
|
+
def get_all_history(self, token_id: str) -> PriceHistory:
|
|
414
|
+
"""Get the full price history of a token."""
|
|
415
|
+
return self.get_history(
|
|
416
|
+
token_id=token_id,
|
|
417
|
+
start_time=datetime(2020, 1, 1, tzinfo=UTC),
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
def get_orders(
|
|
421
|
+
self,
|
|
422
|
+
order_id: str | None = None,
|
|
423
|
+
condition_id: Keccak256 | None = None,
|
|
424
|
+
token_id: str | None = None,
|
|
425
|
+
next_cursor: str = "MA==",
|
|
426
|
+
) -> list[OpenOrder]:
|
|
393
427
|
"""Gets your active orders, filtered by order_id, condition_id, token_id."""
|
|
394
428
|
params = {}
|
|
395
429
|
if order_id:
|
|
@@ -406,14 +440,18 @@ class PolymarketClobClient:
|
|
|
406
440
|
next_cursor = next_cursor if next_cursor is not None else "MA=="
|
|
407
441
|
while next_cursor != END_CURSOR:
|
|
408
442
|
params["next_cursor"] = next_cursor
|
|
409
|
-
response = self.client.get(
|
|
443
|
+
response = self.client.get(
|
|
444
|
+
self._build_url(ORDERS), headers=headers, params=params
|
|
445
|
+
)
|
|
410
446
|
response.raise_for_status()
|
|
411
447
|
next_cursor = response.json()["next_cursor"]
|
|
412
448
|
results += [OpenOrder(**order) for order in response.json()["data"]]
|
|
413
449
|
|
|
414
450
|
return results
|
|
415
451
|
|
|
416
|
-
def create_order(
|
|
452
|
+
def create_order(
|
|
453
|
+
self, order_args: OrderArgs, options: PartialCreateOrderOptions | None = None
|
|
454
|
+
) -> SignedOrder:
|
|
417
455
|
"""Creates and signs an order."""
|
|
418
456
|
# add resolve_order_options, or similar
|
|
419
457
|
tick_size = self.__resolve_tick_size(
|
|
@@ -425,7 +463,6 @@ class PolymarketClobClient:
|
|
|
425
463
|
msg = f"price ({order_args.price}), min: {tick_size} - max: {1 - float(tick_size)}"
|
|
426
464
|
raise InvalidPriceError(msg)
|
|
427
465
|
|
|
428
|
-
|
|
429
466
|
neg_risk = (
|
|
430
467
|
options.neg_risk
|
|
431
468
|
if options and options.neg_risk
|
|
@@ -433,7 +470,9 @@ class PolymarketClobClient:
|
|
|
433
470
|
)
|
|
434
471
|
|
|
435
472
|
# fee rate
|
|
436
|
-
fee_rate_bps = self.__resolve_fee_rate(
|
|
473
|
+
fee_rate_bps = self.__resolve_fee_rate(
|
|
474
|
+
order_args.token_id, order_args.fee_rate_bps
|
|
475
|
+
)
|
|
437
476
|
order_args.fee_rate_bps = fee_rate_bps
|
|
438
477
|
|
|
439
478
|
return self.builder.create_order(
|
|
@@ -444,7 +483,9 @@ class PolymarketClobClient:
|
|
|
444
483
|
),
|
|
445
484
|
)
|
|
446
485
|
|
|
447
|
-
def post_order(
|
|
486
|
+
def post_order(
|
|
487
|
+
self, order: SignedOrder, order_type: OrderType = OrderType.GTC
|
|
488
|
+
) -> OrderPostResponse | None:
|
|
448
489
|
"""Posts a SignedOrder."""
|
|
449
490
|
body = order_to_json(order, self.creds.key, order_type)
|
|
450
491
|
headers = create_level_2_headers(
|
|
@@ -466,15 +507,23 @@ class PolymarketClobClient:
|
|
|
466
507
|
logger.warning(msg)
|
|
467
508
|
error_json = exc.response.json()
|
|
468
509
|
print("Details:", error_json["error"])
|
|
469
|
-
|
|
470
|
-
|
|
510
|
+
return None
|
|
511
|
+
|
|
512
|
+
def create_and_post_order(
|
|
513
|
+
self,
|
|
514
|
+
order_args: OrderArgs,
|
|
515
|
+
options: PartialCreateOrderOptions | None = None,
|
|
516
|
+
order_type: OrderType = OrderType.GTC,
|
|
517
|
+
) -> OrderPostResponse | None:
|
|
471
518
|
"""Utility function to create and publish an order."""
|
|
472
519
|
order = self.create_order(order_args, options)
|
|
473
520
|
return self.post_order(order=order, order_type=order_type)
|
|
474
521
|
|
|
475
|
-
def post_orders(self, args: list[PostOrdersArgs]):
|
|
522
|
+
def post_orders(self, args: list[PostOrdersArgs]) -> list[OrderPostResponse] | None:
|
|
476
523
|
"""Posts multiple SignedOrders at once."""
|
|
477
|
-
body = [
|
|
524
|
+
body = [
|
|
525
|
+
order_to_json(arg.order, self.creds.key, arg.order_type) for arg in args
|
|
526
|
+
]
|
|
478
527
|
headers = create_level_2_headers(
|
|
479
528
|
self.signer,
|
|
480
529
|
self.creds,
|
|
@@ -493,26 +542,36 @@ class PolymarketClobClient:
|
|
|
493
542
|
resp = OrderPostResponse(**item)
|
|
494
543
|
order_responses.append(resp)
|
|
495
544
|
if resp.error_msg:
|
|
496
|
-
msg = (
|
|
497
|
-
|
|
545
|
+
msg = (
|
|
546
|
+
f"Error posting order in position {index} \n"
|
|
547
|
+
f"Details: {resp.error_msg}"
|
|
548
|
+
)
|
|
498
549
|
logger.warning(msg)
|
|
499
550
|
except httpx.HTTPStatusError as exc:
|
|
500
551
|
msg = f"Client Error '{exc.response.status_code} {exc.response.reason_phrase}' while posting order"
|
|
501
552
|
logger.warning(msg)
|
|
502
553
|
error_json = exc.response.json()
|
|
503
554
|
print("Details:", error_json["error"])
|
|
555
|
+
return None
|
|
504
556
|
else:
|
|
505
557
|
return order_responses
|
|
506
558
|
|
|
507
|
-
def create_and_post_orders(
|
|
559
|
+
def create_and_post_orders(
|
|
560
|
+
self, args: list[OrderArgs], order_types: list[OrderType]
|
|
561
|
+
) -> list[OrderPostResponse] | None:
|
|
508
562
|
"""Utility function to create and publish multiple orders at once."""
|
|
509
563
|
return self.post_orders(
|
|
510
|
-
[
|
|
511
|
-
|
|
512
|
-
|
|
564
|
+
[
|
|
565
|
+
PostOrdersArgs(
|
|
566
|
+
order=self.create_order(order_args), order_type=order_type
|
|
567
|
+
)
|
|
568
|
+
for order_args, order_type in zip(args, order_types, strict=True)
|
|
569
|
+
],
|
|
513
570
|
)
|
|
514
571
|
|
|
515
|
-
def calculate_market_price(
|
|
572
|
+
def calculate_market_price(
|
|
573
|
+
self, token_id: str, side: str, amount: float, order_type: OrderType
|
|
574
|
+
) -> float:
|
|
516
575
|
"""Calculates the matching price considering an amount and the current orderbook."""
|
|
517
576
|
book = self.get_order_book(token_id)
|
|
518
577
|
if book is None:
|
|
@@ -523,19 +582,27 @@ class PolymarketClobClient:
|
|
|
523
582
|
msg = "No ask orders available"
|
|
524
583
|
raise LiquidityError(msg)
|
|
525
584
|
return self.builder.calculate_buy_market_price(
|
|
526
|
-
book.asks,
|
|
585
|
+
book.asks,
|
|
586
|
+
amount,
|
|
587
|
+
order_type,
|
|
527
588
|
)
|
|
528
589
|
if side == "SELL":
|
|
529
590
|
if book.bids is None:
|
|
530
591
|
msg = "No bid orders available"
|
|
531
592
|
raise LiquidityError(msg)
|
|
532
593
|
return self.builder.calculate_sell_market_price(
|
|
533
|
-
book.bids,
|
|
594
|
+
book.bids,
|
|
595
|
+
amount,
|
|
596
|
+
order_type,
|
|
534
597
|
)
|
|
535
598
|
msg = 'Side must be "BUY" or "SELL"'
|
|
536
599
|
raise ValueError(msg)
|
|
537
600
|
|
|
538
|
-
def create_market_order(
|
|
601
|
+
def create_market_order(
|
|
602
|
+
self,
|
|
603
|
+
order_args: MarketOrderArgs,
|
|
604
|
+
options: PartialCreateOrderOptions | None = None,
|
|
605
|
+
):
|
|
539
606
|
"""Creates and signs a market order."""
|
|
540
607
|
tick_size = self.__resolve_tick_size(
|
|
541
608
|
order_args.token_id,
|
|
@@ -561,7 +628,9 @@ class PolymarketClobClient:
|
|
|
561
628
|
)
|
|
562
629
|
|
|
563
630
|
# fee rate
|
|
564
|
-
fee_rate_bps = self.__resolve_fee_rate(
|
|
631
|
+
fee_rate_bps = self.__resolve_fee_rate(
|
|
632
|
+
order_args.token_id, order_args.fee_rate_bps
|
|
633
|
+
)
|
|
565
634
|
order_args.fee_rate_bps = fee_rate_bps
|
|
566
635
|
|
|
567
636
|
return self.builder.create_market_order(
|
|
@@ -573,11 +642,11 @@ class PolymarketClobClient:
|
|
|
573
642
|
)
|
|
574
643
|
|
|
575
644
|
def create_and_post_market_order(
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
) -> OrderPostResponse:
|
|
645
|
+
self,
|
|
646
|
+
order_args: MarketOrderArgs,
|
|
647
|
+
options: PartialCreateOrderOptions | None = None,
|
|
648
|
+
order_type: OrderType = OrderType.FOK,
|
|
649
|
+
) -> OrderPostResponse | None:
|
|
581
650
|
"""Utility function to create and publish a market order."""
|
|
582
651
|
order = self.create_market_order(order_args, options)
|
|
583
652
|
return self.post_order(order=order, order_type=order_type)
|
|
@@ -589,7 +658,12 @@ class PolymarketClobClient:
|
|
|
589
658
|
request_args = RequestArgs(method="DELETE", request_path=CANCEL, body=body)
|
|
590
659
|
headers = create_level_2_headers(self.signer, self.creds, request_args)
|
|
591
660
|
|
|
592
|
-
response = self.client.request(
|
|
661
|
+
response = self.client.request(
|
|
662
|
+
"DELETE",
|
|
663
|
+
self._build_url(CANCEL),
|
|
664
|
+
headers=headers,
|
|
665
|
+
content=json.dumps(body).encode("utf-8"),
|
|
666
|
+
)
|
|
593
667
|
response.raise_for_status()
|
|
594
668
|
return OrderCancelResponse(**response.json())
|
|
595
669
|
|
|
@@ -598,11 +672,18 @@ class PolymarketClobClient:
|
|
|
598
672
|
body = order_ids
|
|
599
673
|
|
|
600
674
|
request_args = RequestArgs(
|
|
601
|
-
method="DELETE",
|
|
675
|
+
method="DELETE",
|
|
676
|
+
request_path=CANCEL_ORDERS,
|
|
677
|
+
body=body,
|
|
602
678
|
)
|
|
603
679
|
headers = create_level_2_headers(self.signer, self.creds, request_args)
|
|
604
680
|
|
|
605
|
-
response = self.client.request(
|
|
681
|
+
response = self.client.request(
|
|
682
|
+
"DELETE",
|
|
683
|
+
self._build_url(CANCEL_ORDERS),
|
|
684
|
+
headers=headers,
|
|
685
|
+
content=json.dumps(body).encode("utf-8"),
|
|
686
|
+
)
|
|
606
687
|
response.raise_for_status()
|
|
607
688
|
return OrderCancelResponse(**response.json())
|
|
608
689
|
|
|
@@ -620,7 +701,11 @@ class PolymarketClobClient:
|
|
|
620
701
|
request_args = RequestArgs(method="GET", request_path=IS_ORDER_SCORING)
|
|
621
702
|
headers = create_level_2_headers(self.signer, self.creds, request_args)
|
|
622
703
|
|
|
623
|
-
response = self.client.get(
|
|
704
|
+
response = self.client.get(
|
|
705
|
+
self._build_url(IS_ORDER_SCORING),
|
|
706
|
+
headers=headers,
|
|
707
|
+
params={"order_id": order_id},
|
|
708
|
+
)
|
|
624
709
|
response.raise_for_status()
|
|
625
710
|
return response.json()["scoring"]
|
|
626
711
|
|
|
@@ -628,12 +713,16 @@ class PolymarketClobClient:
|
|
|
628
713
|
"""Check if the orders are currently scoring."""
|
|
629
714
|
body = order_ids
|
|
630
715
|
request_args = RequestArgs(
|
|
631
|
-
method="POST",
|
|
716
|
+
method="POST",
|
|
717
|
+
request_path=ARE_ORDERS_SCORING,
|
|
718
|
+
body=body,
|
|
632
719
|
)
|
|
633
720
|
headers = create_level_2_headers(self.signer, self.creds, request_args)
|
|
634
721
|
headers["Content-Type"] = "application/json"
|
|
635
722
|
|
|
636
|
-
response = self.client.post(
|
|
723
|
+
response = self.client.post(
|
|
724
|
+
self._build_url(ARE_ORDERS_SCORING), headers=headers, json=body
|
|
725
|
+
)
|
|
637
726
|
response.raise_for_status()
|
|
638
727
|
return response.json()
|
|
639
728
|
|
|
@@ -646,21 +735,24 @@ class PolymarketClobClient:
|
|
|
646
735
|
request_args = RequestArgs(method="GET", request_path="/rewards/markets/")
|
|
647
736
|
headers = create_level_2_headers(self.signer, self.creds, request_args)
|
|
648
737
|
|
|
649
|
-
response = self.client.get(
|
|
738
|
+
response = self.client.get(
|
|
739
|
+
self._build_url("/rewards/markets/" + condition_id), headers=headers
|
|
740
|
+
)
|
|
650
741
|
response.raise_for_status()
|
|
651
742
|
return next(MarketRewards(**market) for market in response.json()["data"])
|
|
652
743
|
|
|
653
744
|
def get_trades(
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
745
|
+
self,
|
|
746
|
+
condition_id: Keccak256 | None = None,
|
|
747
|
+
token_id: str | None = None,
|
|
748
|
+
trade_id: str | None = None,
|
|
749
|
+
before: datetime | None = None,
|
|
750
|
+
after: datetime | None = None,
|
|
751
|
+
address: EthAddress | None = None,
|
|
752
|
+
next_cursor="MA==",
|
|
753
|
+
) -> list[PolygonTrade]:
|
|
662
754
|
"""Fetches the trade history for a user."""
|
|
663
|
-
params = {}
|
|
755
|
+
params: dict[str, str | int] = {}
|
|
664
756
|
if condition_id:
|
|
665
757
|
params["market"] = condition_id
|
|
666
758
|
if token_id:
|
|
@@ -671,8 +763,8 @@ class PolymarketClobClient:
|
|
|
671
763
|
params["before"] = int(before.replace(microsecond=0).timestamp())
|
|
672
764
|
if after:
|
|
673
765
|
params["after"] = int(after.replace(microsecond=0).timestamp())
|
|
674
|
-
if
|
|
675
|
-
params["maker_address"] =
|
|
766
|
+
if address:
|
|
767
|
+
params["maker_address"] = address
|
|
676
768
|
|
|
677
769
|
request_args = RequestArgs(method="GET", request_path=TRADES)
|
|
678
770
|
headers = create_level_2_headers(self.signer, self.creds, request_args)
|
|
@@ -681,47 +773,61 @@ class PolymarketClobClient:
|
|
|
681
773
|
next_cursor = next_cursor if next_cursor is not None else "MA=="
|
|
682
774
|
while next_cursor != END_CURSOR:
|
|
683
775
|
params["next_cursor"] = next_cursor
|
|
684
|
-
response =
|
|
776
|
+
response = self.client.get(
|
|
777
|
+
self._build_url(TRADES), headers=headers, params=params
|
|
778
|
+
)
|
|
685
779
|
response.raise_for_status()
|
|
686
780
|
next_cursor = response.json()["next_cursor"]
|
|
687
781
|
results += [PolygonTrade(**trade) for trade in response.json()["data"]]
|
|
688
782
|
|
|
689
783
|
return results
|
|
690
784
|
|
|
691
|
-
def get_total_rewards(self, date:
|
|
785
|
+
def get_total_rewards(self, date: datetime | None = None) -> DailyEarnedReward:
|
|
692
786
|
"""Get the total rewards earned on a given date (seems to only hold the 6 most recent data points)."""
|
|
693
787
|
if date is None:
|
|
694
788
|
date = datetime.now(UTC)
|
|
695
789
|
params = {
|
|
696
790
|
"authenticationType": "magic",
|
|
697
|
-
"date": f"{date.strftime(
|
|
791
|
+
"date": f"{date.strftime('%Y-%m-%d')}",
|
|
698
792
|
}
|
|
699
793
|
|
|
700
794
|
request_args = RequestArgs(method="GET", request_path="/rewards/user/total")
|
|
701
795
|
headers = create_level_2_headers(self.signer, self.creds, request_args)
|
|
702
796
|
params["l2Headers"] = json.dumps(headers)
|
|
703
797
|
|
|
704
|
-
response = self.client.get(
|
|
798
|
+
response = self.client.get(
|
|
799
|
+
"https://polymarket.com/api/rewards/totalEarnings", params=params
|
|
800
|
+
)
|
|
705
801
|
response.raise_for_status()
|
|
706
802
|
if response.json():
|
|
707
803
|
return DailyEarnedReward(**response.json()[0])
|
|
708
804
|
return DailyEarnedReward(
|
|
709
805
|
date=date,
|
|
710
806
|
asset_address="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
|
|
711
|
-
maker_address=self.
|
|
807
|
+
maker_address=self.address,
|
|
712
808
|
earnings=0.0,
|
|
713
809
|
asset_rate=0.0,
|
|
714
810
|
)
|
|
715
811
|
|
|
716
812
|
def get_reward_markets(
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
813
|
+
self,
|
|
814
|
+
query: str | None = None,
|
|
815
|
+
sort_by: Literal[
|
|
816
|
+
"market",
|
|
817
|
+
"max_spread",
|
|
818
|
+
"min_size",
|
|
819
|
+
"rate_per_day",
|
|
820
|
+
"spread",
|
|
821
|
+
"price",
|
|
822
|
+
"earnings",
|
|
823
|
+
"earning_percentage",
|
|
824
|
+
]
|
|
825
|
+
| None = "market",
|
|
826
|
+
sort_direction: Literal["ASC", "DESC"] | None = None,
|
|
827
|
+
show_favorites: bool = False,
|
|
828
|
+
) -> list[RewardMarket]:
|
|
723
829
|
"""
|
|
724
|
-
|
|
830
|
+
Search through markets that offer rewards (polymarket.com/rewards items) by query, sorted by different metrics. If query is empty, returns all markets with rewards.
|
|
725
831
|
|
|
726
832
|
- market start date ("market") - TODO confirm this
|
|
727
833
|
- max spread for rewards in usdc
|
|
@@ -734,7 +840,7 @@ class PolymarketClobClient:
|
|
|
734
840
|
"""
|
|
735
841
|
results = []
|
|
736
842
|
desc = {"ASC": False, "DESC": True}
|
|
737
|
-
params = {
|
|
843
|
+
params: dict[str, bool | str] = {
|
|
738
844
|
"authenticationType": "magic",
|
|
739
845
|
"showFavorites": show_favorites,
|
|
740
846
|
}
|
|
@@ -753,11 +859,12 @@ class PolymarketClobClient:
|
|
|
753
859
|
next_cursor = "MA=="
|
|
754
860
|
while next_cursor != END_CURSOR:
|
|
755
861
|
params["nextCursor"] = next_cursor
|
|
756
|
-
response = self.client.get(
|
|
757
|
-
|
|
862
|
+
response = self.client.get(
|
|
863
|
+
"https://polymarket.com/api/rewards/markets", params=params
|
|
864
|
+
)
|
|
758
865
|
response.raise_for_status()
|
|
759
866
|
next_cursor = response.json()["next_cursor"]
|
|
760
|
-
results += [
|
|
867
|
+
results += [RewardMarket(**reward) for reward in response.json()["data"]]
|
|
761
868
|
|
|
762
869
|
return results
|
|
763
870
|
|