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.
Files changed (88) hide show
  1. prediction_market_agent_tooling/abis/agentresultmapping.abi.json +192 -0
  2. prediction_market_agent_tooling/abis/erc1155.abi.json +352 -0
  3. prediction_market_agent_tooling/abis/processor.abi.json +16 -0
  4. prediction_market_agent_tooling/abis/swapr_quoter.abi.json +221 -0
  5. prediction_market_agent_tooling/abis/swapr_router.abi.json +634 -0
  6. prediction_market_agent_tooling/benchmark/benchmark.py +1 -1
  7. prediction_market_agent_tooling/benchmark/utils.py +13 -0
  8. prediction_market_agent_tooling/chains.py +1 -0
  9. prediction_market_agent_tooling/config.py +61 -2
  10. prediction_market_agent_tooling/data_download/langfuse_data_downloader.py +405 -0
  11. prediction_market_agent_tooling/deploy/agent.py +199 -67
  12. prediction_market_agent_tooling/deploy/agent_example.py +1 -1
  13. prediction_market_agent_tooling/deploy/betting_strategy.py +412 -68
  14. prediction_market_agent_tooling/deploy/constants.py +6 -0
  15. prediction_market_agent_tooling/gtypes.py +11 -1
  16. prediction_market_agent_tooling/jobs/jobs_models.py +2 -2
  17. prediction_market_agent_tooling/jobs/omen/omen_jobs.py +19 -20
  18. prediction_market_agent_tooling/loggers.py +9 -1
  19. prediction_market_agent_tooling/logprobs_parser.py +2 -1
  20. prediction_market_agent_tooling/markets/agent_market.py +106 -18
  21. prediction_market_agent_tooling/markets/blockchain_utils.py +37 -19
  22. prediction_market_agent_tooling/markets/data_models.py +120 -7
  23. prediction_market_agent_tooling/markets/manifold/data_models.py +5 -3
  24. prediction_market_agent_tooling/markets/manifold/manifold.py +21 -2
  25. prediction_market_agent_tooling/markets/manifold/utils.py +8 -2
  26. prediction_market_agent_tooling/markets/market_type.py +74 -0
  27. prediction_market_agent_tooling/markets/markets.py +7 -99
  28. prediction_market_agent_tooling/markets/metaculus/data_models.py +3 -3
  29. prediction_market_agent_tooling/markets/metaculus/metaculus.py +5 -8
  30. prediction_market_agent_tooling/markets/omen/cow_contracts.py +5 -1
  31. prediction_market_agent_tooling/markets/omen/data_models.py +63 -32
  32. prediction_market_agent_tooling/markets/omen/omen.py +112 -23
  33. prediction_market_agent_tooling/markets/omen/omen_constants.py +8 -0
  34. prediction_market_agent_tooling/markets/omen/omen_contracts.py +18 -203
  35. prediction_market_agent_tooling/markets/omen/omen_resolving.py +33 -13
  36. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +23 -18
  37. prediction_market_agent_tooling/markets/polymarket/api.py +123 -100
  38. prediction_market_agent_tooling/markets/polymarket/clob_manager.py +156 -0
  39. prediction_market_agent_tooling/markets/polymarket/constants.py +15 -0
  40. prediction_market_agent_tooling/markets/polymarket/data_models.py +95 -19
  41. prediction_market_agent_tooling/markets/polymarket/polymarket.py +373 -29
  42. prediction_market_agent_tooling/markets/polymarket/polymarket_contracts.py +35 -0
  43. prediction_market_agent_tooling/markets/polymarket/polymarket_subgraph_handler.py +91 -0
  44. prediction_market_agent_tooling/markets/polymarket/utils.py +1 -22
  45. prediction_market_agent_tooling/markets/seer/data_models.py +111 -17
  46. prediction_market_agent_tooling/markets/seer/exceptions.py +2 -0
  47. prediction_market_agent_tooling/markets/seer/price_manager.py +165 -50
  48. prediction_market_agent_tooling/markets/seer/seer.py +393 -106
  49. prediction_market_agent_tooling/markets/seer/seer_api.py +28 -0
  50. prediction_market_agent_tooling/markets/seer/seer_contracts.py +115 -5
  51. prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +297 -66
  52. prediction_market_agent_tooling/markets/seer/subgraph_data_models.py +43 -8
  53. prediction_market_agent_tooling/markets/seer/swap_pool_handler.py +80 -0
  54. prediction_market_agent_tooling/tools/_generic_value.py +8 -2
  55. prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +271 -8
  56. prediction_market_agent_tooling/tools/betting_strategies/utils.py +6 -1
  57. prediction_market_agent_tooling/tools/caches/db_cache.py +219 -117
  58. prediction_market_agent_tooling/tools/caches/serializers.py +11 -2
  59. prediction_market_agent_tooling/tools/contract.py +480 -38
  60. prediction_market_agent_tooling/tools/contract_utils.py +61 -0
  61. prediction_market_agent_tooling/tools/cow/cow_order.py +218 -45
  62. prediction_market_agent_tooling/tools/cow/models.py +122 -0
  63. prediction_market_agent_tooling/tools/cow/semaphore.py +104 -0
  64. prediction_market_agent_tooling/tools/datetime_utc.py +14 -2
  65. prediction_market_agent_tooling/tools/db/db_manager.py +59 -0
  66. prediction_market_agent_tooling/tools/hexbytes_custom.py +4 -1
  67. prediction_market_agent_tooling/tools/httpx_cached_client.py +15 -6
  68. prediction_market_agent_tooling/tools/langfuse_client_utils.py +21 -8
  69. prediction_market_agent_tooling/tools/openai_utils.py +31 -0
  70. prediction_market_agent_tooling/tools/perplexity/perplexity_client.py +86 -0
  71. prediction_market_agent_tooling/tools/perplexity/perplexity_models.py +26 -0
  72. prediction_market_agent_tooling/tools/perplexity/perplexity_search.py +73 -0
  73. prediction_market_agent_tooling/tools/rephrase.py +71 -0
  74. prediction_market_agent_tooling/tools/singleton.py +11 -6
  75. prediction_market_agent_tooling/tools/streamlit_utils.py +188 -0
  76. prediction_market_agent_tooling/tools/tokens/auto_deposit.py +64 -0
  77. prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +8 -0
  78. prediction_market_agent_tooling/tools/tokens/slippage.py +21 -0
  79. prediction_market_agent_tooling/tools/tokens/usd.py +5 -2
  80. prediction_market_agent_tooling/tools/utils.py +61 -3
  81. prediction_market_agent_tooling/tools/web3_utils.py +63 -9
  82. {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/METADATA +13 -9
  83. {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/RECORD +86 -64
  84. {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/WHEEL +1 -1
  85. prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +0 -171
  86. prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -420
  87. {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/entry_points.txt +0 -0
  88. {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}"