prediction-market-agent-tooling 0.65.6__py3-none-any.whl → 0.65.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prediction_market_agent_tooling/deploy/agent.py +3 -10
- prediction_market_agent_tooling/markets/agent_market.py +4 -0
- prediction_market_agent_tooling/markets/data_models.py +21 -1
- prediction_market_agent_tooling/markets/manifold/data_models.py +5 -3
- prediction_market_agent_tooling/markets/manifold/manifold.py +17 -1
- prediction_market_agent_tooling/markets/manifold/utils.py +8 -2
- prediction_market_agent_tooling/markets/markets.py +1 -47
- prediction_market_agent_tooling/markets/omen/omen.py +9 -0
- prediction_market_agent_tooling/markets/omen/omen_resolving.py +27 -10
- prediction_market_agent_tooling/markets/seer/exceptions.py +2 -0
- prediction_market_agent_tooling/markets/seer/price_manager.py +5 -2
- prediction_market_agent_tooling/markets/seer/seer.py +45 -9
- prediction_market_agent_tooling/tools/cow/cow_order.py +37 -6
- prediction_market_agent_tooling/tools/cow/models.py +16 -0
- prediction_market_agent_tooling/tools/utils.py +10 -0
- {prediction_market_agent_tooling-0.65.6.dist-info → prediction_market_agent_tooling-0.65.9.dist-info}/METADATA +1 -1
- {prediction_market_agent_tooling-0.65.6.dist-info → prediction_market_agent_tooling-0.65.9.dist-info}/RECORD +20 -18
- {prediction_market_agent_tooling-0.65.6.dist-info → prediction_market_agent_tooling-0.65.9.dist-info}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.65.6.dist-info → prediction_market_agent_tooling-0.65.9.dist-info}/WHEEL +0 -0
- {prediction_market_agent_tooling-0.65.6.dist-info → prediction_market_agent_tooling-0.65.9.dist-info}/entry_points.txt +0 -0
@@ -33,10 +33,7 @@ from prediction_market_agent_tooling.markets.data_models import (
|
|
33
33
|
ProbabilisticAnswer,
|
34
34
|
Trade,
|
35
35
|
)
|
36
|
-
from prediction_market_agent_tooling.markets.markets import
|
37
|
-
MarketType,
|
38
|
-
have_bet_on_market_since,
|
39
|
-
)
|
36
|
+
from prediction_market_agent_tooling.markets.markets import MarketType
|
40
37
|
from prediction_market_agent_tooling.markets.omen.omen import (
|
41
38
|
send_keeping_token_to_eoa_xdai,
|
42
39
|
)
|
@@ -219,7 +216,6 @@ class DeployablePredictionAgent(DeployableAgent):
|
|
219
216
|
def initialize_langfuse(self) -> None:
|
220
217
|
super().initialize_langfuse()
|
221
218
|
# Auto-observe all the methods where it makes sense, so that subclassses don't need to do it manually.
|
222
|
-
self.have_bet_on_market_since = observe()(self.have_bet_on_market_since) # type: ignore[method-assign]
|
223
219
|
self.verify_market = observe()(self.verify_market) # type: ignore[method-assign]
|
224
220
|
self.answer_binary_market = observe()(self.answer_binary_market) # type: ignore[method-assign]
|
225
221
|
self.answer_categorical_market = observe()(self.answer_categorical_market) # type: ignore[method-assign]
|
@@ -265,16 +261,13 @@ class DeployablePredictionAgent(DeployableAgent):
|
|
265
261
|
f"{api_keys=} doesn't have enough operational balance."
|
266
262
|
)
|
267
263
|
|
268
|
-
def have_bet_on_market_since(self, market: AgentMarket, since: timedelta) -> bool:
|
269
|
-
return have_bet_on_market_since(keys=APIKeys(), market=market, since=since)
|
270
|
-
|
271
264
|
def verify_market(self, market_type: MarketType, market: AgentMarket) -> bool:
|
272
265
|
"""
|
273
266
|
Subclasses can implement their own logic instead of this one, or on top of this one.
|
274
267
|
By default, it allows only markets where user didn't bet recently and it's a reasonable question.
|
275
268
|
"""
|
276
|
-
if
|
277
|
-
|
269
|
+
if market.have_bet_on_market_since(
|
270
|
+
keys=APIKeys(), since=self.same_market_trade_interval.get(market=market)
|
278
271
|
):
|
279
272
|
logger.info(
|
280
273
|
f"Market already bet on within {self.same_market_trade_interval}."
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import typing as t
|
2
|
+
from datetime import timedelta
|
2
3
|
from enum import Enum
|
3
4
|
from math import prod
|
4
5
|
|
@@ -115,6 +116,9 @@ class AgentMarket(BaseModel):
|
|
115
116
|
)
|
116
117
|
return outcome_token_pool
|
117
118
|
|
119
|
+
def have_bet_on_market_since(self, keys: APIKeys, since: timedelta) -> bool:
|
120
|
+
raise NotImplementedError("Subclasses must implement this method")
|
121
|
+
|
118
122
|
def get_outcome_token_pool_by_outcome(self, outcome: OutcomeStr) -> OutcomeToken:
|
119
123
|
if self.outcome_token_pool is None or not self.outcome_token_pool:
|
120
124
|
return OutcomeToken(0)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from enum import Enum
|
2
|
-
from typing import Annotated
|
2
|
+
from typing import Annotated, Sequence
|
3
3
|
|
4
4
|
from pydantic import BaseModel, BeforeValidator, computed_field
|
5
5
|
|
@@ -26,6 +26,26 @@ class Resolution(BaseModel):
|
|
26
26
|
def from_answer(answer: OutcomeStr) -> "Resolution":
|
27
27
|
return Resolution(outcome=answer, invalid=False)
|
28
28
|
|
29
|
+
def find_outcome_matching_market(
|
30
|
+
self, market_outcomes: Sequence[OutcomeStr]
|
31
|
+
) -> OutcomeStr | None:
|
32
|
+
"""
|
33
|
+
Finds a matching outcome in the provided market outcomes.
|
34
|
+
|
35
|
+
Performs case-insensitive matching between this resolution's outcome
|
36
|
+
and the provided market outcomes.
|
37
|
+
|
38
|
+
"""
|
39
|
+
|
40
|
+
if not self.outcome:
|
41
|
+
return None
|
42
|
+
|
43
|
+
normalized_outcome = self.outcome.lower()
|
44
|
+
for outcome in market_outcomes:
|
45
|
+
if outcome.lower() == normalized_outcome:
|
46
|
+
return outcome
|
47
|
+
return None
|
48
|
+
|
29
49
|
|
30
50
|
class Bet(BaseModel):
|
31
51
|
id: str
|
@@ -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 (
|
@@ -15,6 +16,7 @@ from prediction_market_agent_tooling.markets.agent_market import (
|
|
15
16
|
)
|
16
17
|
from prediction_market_agent_tooling.markets.manifold.api import (
|
17
18
|
get_authenticated_user,
|
19
|
+
get_manifold_bets,
|
18
20
|
get_manifold_binary_markets,
|
19
21
|
get_manifold_market,
|
20
22
|
place_bet,
|
@@ -24,7 +26,7 @@ from prediction_market_agent_tooling.markets.manifold.data_models import (
|
|
24
26
|
FullManifoldMarket,
|
25
27
|
usd_to_mana,
|
26
28
|
)
|
27
|
-
from prediction_market_agent_tooling.tools.utils import DatetimeUTC
|
29
|
+
from prediction_market_agent_tooling.tools.utils import DatetimeUTC, utcnow
|
28
30
|
|
29
31
|
|
30
32
|
class ManifoldAgentMarket(AgentMarket):
|
@@ -51,6 +53,20 @@ class ManifoldAgentMarket(AgentMarket):
|
|
51
53
|
def get_tiny_bet_amount(self) -> CollateralToken:
|
52
54
|
return CollateralToken(1)
|
53
55
|
|
56
|
+
def have_bet_on_market_since(self, keys: APIKeys, since: timedelta) -> bool:
|
57
|
+
start_time = utcnow() - since
|
58
|
+
recently_betted_questions = set(
|
59
|
+
get_manifold_market(b.contractId).question
|
60
|
+
for b in get_manifold_bets(
|
61
|
+
user_id=get_authenticated_user(
|
62
|
+
keys.manifold_api_key.get_secret_value()
|
63
|
+
).id,
|
64
|
+
start_time=start_time,
|
65
|
+
end_time=None,
|
66
|
+
)
|
67
|
+
)
|
68
|
+
return self.question in recently_betted_questions
|
69
|
+
|
54
70
|
def place_bet(self, outcome: OutcomeStr, amount: USD) -> str:
|
55
71
|
self.get_usd_in_token(amount)
|
56
72
|
bet = place_bet(
|
@@ -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)}")
|
@@ -1,8 +1,6 @@
|
|
1
1
|
import typing as t
|
2
|
-
from datetime import timedelta
|
3
2
|
from enum import Enum
|
4
3
|
|
5
|
-
from prediction_market_agent_tooling.config import APIKeys
|
6
4
|
from prediction_market_agent_tooling.jobs.jobs_models import JobAgentMarket
|
7
5
|
from prediction_market_agent_tooling.jobs.omen.omen_jobs import OmenJobAgentMarket
|
8
6
|
from prediction_market_agent_tooling.markets.agent_market import (
|
@@ -10,11 +8,6 @@ from prediction_market_agent_tooling.markets.agent_market import (
|
|
10
8
|
FilterBy,
|
11
9
|
SortBy,
|
12
10
|
)
|
13
|
-
from prediction_market_agent_tooling.markets.manifold.api import (
|
14
|
-
get_authenticated_user,
|
15
|
-
get_manifold_bets,
|
16
|
-
get_manifold_market,
|
17
|
-
)
|
18
11
|
from prediction_market_agent_tooling.markets.manifold.manifold import (
|
19
12
|
ManifoldAgentMarket,
|
20
13
|
)
|
@@ -22,18 +15,11 @@ from prediction_market_agent_tooling.markets.metaculus.metaculus import (
|
|
22
15
|
MetaculusAgentMarket,
|
23
16
|
)
|
24
17
|
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
18
|
from prediction_market_agent_tooling.markets.polymarket.polymarket import (
|
29
19
|
PolymarketAgentMarket,
|
30
20
|
)
|
31
21
|
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
|
-
)
|
22
|
+
from prediction_market_agent_tooling.tools.utils import DatetimeUTC
|
37
23
|
|
38
24
|
|
39
25
|
class MarketType(str, Enum):
|
@@ -92,35 +78,3 @@ def get_binary_markets(
|
|
92
78
|
excluded_questions=excluded_questions,
|
93
79
|
)
|
94
80
|
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
|
@@ -84,6 +84,7 @@ from prediction_market_agent_tooling.tools.utils import (
|
|
84
84
|
DatetimeUTC,
|
85
85
|
calculate_sell_amount_in_collateral,
|
86
86
|
check_not_none,
|
87
|
+
utcnow,
|
87
88
|
)
|
88
89
|
from prediction_market_agent_tooling.tools.web3_utils import get_receipt_block_timestamp
|
89
90
|
|
@@ -157,6 +158,14 @@ class OmenAgentMarket(AgentMarket):
|
|
157
158
|
def get_usd_in_token(self, x: USD) -> CollateralToken:
|
158
159
|
return get_usd_in_token(x, self.collateral_token_contract_address_checksummed)
|
159
160
|
|
161
|
+
def have_bet_on_market_since(self, keys: APIKeys, since: timedelta) -> bool:
|
162
|
+
start_time = utcnow() - since
|
163
|
+
prev_bets = self.get_bets_made_since(
|
164
|
+
better_address=keys.bet_from_address, start_time=start_time
|
165
|
+
)
|
166
|
+
|
167
|
+
return self.id in [b.market_id for b in prev_bets]
|
168
|
+
|
160
169
|
def liquidate_existing_positions(
|
161
170
|
self,
|
162
171
|
bet_outcome: OutcomeStr,
|
@@ -31,7 +31,11 @@ from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
|
|
31
31
|
from prediction_market_agent_tooling.tools.tokens.main_token import (
|
32
32
|
MINIMUM_NATIVE_TOKEN_IN_EOA_FOR_FEES,
|
33
33
|
)
|
34
|
-
from prediction_market_agent_tooling.tools.utils import
|
34
|
+
from prediction_market_agent_tooling.tools.utils import (
|
35
|
+
check_not_none,
|
36
|
+
extract_error_from_retry_error,
|
37
|
+
utcnow,
|
38
|
+
)
|
35
39
|
from prediction_market_agent_tooling.tools.web3_utils import ZERO_BYTES
|
36
40
|
|
37
41
|
|
@@ -223,7 +227,10 @@ def omen_submit_answer_market_tx(
|
|
223
227
|
And after the period is over, you need to resolve the market using `omen_resolve_market_tx`.
|
224
228
|
"""
|
225
229
|
realitio_contract = OmenRealitioContract()
|
226
|
-
|
230
|
+
outcome_matching_market = check_not_none(
|
231
|
+
resolution.find_outcome_matching_market(market.outcomes)
|
232
|
+
)
|
233
|
+
outcome_index = market.outcomes.index(outcome_matching_market)
|
227
234
|
realitio_contract.submit_answer(
|
228
235
|
api_keys=api_keys,
|
229
236
|
question_id=market.question.id,
|
@@ -261,14 +268,24 @@ def omen_resolve_market_tx(
|
|
261
268
|
Market can be resolved after the answer if finalized on Reality.
|
262
269
|
"""
|
263
270
|
oracle_contract = OmenOracleContract()
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
271
|
+
try:
|
272
|
+
oracle_contract.resolve(
|
273
|
+
api_keys=api_keys,
|
274
|
+
question_id=market.question.id,
|
275
|
+
template_id=market.question.templateId,
|
276
|
+
question_raw=market.question.question_raw,
|
277
|
+
n_outcomes=market.question.n_outcomes,
|
278
|
+
web3=web3,
|
279
|
+
)
|
280
|
+
except BaseException as e:
|
281
|
+
e = extract_error_from_retry_error(e)
|
282
|
+
if "condition not prepared or found" in str(e):
|
283
|
+
# We can't do anything about these, so just skip them with warning.
|
284
|
+
logger.warning(
|
285
|
+
f"Market {market.url=} not resolved, because `condition not prepared or found`, skipping."
|
286
|
+
)
|
287
|
+
else:
|
288
|
+
raise
|
272
289
|
|
273
290
|
|
274
291
|
def find_resolution_on_other_markets(market: OmenMarket) -> Resolution | None:
|
@@ -12,6 +12,9 @@ from prediction_market_agent_tooling.gtypes import (
|
|
12
12
|
)
|
13
13
|
from prediction_market_agent_tooling.loggers import logger
|
14
14
|
from prediction_market_agent_tooling.markets.seer.data_models import SeerMarket
|
15
|
+
from prediction_market_agent_tooling.markets.seer.exceptions import (
|
16
|
+
PriceCalculationError,
|
17
|
+
)
|
15
18
|
from prediction_market_agent_tooling.markets.seer.seer_subgraph_handler import (
|
16
19
|
SeerSubgraphHandler,
|
17
20
|
)
|
@@ -128,7 +131,7 @@ class PriceManager:
|
|
128
131
|
)
|
129
132
|
# It's okay if invalid (last) outcome has price 0, but not the other outcomes.
|
130
133
|
if price is None and idx != len(self.seer_market.wrapped_tokens) - 1:
|
131
|
-
raise
|
134
|
+
raise PriceCalculationError(
|
132
135
|
f"Couldn't get price for {wrapped_token} for market {self.seer_market.url}."
|
133
136
|
)
|
134
137
|
price_data[wrapped_token] = (
|
@@ -142,7 +145,7 @@ class PriceManager:
|
|
142
145
|
sum(price_data.values(), start=CollateralToken.zero())
|
143
146
|
== CollateralToken.zero()
|
144
147
|
):
|
145
|
-
raise
|
148
|
+
raise PriceCalculationError(
|
146
149
|
f"All prices for market {self.seer_market.url} are zero. This shouldn't happen."
|
147
150
|
)
|
148
151
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import typing as t
|
2
|
+
from datetime import timedelta
|
2
3
|
|
3
4
|
from eth_typing import ChecksumAddress
|
4
5
|
from web3 import Web3
|
@@ -31,6 +32,9 @@ from prediction_market_agent_tooling.markets.seer.data_models import (
|
|
31
32
|
RedeemParams,
|
32
33
|
SeerMarket,
|
33
34
|
)
|
35
|
+
from prediction_market_agent_tooling.markets.seer.exceptions import (
|
36
|
+
PriceCalculationError,
|
37
|
+
)
|
34
38
|
from prediction_market_agent_tooling.markets.seer.price_manager import PriceManager
|
35
39
|
from prediction_market_agent_tooling.markets.seer.seer_contracts import (
|
36
40
|
GnosisRouter,
|
@@ -49,6 +53,7 @@ from prediction_market_agent_tooling.tools.contract import (
|
|
49
53
|
)
|
50
54
|
from prediction_market_agent_tooling.tools.cow.cow_order import (
|
51
55
|
get_buy_token_amount_else_raise,
|
56
|
+
get_orders_by_owner,
|
52
57
|
get_trades_by_owner,
|
53
58
|
swap_tokens_waiting,
|
54
59
|
)
|
@@ -60,6 +65,7 @@ from prediction_market_agent_tooling.tools.tokens.usd import (
|
|
60
65
|
get_token_in_usd,
|
61
66
|
get_usd_in_token,
|
62
67
|
)
|
68
|
+
from prediction_market_agent_tooling.tools.utils import utcnow
|
63
69
|
|
64
70
|
# We place a larger bet amount by default than Omen so that cow presents valid quotes.
|
65
71
|
SEER_TINY_BET_AMOUNT = USD(0.1)
|
@@ -269,24 +275,44 @@ class SeerAgentMarket(AgentMarket):
|
|
269
275
|
|
270
276
|
# GnosisRouter withdraws sDai into wxDAI/xDai on its own, so no auto-withdraw needed by us.
|
271
277
|
|
278
|
+
def have_bet_on_market_since(self, keys: APIKeys, since: timedelta) -> bool:
|
279
|
+
"""Check if the user has placed a bet on this market since a specific time using Cow API."""
|
280
|
+
# Cow endpoint doesn't allow us to filter by time.
|
281
|
+
start_time = utcnow() - since
|
282
|
+
prev_orders = get_orders_by_owner(owner=keys.bet_from_address)
|
283
|
+
for order in prev_orders:
|
284
|
+
if order.creationDate >= start_time and {
|
285
|
+
Web3.to_checksum_address(order.sellToken),
|
286
|
+
Web3.to_checksum_address(order.buyToken),
|
287
|
+
}.intersection(set(self.wrapped_tokens)):
|
288
|
+
return True
|
289
|
+
|
290
|
+
return False
|
291
|
+
|
272
292
|
@staticmethod
|
273
293
|
def verify_operational_balance(api_keys: APIKeys) -> bool:
|
274
294
|
return OmenAgentMarket.verify_operational_balance(api_keys=api_keys)
|
275
295
|
|
276
296
|
@staticmethod
|
277
297
|
def from_data_model_with_subgraph(
|
278
|
-
model: SeerMarket,
|
298
|
+
model: SeerMarket,
|
299
|
+
seer_subgraph: SeerSubgraphHandler,
|
300
|
+
must_have_prices: bool,
|
279
301
|
) -> t.Optional["SeerAgentMarket"]:
|
280
|
-
|
302
|
+
price_manager = PriceManager(seer_market=model, seer_subgraph=seer_subgraph)
|
281
303
|
|
282
|
-
probability_map =
|
283
|
-
|
304
|
+
probability_map = {}
|
305
|
+
try:
|
306
|
+
probability_map = price_manager.build_probability_map()
|
307
|
+
except PriceCalculationError as e:
|
284
308
|
logger.info(
|
285
|
-
f"
|
309
|
+
f"Error when calculating probabilities for market {model.id.hex()} - {e}"
|
286
310
|
)
|
287
|
-
|
311
|
+
if must_have_prices:
|
312
|
+
# Price calculation failed, so don't return the market
|
313
|
+
return None
|
288
314
|
|
289
|
-
|
315
|
+
market = SeerAgentMarket(
|
290
316
|
id=model.id.hex(),
|
291
317
|
question=model.title,
|
292
318
|
creator=model.creator,
|
@@ -305,6 +331,8 @@ class SeerAgentMarket(AgentMarket):
|
|
305
331
|
probabilities=probability_map,
|
306
332
|
)
|
307
333
|
|
334
|
+
return market
|
335
|
+
|
308
336
|
@staticmethod
|
309
337
|
def get_markets(
|
310
338
|
limit: int,
|
@@ -324,17 +352,25 @@ class SeerAgentMarket(AgentMarket):
|
|
324
352
|
|
325
353
|
# We exclude the None values below because `from_data_model_with_subgraph` can return None, which
|
326
354
|
# represents an invalid market.
|
327
|
-
|
355
|
+
seer_agent_markets = [
|
328
356
|
market
|
329
357
|
for m in markets
|
330
358
|
if (
|
331
359
|
market := SeerAgentMarket.from_data_model_with_subgraph(
|
332
|
-
model=m,
|
360
|
+
model=m,
|
361
|
+
seer_subgraph=seer_subgraph,
|
362
|
+
must_have_prices=filter_by == FilterBy.OPEN,
|
333
363
|
)
|
334
364
|
)
|
335
365
|
is not None
|
336
366
|
]
|
337
367
|
|
368
|
+
if filter_by == FilterBy.OPEN:
|
369
|
+
# Extra manual filter for liquidity, as subgraph is sometimes unreliable.
|
370
|
+
seer_agent_markets = [m for m in seer_agent_markets if m.has_liquidity()]
|
371
|
+
|
372
|
+
return seer_agent_markets
|
373
|
+
|
338
374
|
def get_outcome_str_from_idx(self, outcome_index: int) -> OutcomeStr:
|
339
375
|
return self.outcomes[outcome_index]
|
340
376
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import asyncio
|
2
|
+
import typing as t
|
2
3
|
from datetime import timedelta
|
3
4
|
|
4
5
|
import httpx
|
@@ -23,7 +24,6 @@ from cowdao_cowpy.order_book.generated.model import (
|
|
23
24
|
OrderStatus,
|
24
25
|
TokenAmount,
|
25
26
|
)
|
26
|
-
from cowdao_cowpy.subgraph.client import BaseModel
|
27
27
|
from tenacity import (
|
28
28
|
retry_if_not_exception_type,
|
29
29
|
stop_after_attempt,
|
@@ -39,14 +39,10 @@ from prediction_market_agent_tooling.markets.omen.cow_contracts import (
|
|
39
39
|
CowGPv2SettlementContract,
|
40
40
|
)
|
41
41
|
from prediction_market_agent_tooling.tools.contract import ContractERC20OnGnosisChain
|
42
|
+
from prediction_market_agent_tooling.tools.cow.models import MinimalisticToken, Order
|
42
43
|
from prediction_market_agent_tooling.tools.utils import check_not_none, utcnow
|
43
44
|
|
44
45
|
|
45
|
-
class MinimalisticToken(BaseModel):
|
46
|
-
sellToken: ChecksumAddress
|
47
|
-
buyToken: ChecksumAddress
|
48
|
-
|
49
|
-
|
50
46
|
class OrderStatusError(Exception):
|
51
47
|
pass
|
52
48
|
|
@@ -292,3 +288,38 @@ def get_trades_by_owner(
|
|
292
288
|
)
|
293
289
|
response.raise_for_status()
|
294
290
|
return [MinimalisticToken.model_validate(i) for i in response.json()]
|
291
|
+
|
292
|
+
|
293
|
+
@tenacity.retry(
|
294
|
+
stop=stop_after_attempt(3),
|
295
|
+
wait=wait_fixed(1),
|
296
|
+
after=lambda x: logger.debug(f"get_orders_by_owner failed, {x.attempt_number=}."),
|
297
|
+
)
|
298
|
+
def get_orders_by_owner(
|
299
|
+
owner: ChecksumAddress,
|
300
|
+
) -> list[Order]:
|
301
|
+
"""Retrieves all orders with pagination."""
|
302
|
+
items = paginate_endpoint(f"https://api.cow.fi/xdai/api/v1/account/{owner}/orders")
|
303
|
+
return [Order.model_validate(i) for i in items]
|
304
|
+
|
305
|
+
|
306
|
+
@tenacity.retry(
|
307
|
+
stop=stop_after_attempt(3),
|
308
|
+
wait=wait_fixed(1),
|
309
|
+
after=lambda x: logger.debug(f"paginate_endpoint failed, {x.attempt_number=}."),
|
310
|
+
)
|
311
|
+
def paginate_endpoint(url: str, limit: int = 1000) -> t.Any:
|
312
|
+
offset = 0
|
313
|
+
results = []
|
314
|
+
|
315
|
+
while True:
|
316
|
+
response = httpx.get(url, params={"offset": offset, "limit": limit})
|
317
|
+
response.raise_for_status()
|
318
|
+
items = response.json()
|
319
|
+
if not items:
|
320
|
+
break
|
321
|
+
|
322
|
+
results.extend(items)
|
323
|
+
offset += limit
|
324
|
+
|
325
|
+
return results
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from pydantic import BaseModel
|
2
|
+
|
3
|
+
from prediction_market_agent_tooling.gtypes import ChecksumAddress
|
4
|
+
from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC
|
5
|
+
|
6
|
+
|
7
|
+
class MinimalisticToken(BaseModel):
|
8
|
+
sellToken: ChecksumAddress
|
9
|
+
buyToken: ChecksumAddress
|
10
|
+
|
11
|
+
|
12
|
+
class Order(BaseModel):
|
13
|
+
uid: str
|
14
|
+
sellToken: str
|
15
|
+
buyToken: str
|
16
|
+
creationDate: DatetimeUTC
|
@@ -9,6 +9,7 @@ import requests
|
|
9
9
|
from pydantic import BaseModel, ValidationError
|
10
10
|
from scipy.optimize import newton
|
11
11
|
from scipy.stats import entropy
|
12
|
+
from tenacity import RetryError
|
12
13
|
|
13
14
|
from prediction_market_agent_tooling.gtypes import (
|
14
15
|
CollateralToken,
|
@@ -230,3 +231,12 @@ def calculate_sell_amount_in_collateral(
|
|
230
231
|
|
231
232
|
amount_to_sell = newton(f, 0)
|
232
233
|
return CollateralToken(float(amount_to_sell) * 0.999999) # Avoid rounding errors
|
234
|
+
|
235
|
+
|
236
|
+
def extract_error_from_retry_error(e: BaseException | RetryError) -> BaseException:
|
237
|
+
if (
|
238
|
+
isinstance(e, RetryError)
|
239
|
+
and (exp_from_retry := e.last_attempt.exception()) is not None
|
240
|
+
):
|
241
|
+
e = exp_from_retry
|
242
|
+
return e
|
@@ -24,7 +24,7 @@ prediction_market_agent_tooling/benchmark/benchmark.py,sha256=KwMZzwise3sgmhdjw7
|
|
24
24
|
prediction_market_agent_tooling/benchmark/utils.py,sha256=xQd7p9H08-OtN3iC4QT2i9bkUTmrXa6rxGXeg9yMhgU,2986
|
25
25
|
prediction_market_agent_tooling/chains.py,sha256=1qQstoqXMwqwM7k-KH7MjMz8Ei-D83KZByvDbCZpAxs,116
|
26
26
|
prediction_market_agent_tooling/config.py,sha256=-kJfdDr-m0R-tGZ1KRI-hJJk0mXDt142CAlvwaJ2N2I,11778
|
27
|
-
prediction_market_agent_tooling/deploy/agent.py,sha256=
|
27
|
+
prediction_market_agent_tooling/deploy/agent.py,sha256=ONuXYe9zRO37lzume5z-2hPKTBrCljBg5OD_38gNRc0,25289
|
28
28
|
prediction_market_agent_tooling/deploy/agent_example.py,sha256=yS1fWkHynr9MYGNOM2WsCnRWLPaffY4bOc6bIudrdd4,1377
|
29
29
|
prediction_market_agent_tooling/deploy/betting_strategy.py,sha256=YYayGjTKW02d3BUavJ8M3NmFk41oldEM3FHbwppZGRM,17184
|
30
30
|
prediction_market_agent_tooling/deploy/constants.py,sha256=Qe9cllgsGMkecfmbhXoFkPxuJyG6ATsrT87RF9SmPWM,249
|
@@ -38,28 +38,28 @@ prediction_market_agent_tooling/jobs/jobs_models.py,sha256=DoZ9dlvVhpNrnINiR1uy6
|
|
38
38
|
prediction_market_agent_tooling/jobs/omen/omen_jobs.py,sha256=qbTZ9HVvu_iP4dDxuvOZxAp6JsRKejvEW2YDYCnRmd4,5039
|
39
39
|
prediction_market_agent_tooling/loggers.py,sha256=kFZ1BrI8hvWgZO1vzptFnYiOEDx9Ozs86DA9yF3bSgY,5212
|
40
40
|
prediction_market_agent_tooling/logprobs_parser.py,sha256=DBlBQtWX8_URXhzTU3YWIPa76Zx3QDHlx1ARqbgJsVI,5008
|
41
|
-
prediction_market_agent_tooling/markets/agent_market.py,sha256=
|
41
|
+
prediction_market_agent_tooling/markets/agent_market.py,sha256=pnyxTMUrL8cQsP4lmBBpe07R-Mi7S4vNjrvNLdOzAa8,19258
|
42
42
|
prediction_market_agent_tooling/markets/base_subgraph_handler.py,sha256=7RaYO_4qAmQ6ZGM8oPK2-CkiJfKmV9MxM-rJlduaecU,1971
|
43
43
|
prediction_market_agent_tooling/markets/blockchain_utils.py,sha256=gZMwCTO-1d2ALXeY7-LP6U4kCpotJ6GMPZwN11kFOfE,2604
|
44
44
|
prediction_market_agent_tooling/markets/categorize.py,sha256=orLZlPaHgeREU66m1amxfWikeV77idV4sZDPB8NgSD0,1300
|
45
|
-
prediction_market_agent_tooling/markets/data_models.py,sha256=
|
45
|
+
prediction_market_agent_tooling/markets/data_models.py,sha256=seifqxjVpzZdVKJQ7a5sKPPUM749EHV80SdI6pVQ3b4,7542
|
46
46
|
prediction_market_agent_tooling/markets/manifold/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
47
|
prediction_market_agent_tooling/markets/manifold/api.py,sha256=tWnjuqvU8pcCuja2B_ynHeds1iiEFc6QWHjeSO_GSxY,7676
|
48
|
-
prediction_market_agent_tooling/markets/manifold/data_models.py,sha256=
|
49
|
-
prediction_market_agent_tooling/markets/manifold/manifold.py,sha256=
|
50
|
-
prediction_market_agent_tooling/markets/manifold/utils.py,sha256=
|
48
|
+
prediction_market_agent_tooling/markets/manifold/data_models.py,sha256=3z1gFbPMEgCDGqeH-IK8wcvqmIHgLdZX8C2M1UQ7iDw,6740
|
49
|
+
prediction_market_agent_tooling/markets/manifold/manifold.py,sha256=7s8BC32QkzU80coLTKzms1FrG0E-GEeHfkrl_MgrrLk,5301
|
50
|
+
prediction_market_agent_tooling/markets/manifold/utils.py,sha256=DCigEbpGWkXR-RZT_oJrvJhilmxKFAxcWMjUFi0nBBI,530
|
51
51
|
prediction_market_agent_tooling/markets/market_fees.py,sha256=YeK3ynjYIguB0xf6sO5iyg9lOdW_HD4C6nbJfiGyRCU,1351
|
52
|
-
prediction_market_agent_tooling/markets/markets.py,sha256=
|
52
|
+
prediction_market_agent_tooling/markets/markets.py,sha256=lIEPfPJD1Gz90pTvN2pZi51rpb969STPgQtNFCqHUJg,2667
|
53
53
|
prediction_market_agent_tooling/markets/metaculus/api.py,sha256=4TRPGytQQbSdf42DCg2M_JWYPAuNjqZ3eBqaQBLkNks,2736
|
54
54
|
prediction_market_agent_tooling/markets/metaculus/data_models.py,sha256=FaBCTPPezXbBwZ9p791CiVgQ4vB696xnMbz9XVXmiVI,3267
|
55
55
|
prediction_market_agent_tooling/markets/metaculus/metaculus.py,sha256=6iuUpDXgdbFOh-XuxH0rbeAf_m55r2KbHTaSTePNSWA,5614
|
56
56
|
prediction_market_agent_tooling/markets/omen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
57
|
prediction_market_agent_tooling/markets/omen/cow_contracts.py,sha256=sl1L4cK5nAJwZ2wdhLzqh8p7h_IEValNvLwKUlInKxw,957
|
58
58
|
prediction_market_agent_tooling/markets/omen/data_models.py,sha256=0jCxgUEVpaggt_avkNqgXAnZWdA6D-ew9PE2gm0aqDk,29930
|
59
|
-
prediction_market_agent_tooling/markets/omen/omen.py,sha256=
|
59
|
+
prediction_market_agent_tooling/markets/omen/omen.py,sha256=q3SqvQEpZAsbFBbSid_rhRn-hVi-roCRN4piGj2wxU8,50301
|
60
60
|
prediction_market_agent_tooling/markets/omen/omen_constants.py,sha256=D9oflYKafLQiHYtB5sScMHqmXyzM8JP8J0yATmc4SQQ,233
|
61
61
|
prediction_market_agent_tooling/markets/omen/omen_contracts.py,sha256=f0dKbdVM2OUTSpkCSZdPtKqeckS2c48j3rjnK8oD3wE,29716
|
62
|
-
prediction_market_agent_tooling/markets/omen/omen_resolving.py,sha256=
|
62
|
+
prediction_market_agent_tooling/markets/omen/omen_resolving.py,sha256=_9FjpH-y_yDwua2-mZ0Iop49cRBs2m7w-Z1s3mOofFk,10848
|
63
63
|
prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py,sha256=149T_tJxK2GFnGCulOlGr2Mwiaa7sa74E4lqYsuCv68,39962
|
64
64
|
prediction_market_agent_tooling/markets/polymarket/api.py,sha256=UZ4_TG8ceb9Y-qgsOKs8Qiv8zDt957QkT8IX2c83yqo,4800
|
65
65
|
prediction_market_agent_tooling/markets/polymarket/data_models.py,sha256=U1SXTz93FIG3GO1h5BJWSt1hPKn_YAMBeZ3k8IS-ook,4552
|
@@ -67,8 +67,9 @@ prediction_market_agent_tooling/markets/polymarket/data_models_web.py,sha256=wCw
|
|
67
67
|
prediction_market_agent_tooling/markets/polymarket/polymarket.py,sha256=meAhQ5_gwVDvlSxhGGVAvRB7B47zKLnRvZ-_13tKtwY,3433
|
68
68
|
prediction_market_agent_tooling/markets/polymarket/utils.py,sha256=8kTeVjXPcXC6DkDvWYsZQLY7x8DS6CEp_yznSEazsNU,2037
|
69
69
|
prediction_market_agent_tooling/markets/seer/data_models.py,sha256=G0i-fnVaK16KWDYVI6w3lvyte6Op7ca_iIC8IfrXmlM,4702
|
70
|
-
prediction_market_agent_tooling/markets/seer/
|
71
|
-
prediction_market_agent_tooling/markets/seer/
|
70
|
+
prediction_market_agent_tooling/markets/seer/exceptions.py,sha256=cEObdjluivD94tgOLzmimR7wgQEOt6SRakrYdhsRQtk,112
|
71
|
+
prediction_market_agent_tooling/markets/seer/price_manager.py,sha256=MClY2NGwOV70nZYIcmzXFy6Ogd8NBIq7telQcQ3VcU4,6243
|
72
|
+
prediction_market_agent_tooling/markets/seer/seer.py,sha256=IsFK8XXjHq8UBvIkueiWpm_b3ddMslr84DqF_qNFQw0,21745
|
72
73
|
prediction_market_agent_tooling/markets/seer/seer_contracts.py,sha256=kH9nPXsx6UM5er42g2f3fLvy36sY5JM2f_beXeuNgUc,3790
|
73
74
|
prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py,sha256=pJxch9_u0EdiIatQP1-UFClt8UEfMZAXBlk5wDO_ovk,9940
|
74
75
|
prediction_market_agent_tooling/markets/seer/subgraph_data_models.py,sha256=0izxS8Mtzonfdl9UqvFVXrdj0hVzieroekXhogfZKCw,1817
|
@@ -83,7 +84,8 @@ prediction_market_agent_tooling/tools/caches/inmemory_cache.py,sha256=ZW5iI5rmjq
|
|
83
84
|
prediction_market_agent_tooling/tools/caches/serializers.py,sha256=vFDx4fsPxclXp2q0sv27j4al_M_Tj9aR2JJP-xNHQXA,2151
|
84
85
|
prediction_market_agent_tooling/tools/contract.py,sha256=pdr9ZYmj4QVUfgVKdvOU6ucYdBpJGdha_FMR_LgtcEs,22912
|
85
86
|
prediction_market_agent_tooling/tools/costs.py,sha256=EaAJ7v9laD4VEV3d8B44M4u3_oEO_H16jRVCdoZ93Uw,954
|
86
|
-
prediction_market_agent_tooling/tools/cow/cow_order.py,sha256
|
87
|
+
prediction_market_agent_tooling/tools/cow/cow_order.py,sha256=KpklYy5DY3j-aIlf6dB_o0mEX4MD3fqMiZK3tJs5Gro,10129
|
88
|
+
prediction_market_agent_tooling/tools/cow/models.py,sha256=ZWGW0og5vXjgZVXxkx4uV2m61Q8AmL-L-D_D4f7ApR0,379
|
87
89
|
prediction_market_agent_tooling/tools/custom_exceptions.py,sha256=Fh8z1fbwONvP4-j7AmV_PuEcoqb6-QXa9PJ9m7guMcM,93
|
88
90
|
prediction_market_agent_tooling/tools/datetime_utc.py,sha256=8_WackjtjC8zHXrhQFTGQ6e6Fz_6llWoKR4CSFvIv9I,2766
|
89
91
|
prediction_market_agent_tooling/tools/db/db_manager.py,sha256=GtzHH1NLl8HwqC8Z7s6eTlIQXuV0blxfaV2PeQrBnfQ,3013
|
@@ -117,10 +119,10 @@ prediction_market_agent_tooling/tools/tokens/main_token.py,sha256=1rbwpdCusPgQIV
|
|
117
119
|
prediction_market_agent_tooling/tools/tokens/token_utils.py,sha256=fhs-FH9m9IbzGa-30R3ZleSKLeKfLEDoJ7F5Om285Vk,1369
|
118
120
|
prediction_market_agent_tooling/tools/tokens/usd.py,sha256=yuW8iPPtcpP4eLH2nORMDAfztcq0Nv2ascSrCquF1f8,3115
|
119
121
|
prediction_market_agent_tooling/tools/transaction_cache.py,sha256=K5YKNL2_tR10Iw2TD9fuP-CTGpBbZtNdgbd0B_R7pjg,1814
|
120
|
-
prediction_market_agent_tooling/tools/utils.py,sha256=
|
122
|
+
prediction_market_agent_tooling/tools/utils.py,sha256=RlWSlzS2LavMIWrpwn1fevbzgPZruD4VcXTa-XxjWnE,7343
|
121
123
|
prediction_market_agent_tooling/tools/web3_utils.py,sha256=zRq-eeBGWt8uUGN9G_WfjmJ0eVvO8aWE9S0Pz_Y6AOA,12342
|
122
|
-
prediction_market_agent_tooling-0.65.
|
123
|
-
prediction_market_agent_tooling-0.65.
|
124
|
-
prediction_market_agent_tooling-0.65.
|
125
|
-
prediction_market_agent_tooling-0.65.
|
126
|
-
prediction_market_agent_tooling-0.65.
|
124
|
+
prediction_market_agent_tooling-0.65.9.dist-info/LICENSE,sha256=6or154nLLU6bELzjh0mCreFjt0m2v72zLi3yHE0QbeE,7650
|
125
|
+
prediction_market_agent_tooling-0.65.9.dist-info/METADATA,sha256=fwrbaHBiT91jMhqYkTWJ-vPB2dav-bxrgqfV7oDjGHY,8734
|
126
|
+
prediction_market_agent_tooling-0.65.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
127
|
+
prediction_market_agent_tooling-0.65.9.dist-info/entry_points.txt,sha256=m8PukHbeH5g0IAAmOf_1Ahm-sGAMdhSSRQmwtpmi2s8,81
|
128
|
+
prediction_market_agent_tooling-0.65.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|