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,11 +1,15 @@
1
1
  from enum import Enum
2
- from typing import Annotated
2
+ from typing import Annotated, Any, Sequence
3
3
 
4
- from pydantic import BaseModel, BeforeValidator, computed_field
4
+ from pydantic import BaseModel, BeforeValidator, computed_field, model_validator
5
5
 
6
6
  from prediction_market_agent_tooling.deploy.constants import (
7
+ DOWN_OUTCOME_LOWERCASE_IDENTIFIER,
8
+ INVALID_OUTCOME_LOWERCASE_IDENTIFIER,
7
9
  NO_OUTCOME_LOWERCASE_IDENTIFIER,
10
+ UP_OUTCOME_LOWERCASE_IDENTIFIER,
8
11
  YES_OUTCOME_LOWERCASE_IDENTIFIER,
12
+ is_invalid_outcome,
9
13
  )
10
14
  from prediction_market_agent_tooling.gtypes import (
11
15
  USD,
@@ -13,8 +17,13 @@ from prediction_market_agent_tooling.gtypes import (
13
17
  OutcomeStr,
14
18
  OutcomeToken,
15
19
  Probability,
20
+ Wei,
16
21
  )
17
22
  from prediction_market_agent_tooling.logprobs_parser import FieldLogprobs
23
+ from prediction_market_agent_tooling.markets.omen.omen_constants import (
24
+ OMEN_FALSE_OUTCOME,
25
+ OMEN_TRUE_OUTCOME,
26
+ )
18
27
  from prediction_market_agent_tooling.tools.utils import DatetimeUTC, check_not_none
19
28
 
20
29
 
@@ -26,6 +35,26 @@ class Resolution(BaseModel):
26
35
  def from_answer(answer: OutcomeStr) -> "Resolution":
27
36
  return Resolution(outcome=answer, invalid=False)
28
37
 
38
+ def find_outcome_matching_market(
39
+ self, market_outcomes: Sequence[OutcomeStr]
40
+ ) -> OutcomeStr | None:
41
+ """
42
+ Finds a matching outcome in the provided market outcomes.
43
+
44
+ Performs case-insensitive matching between this resolution's outcome
45
+ and the provided market outcomes.
46
+
47
+ """
48
+
49
+ if not self.outcome:
50
+ return None
51
+
52
+ normalized_outcome = self.outcome.lower()
53
+ for outcome in market_outcomes:
54
+ if outcome.lower() == normalized_outcome:
55
+ return outcome
56
+ return None
57
+
29
58
 
30
59
  class Bet(BaseModel):
31
60
  id: str
@@ -76,6 +105,31 @@ def to_boolean_outcome(value: str | bool) -> bool:
76
105
  Decision = Annotated[bool, BeforeValidator(to_boolean_outcome)]
77
106
 
78
107
 
108
+ class ScalarProbabilisticAnswer(BaseModel):
109
+ scalar_value: Wei
110
+ upperBound: Wei
111
+ lowerBound: Wei
112
+ confidence: float
113
+ reasoning: str | None = None
114
+ logprobs: list[FieldLogprobs] | None = None
115
+
116
+ @property
117
+ def p_up(self) -> Probability:
118
+ if self.scalar_value > self.upperBound:
119
+ return Probability(1)
120
+ elif self.scalar_value < self.lowerBound:
121
+ return Probability(0)
122
+ else:
123
+ return Probability(
124
+ (self.scalar_value - self.lowerBound)
125
+ / (self.upperBound - self.lowerBound)
126
+ )
127
+
128
+ @property
129
+ def p_down(self) -> Probability:
130
+ return Probability(1 - self.p_up)
131
+
132
+
79
133
  class ProbabilisticAnswer(BaseModel):
80
134
  p_yes: Probability
81
135
  confidence: float
@@ -104,6 +158,15 @@ class CategoricalProbabilisticAnswer(BaseModel):
104
158
  confidence: float
105
159
  reasoning: str | None = None
106
160
 
161
+ @model_validator(mode="before")
162
+ @classmethod
163
+ def _model_validator(cls, data: Any) -> Any:
164
+ if "p_yes" in data:
165
+ return CategoricalProbabilisticAnswer.from_probabilistic_answer(
166
+ ProbabilisticAnswer.model_validate(data)
167
+ ).model_dump()
168
+ return data
169
+
107
170
  @property
108
171
  def probable_resolution(self) -> Resolution:
109
172
  most_likely_outcome = max(
@@ -122,18 +185,57 @@ class CategoricalProbabilisticAnswer(BaseModel):
122
185
  @staticmethod
123
186
  def from_probabilistic_answer(
124
187
  answer: ProbabilisticAnswer,
188
+ market_outcomes: Sequence[OutcomeStr] | None = None,
125
189
  ) -> "CategoricalProbabilisticAnswer":
126
190
  return CategoricalProbabilisticAnswer(
127
191
  probabilities={
128
- OutcomeStr(YES_OUTCOME_LOWERCASE_IDENTIFIER): answer.p_yes,
129
- OutcomeStr(NO_OUTCOME_LOWERCASE_IDENTIFIER): Probability(
130
- 1 - answer.p_yes
131
- ),
192
+ (
193
+ OMEN_TRUE_OUTCOME
194
+ if market_outcomes and OMEN_TRUE_OUTCOME in market_outcomes
195
+ else OutcomeStr(YES_OUTCOME_LOWERCASE_IDENTIFIER)
196
+ ): answer.p_yes,
197
+ (
198
+ OMEN_FALSE_OUTCOME
199
+ if market_outcomes and OMEN_FALSE_OUTCOME in market_outcomes
200
+ else OutcomeStr(NO_OUTCOME_LOWERCASE_IDENTIFIER)
201
+ ): Probability(1 - answer.p_yes),
132
202
  },
133
203
  confidence=answer.confidence,
134
204
  reasoning=answer.reasoning,
135
205
  )
136
206
 
207
+ @staticmethod
208
+ def from_scalar_answer(
209
+ answer: ScalarProbabilisticAnswer,
210
+ market_outcomes: Sequence[OutcomeStr],
211
+ ) -> "CategoricalProbabilisticAnswer":
212
+ probabilities = {}
213
+ lowercase_market_outcomes = [outcome.lower() for outcome in market_outcomes]
214
+
215
+ if not set(
216
+ [
217
+ DOWN_OUTCOME_LOWERCASE_IDENTIFIER,
218
+ UP_OUTCOME_LOWERCASE_IDENTIFIER,
219
+ ]
220
+ ).issubset(lowercase_market_outcomes):
221
+ raise ValueError("Market with no outcomes")
222
+
223
+ probabilities[OutcomeStr(UP_OUTCOME_LOWERCASE_IDENTIFIER.upper())] = answer.p_up
224
+ probabilities[
225
+ OutcomeStr(DOWN_OUTCOME_LOWERCASE_IDENTIFIER.upper())
226
+ ] = answer.p_down
227
+
228
+ if market_outcomes and any(is_invalid_outcome(o) for o in market_outcomes):
229
+ probabilities[
230
+ OutcomeStr(INVALID_OUTCOME_LOWERCASE_IDENTIFIER.capitalize())
231
+ ] = Probability(1 - answer.p_up - answer.p_down)
232
+
233
+ return CategoricalProbabilisticAnswer(
234
+ probabilities=probabilities,
235
+ confidence=answer.confidence,
236
+ reasoning=answer.reasoning,
237
+ )
238
+
137
239
  def probability_for_market_outcome(self, market_outcome: OutcomeStr) -> Probability:
138
240
  for k, v in self.probabilities.items():
139
241
  if k.lower() == market_outcome.lower():
@@ -195,9 +297,20 @@ class Trade(BaseModel):
195
297
  outcome: OutcomeStr
196
298
  amount: USD
197
299
 
300
+ @model_validator(mode="before")
301
+ @classmethod
302
+ def _model_validator(cls, data: Any) -> Any:
303
+ if isinstance(data["outcome"], bool):
304
+ data["outcome"] = (
305
+ YES_OUTCOME_LOWERCASE_IDENTIFIER
306
+ if data["outcome"]
307
+ else NO_OUTCOME_LOWERCASE_IDENTIFIER
308
+ )
309
+ return data
310
+
198
311
 
199
312
  class PlacedTrade(Trade):
200
- id: str | None = None
313
+ id: str
201
314
 
202
315
  @staticmethod
203
316
  def from_trade(trade: Trade, id: str) -> "PlacedTrade":
@@ -12,7 +12,9 @@ from prediction_market_agent_tooling.gtypes import (
12
12
  Probability,
13
13
  )
14
14
  from prediction_market_agent_tooling.markets.data_models import Resolution
15
- from prediction_market_agent_tooling.markets.manifold.utils import validate_resolution
15
+ from prediction_market_agent_tooling.markets.manifold.utils import (
16
+ validate_manifold_resolution,
17
+ )
16
18
  from prediction_market_agent_tooling.tools.utils import DatetimeUTC, should_not_happen
17
19
 
18
20
  MANIFOLD_BASE_URL = "https://manifold.markets"
@@ -110,7 +112,7 @@ class ManifoldMarket(BaseModel):
110
112
 
111
113
  @field_validator("resolution", mode="before")
112
114
  def validate_resolution(cls, v: t.Any) -> Resolution:
113
- return validate_resolution(v)
115
+ return validate_manifold_resolution(v)
114
116
 
115
117
  def __repr__(self) -> str:
116
118
  return f"Manifold's market: {self.question}"
@@ -204,7 +206,7 @@ class ManifoldBet(BaseModel):
204
206
 
205
207
  @field_validator("outcome", mode="before")
206
208
  def validate_resolution(cls, v: t.Any) -> Resolution:
207
- return validate_resolution(v)
209
+ return validate_manifold_resolution(v)
208
210
 
209
211
  def get_resolved_outcome(self) -> OutcomeStr:
210
212
  if self.outcome.outcome:
@@ -1,4 +1,5 @@
1
1
  import typing as t
2
+ from datetime import timedelta
2
3
 
3
4
  from prediction_market_agent_tooling.config import APIKeys
4
5
  from prediction_market_agent_tooling.gtypes import (
@@ -9,12 +10,15 @@ from prediction_market_agent_tooling.gtypes import (
9
10
  )
10
11
  from prediction_market_agent_tooling.markets.agent_market import (
11
12
  AgentMarket,
13
+ ConditionalFilterType,
12
14
  FilterBy,
13
15
  MarketFees,
16
+ QuestionType,
14
17
  SortBy,
15
18
  )
16
19
  from prediction_market_agent_tooling.markets.manifold.api import (
17
20
  get_authenticated_user,
21
+ get_manifold_bets,
18
22
  get_manifold_binary_markets,
19
23
  get_manifold_market,
20
24
  place_bet,
@@ -24,7 +28,7 @@ from prediction_market_agent_tooling.markets.manifold.data_models import (
24
28
  FullManifoldMarket,
25
29
  usd_to_mana,
26
30
  )
27
- from prediction_market_agent_tooling.tools.utils import DatetimeUTC
31
+ from prediction_market_agent_tooling.tools.utils import DatetimeUTC, utcnow
28
32
 
29
33
 
30
34
  class ManifoldAgentMarket(AgentMarket):
@@ -51,6 +55,20 @@ class ManifoldAgentMarket(AgentMarket):
51
55
  def get_tiny_bet_amount(self) -> CollateralToken:
52
56
  return CollateralToken(1)
53
57
 
58
+ def have_bet_on_market_since(self, keys: APIKeys, since: timedelta) -> bool:
59
+ start_time = utcnow() - since
60
+ recently_betted_questions = set(
61
+ get_manifold_market(b.contractId).question
62
+ for b in get_manifold_bets(
63
+ user_id=get_authenticated_user(
64
+ keys.manifold_api_key.get_secret_value()
65
+ ).id,
66
+ start_time=start_time,
67
+ end_time=None,
68
+ )
69
+ )
70
+ return self.question in recently_betted_questions
71
+
54
72
  def place_bet(self, outcome: OutcomeStr, amount: USD) -> str:
55
73
  self.get_usd_in_token(amount)
56
74
  bet = place_bet(
@@ -94,7 +112,8 @@ class ManifoldAgentMarket(AgentMarket):
94
112
  filter_by: FilterBy = FilterBy.OPEN,
95
113
  created_after: t.Optional[DatetimeUTC] = None,
96
114
  excluded_questions: set[str] | None = None,
97
- fetch_categorical_markets: bool = False,
115
+ question_type: QuestionType = QuestionType.ALL,
116
+ conditional_filter_type: ConditionalFilterType = ConditionalFilterType.ONLY_NOT_CONDITIONAL,
98
117
  ) -> t.Sequence["ManifoldAgentMarket"]:
99
118
  sort: t.Literal["newest", "close-date"] | None
100
119
  if sort_by == SortBy.CLOSING_SOONEST:
@@ -3,8 +3,14 @@ import typing as t
3
3
  from prediction_market_agent_tooling.gtypes import OutcomeStr
4
4
  from prediction_market_agent_tooling.markets.data_models import Resolution
5
5
 
6
+ MANIFOLD_CANCEL_OUTCOME = "CANCEL"
6
7
 
7
- def validate_resolution(v: t.Any) -> Resolution:
8
+
9
+ def validate_manifold_resolution(v: t.Any) -> Resolution:
8
10
  if isinstance(v, str):
9
- return Resolution(outcome=OutcomeStr(v), invalid=False)
11
+ return (
12
+ Resolution(outcome=OutcomeStr(v), invalid=False)
13
+ if v != MANIFOLD_CANCEL_OUTCOME
14
+ else Resolution(outcome=None, invalid=True)
15
+ )
10
16
  raise ValueError(f"Expected a string, got {v} {type(v)}")
@@ -0,0 +1,74 @@
1
+ from enum import Enum
2
+ from typing import TypeVar
3
+
4
+ from prediction_market_agent_tooling.jobs.jobs_models import JobAgentMarket
5
+ from prediction_market_agent_tooling.jobs.omen.omen_jobs import OmenJobAgentMarket
6
+ from prediction_market_agent_tooling.markets.agent_market import AgentMarket
7
+ from prediction_market_agent_tooling.markets.manifold.manifold import (
8
+ ManifoldAgentMarket,
9
+ )
10
+ from prediction_market_agent_tooling.markets.metaculus.metaculus import (
11
+ MetaculusAgentMarket,
12
+ )
13
+ from prediction_market_agent_tooling.markets.omen.omen import OmenAgentMarket
14
+ from prediction_market_agent_tooling.markets.polymarket.polymarket import (
15
+ PolymarketAgentMarket,
16
+ )
17
+ from prediction_market_agent_tooling.markets.seer.seer import SeerAgentMarket
18
+
19
+ T = TypeVar("T", bound=AgentMarket)
20
+
21
+
22
+ class MarketType(str, Enum):
23
+ # Note: Always keep the omen market first, as it is the main market for us.
24
+ OMEN = "omen"
25
+ MANIFOLD = "manifold"
26
+ POLYMARKET = "polymarket"
27
+ METACULUS = "metaculus"
28
+ SEER = "seer"
29
+
30
+ @staticmethod
31
+ def from_market(market: AgentMarket) -> "MarketType":
32
+ return AGENT_MARKET_TO_MARKET_TYPE[type(market)]
33
+
34
+ @property
35
+ def market_class(self) -> type[AgentMarket]:
36
+ if self not in MARKET_TYPE_TO_AGENT_MARKET:
37
+ raise ValueError(f"Unknown market type: {self}")
38
+ return MARKET_TYPE_TO_AGENT_MARKET[self]
39
+
40
+ @property
41
+ def job_class(self) -> type[JobAgentMarket]:
42
+ if self not in JOB_MARKET_TYPE_TO_JOB_AGENT_MARKET:
43
+ raise ValueError(f"Unknown market type: {self}")
44
+ return JOB_MARKET_TYPE_TO_JOB_AGENT_MARKET[self]
45
+
46
+ @property
47
+ def is_trading_market(self) -> bool:
48
+ return self in [
49
+ MarketType.OMEN,
50
+ MarketType.POLYMARKET,
51
+ MarketType.SEER,
52
+ MarketType.MANIFOLD,
53
+ ]
54
+
55
+ @property
56
+ def is_blockchain_market(self) -> bool:
57
+ return self in [MarketType.OMEN, MarketType.POLYMARKET, MarketType.SEER]
58
+
59
+
60
+ MARKET_TYPE_TO_AGENT_MARKET: dict[MarketType, type[AgentMarket]] = {
61
+ MarketType.MANIFOLD: ManifoldAgentMarket,
62
+ MarketType.OMEN: OmenAgentMarket,
63
+ MarketType.POLYMARKET: PolymarketAgentMarket,
64
+ MarketType.METACULUS: MetaculusAgentMarket,
65
+ MarketType.SEER: SeerAgentMarket,
66
+ }
67
+
68
+ AGENT_MARKET_TO_MARKET_TYPE: dict[type[AgentMarket], MarketType] = {
69
+ v: k for k, v in MARKET_TYPE_TO_AGENT_MARKET.items()
70
+ }
71
+
72
+ JOB_MARKET_TYPE_TO_JOB_AGENT_MARKET: dict[MarketType, type[JobAgentMarket]] = {
73
+ MarketType.OMEN: OmenJobAgentMarket,
74
+ }
@@ -1,78 +1,16 @@
1
1
  import typing as t
2
- from datetime import timedelta
3
- from enum import Enum
4
2
 
5
- from prediction_market_agent_tooling.config import APIKeys
6
- from prediction_market_agent_tooling.jobs.jobs_models import JobAgentMarket
7
- from prediction_market_agent_tooling.jobs.omen.omen_jobs import OmenJobAgentMarket
8
3
  from prediction_market_agent_tooling.markets.agent_market import (
9
4
  AgentMarket,
10
5
  FilterBy,
6
+ QuestionType,
11
7
  SortBy,
12
8
  )
13
- from prediction_market_agent_tooling.markets.manifold.api import (
14
- get_authenticated_user,
15
- get_manifold_bets,
16
- get_manifold_market,
9
+ from prediction_market_agent_tooling.markets.market_type import (
10
+ MARKET_TYPE_TO_AGENT_MARKET,
11
+ MarketType,
17
12
  )
18
- from prediction_market_agent_tooling.markets.manifold.manifold import (
19
- ManifoldAgentMarket,
20
- )
21
- from prediction_market_agent_tooling.markets.metaculus.metaculus import (
22
- MetaculusAgentMarket,
23
- )
24
- from prediction_market_agent_tooling.markets.omen.omen import OmenAgentMarket
25
- from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
26
- OmenSubgraphHandler,
27
- )
28
- from prediction_market_agent_tooling.markets.polymarket.polymarket import (
29
- PolymarketAgentMarket,
30
- )
31
- from prediction_market_agent_tooling.markets.seer.seer import SeerAgentMarket
32
- from prediction_market_agent_tooling.tools.utils import (
33
- DatetimeUTC,
34
- should_not_happen,
35
- utcnow,
36
- )
37
-
38
-
39
- class MarketType(str, Enum):
40
- # Note: Always keep the omen market first, as it is the main market for us.
41
- OMEN = "omen"
42
- MANIFOLD = "manifold"
43
- POLYMARKET = "polymarket"
44
- METACULUS = "metaculus"
45
- SEER = "seer"
46
-
47
- @property
48
- def market_class(self) -> type[AgentMarket]:
49
- if self not in MARKET_TYPE_TO_AGENT_MARKET:
50
- raise ValueError(f"Unknown market type: {self}")
51
- return MARKET_TYPE_TO_AGENT_MARKET[self]
52
-
53
- @property
54
- def job_class(self) -> type[JobAgentMarket]:
55
- if self not in JOB_MARKET_TYPE_TO_JOB_AGENT_MARKET:
56
- raise ValueError(f"Unknown market type: {self}")
57
- return JOB_MARKET_TYPE_TO_JOB_AGENT_MARKET[self]
58
-
59
- @property
60
- def is_blockchain_market(self) -> bool:
61
- return self in [MarketType.OMEN, MarketType.POLYMARKET, MarketType.SEER]
62
-
63
-
64
- MARKET_TYPE_TO_AGENT_MARKET: dict[MarketType, type[AgentMarket]] = {
65
- MarketType.MANIFOLD: ManifoldAgentMarket,
66
- MarketType.OMEN: OmenAgentMarket,
67
- MarketType.POLYMARKET: PolymarketAgentMarket,
68
- MarketType.METACULUS: MetaculusAgentMarket,
69
- MarketType.SEER: SeerAgentMarket,
70
- }
71
-
72
-
73
- JOB_MARKET_TYPE_TO_JOB_AGENT_MARKET: dict[MarketType, type[JobAgentMarket]] = {
74
- MarketType.OMEN: OmenJobAgentMarket,
75
- }
13
+ from prediction_market_agent_tooling.tools.utils import DatetimeUTC
76
14
 
77
15
 
78
16
  def get_binary_markets(
@@ -82,6 +20,7 @@ def get_binary_markets(
82
20
  sort_by: SortBy = SortBy.NONE,
83
21
  excluded_questions: set[str] | None = None,
84
22
  created_after: DatetimeUTC | None = None,
23
+ question_type: QuestionType = QuestionType.BINARY,
85
24
  ) -> t.Sequence[AgentMarket]:
86
25
  agent_market_class = MARKET_TYPE_TO_AGENT_MARKET[market_type]
87
26
  markets = agent_market_class.get_markets(
@@ -90,37 +29,6 @@ def get_binary_markets(
90
29
  filter_by=filter_by,
91
30
  created_after=created_after,
92
31
  excluded_questions=excluded_questions,
32
+ question_type=question_type,
93
33
  )
94
34
  return markets
95
-
96
-
97
- def have_bet_on_market_since(
98
- keys: APIKeys, market: AgentMarket, since: timedelta
99
- ) -> bool:
100
- start_time = utcnow() - since
101
- recently_betted_questions = (
102
- set(
103
- get_manifold_market(b.contractId).question
104
- for b in get_manifold_bets(
105
- user_id=get_authenticated_user(
106
- keys.manifold_api_key.get_secret_value()
107
- ).id,
108
- start_time=start_time,
109
- end_time=None,
110
- )
111
- )
112
- if isinstance(market, ManifoldAgentMarket)
113
- else (
114
- set(
115
- b.title
116
- for b in OmenSubgraphHandler().get_bets(
117
- better_address=keys.bet_from_address,
118
- start_time=start_time,
119
- market_id=market.market_maker_contract_address_checksummed,
120
- )
121
- )
122
- if isinstance(market, OmenAgentMarket)
123
- else should_not_happen(f"Unknown market: {market}")
124
- )
125
- )
126
- return market.question in recently_betted_questions
@@ -14,13 +14,13 @@ class QuestionType(str, Enum):
14
14
  class AggregationItem(BaseModel):
15
15
  start_time: DatetimeUTC
16
16
  end_time: DatetimeUTC | None
17
- forecast_values: list[float] | None
17
+ forecast_values: list[float] | None = None
18
18
  forecaster_count: int
19
19
  interval_lower_bounds: list[float] | None
20
20
  centers: list[float] | None
21
21
  interval_upper_bounds: list[float] | None
22
- means: list[float] | None
23
- histogram: list[list[float]] | None
22
+ means: list[float] | None = None
23
+ histogram: list[list[float]] | None = None
24
24
 
25
25
 
26
26
  class Aggregation(BaseModel):
@@ -5,12 +5,13 @@ from pydantic_core.core_schema import FieldValidationInfo
5
5
 
6
6
  from prediction_market_agent_tooling.config import APIKeys
7
7
  from prediction_market_agent_tooling.gtypes import OutcomeStr, Probability
8
- from prediction_market_agent_tooling.loggers import logger
9
8
  from prediction_market_agent_tooling.markets.agent_market import (
10
9
  AgentMarket,
10
+ ConditionalFilterType,
11
11
  FilterBy,
12
12
  MarketFees,
13
13
  ProcessedMarket,
14
+ QuestionType,
14
15
  SortBy,
15
16
  )
16
17
  from prediction_market_agent_tooling.markets.metaculus.api import (
@@ -43,13 +44,7 @@ class MetaculusAgentMarket(AgentMarket):
43
44
  probs: dict[OutcomeStr, Probability],
44
45
  info: FieldValidationInfo,
45
46
  ) -> dict[OutcomeStr, Probability]:
46
- outcomes: t.Sequence[OutcomeStr] = check_not_none(info.data.get("outcomes"))
47
- # We don't check for outcomes match because Metaculus has no filled outcomes.
48
- total = float(sum(probs.values()))
49
- if not 0.999 <= total <= 1.001:
50
- # We simply log a warning because for some use-cases (e.g. existing positions), the
51
- # markets might be already closed hence no reliable outcome token prices exist anymore.
52
- logger.warning(f"Probabilities for market {info.data=} do not sum to 1.")
47
+ # We don't check for outcomes match here because Metaculus has no filled outcomes.
53
48
  return probs
54
49
 
55
50
  @staticmethod
@@ -79,6 +74,8 @@ class MetaculusAgentMarket(AgentMarket):
79
74
  filter_by: FilterBy = FilterBy.OPEN,
80
75
  created_after: t.Optional[DatetimeUTC] = None,
81
76
  excluded_questions: set[str] | None = None,
77
+ question_type: QuestionType = QuestionType.ALL,
78
+ conditional_filter_type: ConditionalFilterType = ConditionalFilterType.ONLY_NOT_CONDITIONAL,
82
79
  tournament_id: int | None = None,
83
80
  ) -> t.Sequence["MetaculusAgentMarket"]:
84
81
  order_by: str | None
@@ -3,7 +3,7 @@ import os
3
3
  from web3 import Web3
4
4
 
5
5
  from prediction_market_agent_tooling.config import APIKeys
6
- from prediction_market_agent_tooling.gtypes import ABI, HexBytes
6
+ from prediction_market_agent_tooling.gtypes import ABI, ChecksumAddress, HexBytes
7
7
  from prediction_market_agent_tooling.tools.contract import (
8
8
  ContractOnGnosisChain,
9
9
  abi_field_validator,
@@ -19,6 +19,10 @@ class CowGPv2SettlementContract(ContractOnGnosisChain):
19
19
  )
20
20
  )
21
21
 
22
+ address: ChecksumAddress = Web3.to_checksum_address(
23
+ "0x9008D19f58AAbD9eD0D60971565AA8510560ab41"
24
+ )
25
+
22
26
  def setPreSignature(
23
27
  self,
24
28
  api_keys: APIKeys,