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,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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
8
|
+
|
|
9
|
+
def validate_manifold_resolution(v: t.Any) -> Resolution:
|
|
8
10
|
if isinstance(v, str):
|
|
9
|
-
return
|
|
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.
|
|
14
|
-
|
|
15
|
-
|
|
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.
|
|
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
|
-
|
|
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,
|