prediction-market-agent-tooling 0.65.5__py3-none-any.whl → 0.69.17.dev1149__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.
- prediction_market_agent_tooling/abis/agentresultmapping.abi.json +192 -0
- prediction_market_agent_tooling/abis/erc1155.abi.json +352 -0
- prediction_market_agent_tooling/abis/processor.abi.json +16 -0
- prediction_market_agent_tooling/abis/swapr_quoter.abi.json +221 -0
- prediction_market_agent_tooling/abis/swapr_router.abi.json +634 -0
- prediction_market_agent_tooling/benchmark/benchmark.py +1 -1
- prediction_market_agent_tooling/benchmark/utils.py +13 -0
- prediction_market_agent_tooling/chains.py +1 -0
- prediction_market_agent_tooling/config.py +61 -2
- prediction_market_agent_tooling/data_download/langfuse_data_downloader.py +405 -0
- prediction_market_agent_tooling/deploy/agent.py +199 -67
- prediction_market_agent_tooling/deploy/agent_example.py +1 -1
- prediction_market_agent_tooling/deploy/betting_strategy.py +412 -68
- prediction_market_agent_tooling/deploy/constants.py +6 -0
- prediction_market_agent_tooling/gtypes.py +11 -1
- prediction_market_agent_tooling/jobs/jobs_models.py +2 -2
- prediction_market_agent_tooling/jobs/omen/omen_jobs.py +19 -20
- prediction_market_agent_tooling/loggers.py +9 -1
- prediction_market_agent_tooling/logprobs_parser.py +2 -1
- prediction_market_agent_tooling/markets/agent_market.py +106 -18
- prediction_market_agent_tooling/markets/blockchain_utils.py +37 -19
- prediction_market_agent_tooling/markets/data_models.py +120 -7
- prediction_market_agent_tooling/markets/manifold/data_models.py +5 -3
- prediction_market_agent_tooling/markets/manifold/manifold.py +21 -2
- prediction_market_agent_tooling/markets/manifold/utils.py +8 -2
- prediction_market_agent_tooling/markets/market_type.py +74 -0
- prediction_market_agent_tooling/markets/markets.py +7 -99
- prediction_market_agent_tooling/markets/metaculus/data_models.py +3 -3
- prediction_market_agent_tooling/markets/metaculus/metaculus.py +5 -8
- prediction_market_agent_tooling/markets/omen/cow_contracts.py +5 -1
- prediction_market_agent_tooling/markets/omen/data_models.py +63 -32
- prediction_market_agent_tooling/markets/omen/omen.py +112 -23
- prediction_market_agent_tooling/markets/omen/omen_constants.py +8 -0
- prediction_market_agent_tooling/markets/omen/omen_contracts.py +18 -203
- prediction_market_agent_tooling/markets/omen/omen_resolving.py +33 -13
- prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +23 -18
- prediction_market_agent_tooling/markets/polymarket/api.py +123 -100
- prediction_market_agent_tooling/markets/polymarket/clob_manager.py +156 -0
- prediction_market_agent_tooling/markets/polymarket/constants.py +15 -0
- prediction_market_agent_tooling/markets/polymarket/data_models.py +95 -19
- prediction_market_agent_tooling/markets/polymarket/polymarket.py +373 -29
- prediction_market_agent_tooling/markets/polymarket/polymarket_contracts.py +35 -0
- prediction_market_agent_tooling/markets/polymarket/polymarket_subgraph_handler.py +91 -0
- prediction_market_agent_tooling/markets/polymarket/utils.py +1 -22
- prediction_market_agent_tooling/markets/seer/data_models.py +111 -17
- prediction_market_agent_tooling/markets/seer/exceptions.py +2 -0
- prediction_market_agent_tooling/markets/seer/price_manager.py +165 -50
- prediction_market_agent_tooling/markets/seer/seer.py +393 -106
- prediction_market_agent_tooling/markets/seer/seer_api.py +28 -0
- prediction_market_agent_tooling/markets/seer/seer_contracts.py +115 -5
- prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +297 -66
- prediction_market_agent_tooling/markets/seer/subgraph_data_models.py +43 -8
- prediction_market_agent_tooling/markets/seer/swap_pool_handler.py +80 -0
- prediction_market_agent_tooling/tools/_generic_value.py +8 -2
- prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +271 -8
- prediction_market_agent_tooling/tools/betting_strategies/utils.py +6 -1
- prediction_market_agent_tooling/tools/caches/db_cache.py +219 -117
- prediction_market_agent_tooling/tools/caches/serializers.py +11 -2
- prediction_market_agent_tooling/tools/contract.py +480 -38
- prediction_market_agent_tooling/tools/contract_utils.py +61 -0
- prediction_market_agent_tooling/tools/cow/cow_order.py +218 -45
- prediction_market_agent_tooling/tools/cow/models.py +122 -0
- prediction_market_agent_tooling/tools/cow/semaphore.py +104 -0
- prediction_market_agent_tooling/tools/datetime_utc.py +14 -2
- prediction_market_agent_tooling/tools/db/db_manager.py +59 -0
- prediction_market_agent_tooling/tools/hexbytes_custom.py +4 -1
- prediction_market_agent_tooling/tools/httpx_cached_client.py +15 -6
- prediction_market_agent_tooling/tools/langfuse_client_utils.py +21 -8
- prediction_market_agent_tooling/tools/openai_utils.py +31 -0
- prediction_market_agent_tooling/tools/perplexity/perplexity_client.py +86 -0
- prediction_market_agent_tooling/tools/perplexity/perplexity_models.py +26 -0
- prediction_market_agent_tooling/tools/perplexity/perplexity_search.py +73 -0
- prediction_market_agent_tooling/tools/rephrase.py +71 -0
- prediction_market_agent_tooling/tools/singleton.py +11 -6
- prediction_market_agent_tooling/tools/streamlit_utils.py +188 -0
- prediction_market_agent_tooling/tools/tokens/auto_deposit.py +64 -0
- prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +8 -0
- prediction_market_agent_tooling/tools/tokens/slippage.py +21 -0
- prediction_market_agent_tooling/tools/tokens/usd.py +5 -2
- prediction_market_agent_tooling/tools/utils.py +61 -3
- prediction_market_agent_tooling/tools/web3_utils.py +63 -9
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/METADATA +13 -9
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/RECORD +86 -64
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/WHEEL +1 -1
- prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +0 -171
- prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -420
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/entry_points.txt +0 -0
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,420 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Autogenerated using `datamodel-codegen` from a single Polymarket response. Then adjusted, fixed.
|
|
3
|
-
Keep in mind that not all fields were used so far, so there might be some bugs.
|
|
4
|
-
|
|
5
|
-
These models are based on what Polymarket's website returns in the response, and `prediction_market_agent_tooling/markets/polymarket/data_models.py` are based on what their API returns.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import json
|
|
9
|
-
import typing as t
|
|
10
|
-
|
|
11
|
-
import requests
|
|
12
|
-
from pydantic import BaseModel, field_validator
|
|
13
|
-
|
|
14
|
-
from prediction_market_agent_tooling.gtypes import USDC, HexAddress, OutcomeStr
|
|
15
|
-
from prediction_market_agent_tooling.loggers import logger
|
|
16
|
-
from prediction_market_agent_tooling.markets.data_models import Resolution
|
|
17
|
-
from prediction_market_agent_tooling.tools.utils import DatetimeUTC
|
|
18
|
-
|
|
19
|
-
POLYMARKET_BASE_URL = "https://polymarket.com"
|
|
20
|
-
POLYMARKET_TRUE_OUTCOME = "Yes"
|
|
21
|
-
POLYMARKET_FALSE_OUTCOME = "No"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class ImageOptimized(BaseModel):
|
|
25
|
-
imageUrlOptimized: str
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class IconOptimized(BaseModel):
|
|
29
|
-
imageUrlOptimized: str
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class Event(BaseModel):
|
|
33
|
-
id: str
|
|
34
|
-
slug: str
|
|
35
|
-
ticker: str
|
|
36
|
-
title: str
|
|
37
|
-
series: t.Any | None = None
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class Event1(BaseModel):
|
|
41
|
-
startDate: DatetimeUTC | None = None
|
|
42
|
-
slug: str
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class Market1(BaseModel):
|
|
46
|
-
slug: str
|
|
47
|
-
question: str
|
|
48
|
-
image: str
|
|
49
|
-
volume: USDC | None = None
|
|
50
|
-
outcomes: t.Sequence[OutcomeStr]
|
|
51
|
-
outcomePrices: list[USDC]
|
|
52
|
-
active: bool
|
|
53
|
-
archived: bool
|
|
54
|
-
closed: bool
|
|
55
|
-
orderPriceMinTickSize: USDC
|
|
56
|
-
clobTokenIds: str
|
|
57
|
-
events: list[Event1] | None = None
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class ResolutionData(BaseModel):
|
|
61
|
-
id: str
|
|
62
|
-
author: str
|
|
63
|
-
lastUpdateTimestamp: int
|
|
64
|
-
status: str
|
|
65
|
-
wasDisputed: bool
|
|
66
|
-
price: str
|
|
67
|
-
proposedPrice: str
|
|
68
|
-
reproposedPrice: str
|
|
69
|
-
updates: str
|
|
70
|
-
newVersionQ: bool
|
|
71
|
-
transactionHash: str
|
|
72
|
-
logIndex: str
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class Market(BaseModel):
|
|
76
|
-
id: str
|
|
77
|
-
question: str
|
|
78
|
-
conditionId: str
|
|
79
|
-
slug: str
|
|
80
|
-
twitterCardImage: t.Any | None = None
|
|
81
|
-
resolutionSource: str | None = None
|
|
82
|
-
endDate: DatetimeUTC
|
|
83
|
-
category: t.Any | None = None
|
|
84
|
-
ammType: t.Any | None = None
|
|
85
|
-
description: str
|
|
86
|
-
liquidity: str | None = None
|
|
87
|
-
startDate: DatetimeUTC | None = None
|
|
88
|
-
createdAt: DatetimeUTC
|
|
89
|
-
xAxisValue: t.Any | None = None
|
|
90
|
-
yAxisValue: t.Any | None = None
|
|
91
|
-
denominationToken: t.Any | None = None
|
|
92
|
-
fee: str | None = None
|
|
93
|
-
lowerBound: t.Any | None = None
|
|
94
|
-
upperBound: t.Any | None = None
|
|
95
|
-
outcomes: t.Sequence[OutcomeStr]
|
|
96
|
-
image: str | None = None
|
|
97
|
-
icon: str | None = None
|
|
98
|
-
imageOptimized: t.Any | None = None
|
|
99
|
-
iconOptimized: t.Any | None = None
|
|
100
|
-
outcomePrices: list[USDC]
|
|
101
|
-
volume: USDC | None = None
|
|
102
|
-
active: bool
|
|
103
|
-
marketType: str | None = None
|
|
104
|
-
formatType: t.Any | None = None
|
|
105
|
-
lowerBoundDate: t.Any | None = None
|
|
106
|
-
upperBoundDate: t.Any | None = None
|
|
107
|
-
closed: bool
|
|
108
|
-
marketMakerAddress: HexAddress
|
|
109
|
-
closedTime: DatetimeUTC | None = None
|
|
110
|
-
wideFormat: bool | None = None
|
|
111
|
-
new: bool | None = None
|
|
112
|
-
sentDiscord: t.Any | None = None
|
|
113
|
-
mailchimpTag: t.Any | None = None
|
|
114
|
-
featured: bool | None = None
|
|
115
|
-
submitted_by: str | None = None
|
|
116
|
-
subcategory: t.Any | None = None
|
|
117
|
-
categoryMailchimpTag: t.Any | None = None
|
|
118
|
-
archived: bool | None = None
|
|
119
|
-
resolvedBy: str | None = None
|
|
120
|
-
restricted: bool | None = None
|
|
121
|
-
groupItemTitle: str | None = None
|
|
122
|
-
groupItemThreshold: str | None = None
|
|
123
|
-
questionID: str | None = None
|
|
124
|
-
umaEndDate: t.Any | None = None
|
|
125
|
-
enableOrderBook: bool | None = None
|
|
126
|
-
orderPriceMinTickSize: float | None = None
|
|
127
|
-
orderMinSize: int | None = None
|
|
128
|
-
umaResolutionStatus: t.Any | None = None
|
|
129
|
-
curationOrder: t.Any | None = None
|
|
130
|
-
volumeNum: USDC | None = None
|
|
131
|
-
liquidityNum: float | None = None
|
|
132
|
-
endDateIso: DatetimeUTC | None = None
|
|
133
|
-
startDateIso: DatetimeUTC | None = None
|
|
134
|
-
umaEndDateIso: DatetimeUTC | None = None
|
|
135
|
-
commentsEnabled: bool | None = None
|
|
136
|
-
disqusThread: t.Any | None = None
|
|
137
|
-
gameStartTime: t.Any | None = None
|
|
138
|
-
secondsDelay: int | None = None
|
|
139
|
-
clobTokenIds: list[str] | None = None
|
|
140
|
-
liquidityAmm: float | None = None
|
|
141
|
-
liquidityClob: float | None = None
|
|
142
|
-
makerBaseFee: int | None = None
|
|
143
|
-
takerBaseFee: int | None = None
|
|
144
|
-
negRisk: t.Any | None = None
|
|
145
|
-
negRiskRequestID: t.Any | None = None
|
|
146
|
-
negRiskMarketID: t.Any | None = None
|
|
147
|
-
events: list[Event] | None = None
|
|
148
|
-
markets: list[Market1] | None = None
|
|
149
|
-
lower_bound_date: t.Any | None = None
|
|
150
|
-
upper_bound_date: t.Any | None = None
|
|
151
|
-
market_type: str | None = None
|
|
152
|
-
resolution_source: str | None = None
|
|
153
|
-
end_date: str | None = None
|
|
154
|
-
amm_type: t.Any | None = None
|
|
155
|
-
x_axis_value: t.Any | None = None
|
|
156
|
-
y_axis_value: t.Any | None = None
|
|
157
|
-
denomination_token: t.Any | None = None
|
|
158
|
-
resolved_by: str | None = None
|
|
159
|
-
upper_bound: t.Any | None = None
|
|
160
|
-
lower_bound: t.Any | None = None
|
|
161
|
-
created_at: str | None = None
|
|
162
|
-
updated_at: t.Any | None = None
|
|
163
|
-
closed_time: t.Any | None = None
|
|
164
|
-
wide_format: bool | None = None
|
|
165
|
-
volume_num: USDC | None = None
|
|
166
|
-
liquidity_num: USDC | None = None
|
|
167
|
-
image_raw: str | None = None
|
|
168
|
-
resolutionData: ResolutionData
|
|
169
|
-
|
|
170
|
-
@field_validator("closedTime", mode="before")
|
|
171
|
-
def field_validator_closedTime(cls, v: str | None = None) -> str | None:
|
|
172
|
-
return v.replace("+00", "") if v else None
|
|
173
|
-
|
|
174
|
-
@property
|
|
175
|
-
def resolution(self) -> Resolution | None:
|
|
176
|
-
# If the market is not closed, it doesn't have a resolution.
|
|
177
|
-
if not self.closed:
|
|
178
|
-
return None
|
|
179
|
-
|
|
180
|
-
outcome_to_outcome_price: dict[str, USDC] = dict(
|
|
181
|
-
zip(self.outcomes, self.outcomePrices)
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
# On Polymarket, we can find out binary market resolution by checking for the outcome prices.
|
|
185
|
-
# E.g. if `Yes` price (probability) is 1$ and `No` price (probability) is 0$, it means the resolution is `Yes`.
|
|
186
|
-
if (
|
|
187
|
-
outcome_to_outcome_price[POLYMARKET_TRUE_OUTCOME] == 1.0
|
|
188
|
-
and outcome_to_outcome_price[POLYMARKET_FALSE_OUTCOME] == 0.0
|
|
189
|
-
):
|
|
190
|
-
return Resolution(
|
|
191
|
-
outcome=OutcomeStr(POLYMARKET_TRUE_OUTCOME), invalid=False
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
elif (
|
|
195
|
-
outcome_to_outcome_price[POLYMARKET_TRUE_OUTCOME] == 0.0
|
|
196
|
-
and outcome_to_outcome_price[POLYMARKET_FALSE_OUTCOME] == 1.0
|
|
197
|
-
):
|
|
198
|
-
return Resolution(
|
|
199
|
-
outcome=OutcomeStr(POLYMARKET_FALSE_OUTCOME), invalid=False
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
else:
|
|
203
|
-
raise ValueError(
|
|
204
|
-
f"Unexpected outcome prices {outcome_to_outcome_price} or outcomes {self.outcomes}, please debug."
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
class Category(BaseModel):
|
|
209
|
-
id: str
|
|
210
|
-
label: str
|
|
211
|
-
parentCategory: str
|
|
212
|
-
slug: str
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
class Bid(BaseModel):
|
|
216
|
-
price: str
|
|
217
|
-
size: str
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
class Ask(BaseModel):
|
|
221
|
-
price: str
|
|
222
|
-
size: str
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
class MarketBidsAndAsks(BaseModel):
|
|
226
|
-
market: str
|
|
227
|
-
asset_id: str
|
|
228
|
-
hash: str
|
|
229
|
-
bids: list[Bid]
|
|
230
|
-
asks: list[Ask]
|
|
231
|
-
lastUpdated: int
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
class PolymarketFullMarket(BaseModel):
|
|
235
|
-
id: str
|
|
236
|
-
ticker: str
|
|
237
|
-
slug: str
|
|
238
|
-
title: str
|
|
239
|
-
subtitle: t.Any | None = None
|
|
240
|
-
description: str
|
|
241
|
-
commentCount: int | None = None
|
|
242
|
-
resolutionSource: str | None = None
|
|
243
|
-
startDate: DatetimeUTC | None = None
|
|
244
|
-
endDate: DatetimeUTC
|
|
245
|
-
image: str | None = None
|
|
246
|
-
icon: str | None = None
|
|
247
|
-
featuredImage: str | None = None
|
|
248
|
-
active: bool
|
|
249
|
-
closed: bool
|
|
250
|
-
archived: bool | None = None
|
|
251
|
-
new: bool | None = None
|
|
252
|
-
featured: bool | None = None
|
|
253
|
-
restricted: bool | None = None
|
|
254
|
-
liquidity: USDC | None = None
|
|
255
|
-
volume: USDC | None = None
|
|
256
|
-
volume24hr: USDC | None = None
|
|
257
|
-
competitive: float | None = None
|
|
258
|
-
openInterest: int | None = None
|
|
259
|
-
sortBy: str | None = None
|
|
260
|
-
createdAt: DatetimeUTC
|
|
261
|
-
commentsEnabled: bool | None = None
|
|
262
|
-
disqusThread: t.Any | None = None
|
|
263
|
-
updatedAt: DatetimeUTC
|
|
264
|
-
enableOrderBook: bool | None = None
|
|
265
|
-
liquidityAmm: float | None = None
|
|
266
|
-
liquidityClob: float | None = None
|
|
267
|
-
imageOptimized: ImageOptimized | None = None
|
|
268
|
-
iconOptimized: IconOptimized | None = None
|
|
269
|
-
featuredImageOptimized: str | None = None
|
|
270
|
-
negRisk: t.Any | None = None
|
|
271
|
-
negRiskMarketID: t.Any | None = None
|
|
272
|
-
negRiskFeeBips: t.Any | None = None
|
|
273
|
-
markets: list[Market]
|
|
274
|
-
categories: list[Category] | None = None
|
|
275
|
-
series: t.Any | None = None
|
|
276
|
-
image_raw: str | None = None
|
|
277
|
-
|
|
278
|
-
@property
|
|
279
|
-
def url(self) -> str:
|
|
280
|
-
return construct_polymarket_url(self.slug)
|
|
281
|
-
|
|
282
|
-
@property
|
|
283
|
-
def is_main_market(self) -> bool:
|
|
284
|
-
# On Polymarket, there are markets that are actually a group of multiple Yes/No markets, for example https://polymarket.com/event/presidential-election-winner-2024.
|
|
285
|
-
# But if there is only 1 market in this list, it should mean it's a "main market", e.g. with only one question.
|
|
286
|
-
return len(self.markets) == 1
|
|
287
|
-
|
|
288
|
-
@property
|
|
289
|
-
def main_market(self) -> Market:
|
|
290
|
-
if not self.is_main_market:
|
|
291
|
-
raise ValueError(
|
|
292
|
-
f"Unexpected number of markets in the Polymarket's response, shouldn't happen if you used `is_main_market` filter, please debug: {self.id=}, {self.title=}"
|
|
293
|
-
)
|
|
294
|
-
return self.markets[0]
|
|
295
|
-
|
|
296
|
-
@staticmethod
|
|
297
|
-
def fetch_from_url(url: str) -> "PolymarketFullMarket | None":
|
|
298
|
-
"""
|
|
299
|
-
Get the full market data from the Polymarket website.
|
|
300
|
-
|
|
301
|
-
Returns None if this market's url returns "Oops...we didn't forecast this", see `check_if_its_a_main_market` method for more details.
|
|
302
|
-
|
|
303
|
-
Warning: This is a very slow operation, as it requires fetching the website. Use it only when necessary.
|
|
304
|
-
"""
|
|
305
|
-
logger.info(f"Fetching full market from {url}")
|
|
306
|
-
|
|
307
|
-
# Fetch the website as a normal browser would.
|
|
308
|
-
headers = {
|
|
309
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
|
310
|
-
}
|
|
311
|
-
content = requests.get(url, headers=headers).text
|
|
312
|
-
|
|
313
|
-
# Find the JSON with the data within the content.
|
|
314
|
-
start_tag = """<script id="__NEXT_DATA__" type="application/json" crossorigin="anonymous">"""
|
|
315
|
-
start_idx = content.find(start_tag) + len(start_tag)
|
|
316
|
-
end_idx = content.find("</script>", start_idx)
|
|
317
|
-
response_data = content[start_idx:end_idx]
|
|
318
|
-
|
|
319
|
-
# Parsing.
|
|
320
|
-
response_dict = json.loads(response_data)
|
|
321
|
-
response_model = PolymarketWebResponse.model_validate(response_dict)
|
|
322
|
-
|
|
323
|
-
full_market_queries = [
|
|
324
|
-
q
|
|
325
|
-
for q in response_model.props.pageProps.dehydratedState.queries
|
|
326
|
-
if isinstance(q.state.data, PolymarketFullMarket)
|
|
327
|
-
]
|
|
328
|
-
|
|
329
|
-
# We expect either 0 markets (if it doesn't exist) or 1 market.
|
|
330
|
-
if len(full_market_queries) not in (0, 1):
|
|
331
|
-
raise ValueError(
|
|
332
|
-
f"Unexpected number of queries in the response, please check it out and modify the code accordingly: `{response_dict}`"
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
# It will be `PolymarketFullMarket` thanks to the filter above.
|
|
336
|
-
market = (
|
|
337
|
-
t.cast(PolymarketFullMarket, full_market_queries[0].state.data)
|
|
338
|
-
if full_market_queries
|
|
339
|
-
else None
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
if market is None:
|
|
343
|
-
logger.warning(f"No polymarket found for {url}")
|
|
344
|
-
|
|
345
|
-
return market
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
class PriceSide(BaseModel):
|
|
349
|
-
price: USDC
|
|
350
|
-
side: t.Literal["BUY", "SELL"]
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
class State(BaseModel):
|
|
354
|
-
data: (
|
|
355
|
-
PolymarketFullMarket
|
|
356
|
-
| MarketBidsAndAsks
|
|
357
|
-
| PriceSide
|
|
358
|
-
| dict[str, MarketBidsAndAsks]
|
|
359
|
-
| dict[str, PriceSide]
|
|
360
|
-
| None
|
|
361
|
-
# It's none if you go to the website and it says "Oops...we didn't forecast this".
|
|
362
|
-
)
|
|
363
|
-
dataUpdateCount: int
|
|
364
|
-
dataUpdatedAt: int
|
|
365
|
-
error: t.Any | None = None
|
|
366
|
-
errorUpdateCount: int
|
|
367
|
-
errorUpdatedAt: int
|
|
368
|
-
fetchFailureCount: int
|
|
369
|
-
fetchFailureReason: t.Any | None = None
|
|
370
|
-
fetchMeta: t.Any | None = None
|
|
371
|
-
isInvalidated: bool
|
|
372
|
-
status: str
|
|
373
|
-
fetchStatus: str
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
class Query(BaseModel):
|
|
377
|
-
state: State
|
|
378
|
-
queryKey: list[str]
|
|
379
|
-
queryHash: str
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
class DehydratedState(BaseModel):
|
|
383
|
-
mutations: list[t.Any]
|
|
384
|
-
queries: list[Query]
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
class PageProps(BaseModel):
|
|
388
|
-
key: str
|
|
389
|
-
dehydratedState: DehydratedState
|
|
390
|
-
eslug: str
|
|
391
|
-
mslug: str | None = None
|
|
392
|
-
isSingleMarket: bool
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
class Props(BaseModel):
|
|
396
|
-
pageProps: PageProps
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
class Query1(BaseModel):
|
|
400
|
-
slug: list[str]
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
class PolymarketWebResponse(BaseModel):
|
|
404
|
-
props: Props
|
|
405
|
-
page: str
|
|
406
|
-
query: Query1
|
|
407
|
-
buildId: str
|
|
408
|
-
isFallback: bool
|
|
409
|
-
gsp: bool
|
|
410
|
-
locale: str
|
|
411
|
-
locales: list[str]
|
|
412
|
-
defaultLocale: str
|
|
413
|
-
scriptLoader: list[t.Any]
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
def construct_polymarket_url(slug: str) -> str:
|
|
417
|
-
"""
|
|
418
|
-
Note: This works only if it's a single main market, not sub-market of some more general question.
|
|
419
|
-
"""
|
|
420
|
-
return f"{POLYMARKET_BASE_URL}/event/{slug}"
|
|
File without changes
|