prediction-market-agent-tooling 0.53.0__tar.gz → 0.55.0__tar.gz
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-0.53.0 → prediction_market_agent_tooling-0.55.0}/PKG-INFO +2 -2
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/deploy/agent.py +181 -183
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/deploy/betting_strategy.py +23 -2
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/agent_market.py +48 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +5 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/markets.py +4 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/metaculus/data_models.py +4 -1
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/metaculus/metaculus.py +30 -8
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/omen/omen.py +70 -4
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/is_invalid.py +4 -3
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/tavily/tavily_search.py +11 -1
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/pyproject.toml +3 -3
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/README.md +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/debuggingcontract.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/erc4626.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/abis/proxy.abi.json +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/config.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/gtypes.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/jobs/__init__.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/jobs/jobs.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/jobs/jobs_models.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/jobs/omen/omen_jobs.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/loggers.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/data_models.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/market_fees.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/metaculus/api.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/omen/data_models.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/monitor/markets/metaculus.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/monitor/markets/omen.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/monitor/markets/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/monitor/monitor.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/py.typed +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/balances.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/betting_strategies/utils.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/cache.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/contract.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/costs.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/datetime_utc.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/google.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/httpx_cached_client.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/image_gen/image_gen.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/langfuse_.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/langfuse_client_utils.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/omen/reality_accuracy.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/safe.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/streamlit_user_login.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/tavily/tavily_models.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/tavily/tavily_storage.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/utils.py +0 -0
- {prediction_market_agent_tooling-0.53.0 → prediction_market_agent_tooling-0.55.0}/prediction_market_agent_tooling/tools/web3_utils.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: prediction-market-agent-tooling
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.55.0
|
4
4
|
Summary: Tools to benchmark, deploy and monitor prediction market agents.
|
5
5
|
Author: Gnosis
|
6
6
|
Requires-Python: >=3.10,<3.12
|
@@ -44,7 +44,7 @@ Requires-Dist: sqlmodel (>=0.0.22,<0.0.23)
|
|
44
44
|
Requires-Dist: streamlit (>=1.31.0,<2.0.0)
|
45
45
|
Requires-Dist: subgrounds (>=1.9.1,<2.0.0)
|
46
46
|
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
47
|
-
Requires-Dist: tavily-python (>=0.
|
47
|
+
Requires-Dist: tavily-python (>=0.5.0,<0.6.0)
|
48
48
|
Requires-Dist: tqdm (>=4.66.2,<5.0.0)
|
49
49
|
Requires-Dist: typer (>=0.9.0,<1.0.0)
|
50
50
|
Requires-Dist: types-python-dateutil (>=2.9.0.20240906,<3.0.0.0)
|
@@ -8,10 +8,8 @@ from datetime import timedelta
|
|
8
8
|
from enum import Enum
|
9
9
|
from functools import cached_property
|
10
10
|
|
11
|
-
from pydantic import
|
11
|
+
from pydantic import BeforeValidator, computed_field
|
12
12
|
from typing_extensions import Annotated
|
13
|
-
from web3 import Web3
|
14
|
-
from web3.constants import HASH_ZERO
|
15
13
|
|
16
14
|
from prediction_market_agent_tooling.config import APIKeys
|
17
15
|
from prediction_market_agent_tooling.deploy.betting_strategy import (
|
@@ -32,11 +30,13 @@ from prediction_market_agent_tooling.deploy.gcp.utils import (
|
|
32
30
|
gcp_function_is_active,
|
33
31
|
gcp_resolve_api_keys_secrets,
|
34
32
|
)
|
35
|
-
from prediction_market_agent_tooling.gtypes import
|
33
|
+
from prediction_market_agent_tooling.gtypes import xDai, xdai_type
|
36
34
|
from prediction_market_agent_tooling.loggers import logger
|
37
35
|
from prediction_market_agent_tooling.markets.agent_market import (
|
38
36
|
AgentMarket,
|
39
37
|
FilterBy,
|
38
|
+
ProcessedMarket,
|
39
|
+
ProcessedTradedMarket,
|
40
40
|
SortBy,
|
41
41
|
)
|
42
42
|
from prediction_market_agent_tooling.markets.data_models import (
|
@@ -49,28 +49,16 @@ from prediction_market_agent_tooling.markets.markets import (
|
|
49
49
|
MarketType,
|
50
50
|
have_bet_on_market_since,
|
51
51
|
)
|
52
|
-
from prediction_market_agent_tooling.markets.omen.data_models import (
|
53
|
-
ContractPrediction,
|
54
|
-
IPFSAgentResult,
|
55
|
-
)
|
56
52
|
from prediction_market_agent_tooling.markets.omen.omen import (
|
57
|
-
is_minimum_required_balance,
|
58
|
-
redeem_from_all_user_positions,
|
59
53
|
withdraw_wxdai_to_xdai_to_keep_balance,
|
60
54
|
)
|
61
|
-
from prediction_market_agent_tooling.markets.omen.omen_contracts import (
|
62
|
-
OmenAgentResultMappingContract,
|
63
|
-
)
|
64
55
|
from prediction_market_agent_tooling.monitor.monitor_app import (
|
65
56
|
MARKET_TYPE_TO_DEPLOYED_AGENT,
|
66
57
|
)
|
67
|
-
from prediction_market_agent_tooling.tools.hexbytes_custom import HexBytes
|
68
|
-
from prediction_market_agent_tooling.tools.ipfs.ipfs_handler import IPFSHandler
|
69
58
|
from prediction_market_agent_tooling.tools.is_invalid import is_invalid
|
70
59
|
from prediction_market_agent_tooling.tools.is_predictable import is_predictable_binary
|
71
60
|
from prediction_market_agent_tooling.tools.langfuse_ import langfuse_context, observe
|
72
61
|
from prediction_market_agent_tooling.tools.utils import DatetimeUTC, utcnow
|
73
|
-
from prediction_market_agent_tooling.tools.web3_utils import ipfscidv0_to_byte32
|
74
62
|
|
75
63
|
MAX_AVAILABLE_MARKETS = 20
|
76
64
|
TRADER_TAG = "trader"
|
@@ -122,11 +110,6 @@ class OutOfFundsError(ValueError):
|
|
122
110
|
pass
|
123
111
|
|
124
112
|
|
125
|
-
class ProcessedMarket(BaseModel):
|
126
|
-
answer: ProbabilisticAnswer
|
127
|
-
trades: list[PlacedTrade]
|
128
|
-
|
129
|
-
|
130
113
|
class AnsweredEnum(str, Enum):
|
131
114
|
ANSWERED = "answered"
|
132
115
|
NOT_ANSWERED = "not_answered"
|
@@ -183,9 +166,11 @@ class DeployableAgent:
|
|
183
166
|
return f"{self.__class__.__name__} - {self.start_time.strftime('%Y-%m-%d %H:%M:%S')}"
|
184
167
|
|
185
168
|
def __init_subclass__(cls, **kwargs: t.Any) -> None:
|
186
|
-
if
|
187
|
-
cls.__init__
|
188
|
-
|
169
|
+
if (
|
170
|
+
"DeployableAgent" not in str(cls.__init__)
|
171
|
+
and "DeployableTraderAgent" not in str(cls.__init__)
|
172
|
+
and "DeployablePredictionAgent" not in str(cls.__init__)
|
173
|
+
):
|
189
174
|
raise TypeError(
|
190
175
|
"Cannot override __init__ method of deployable agent class, please override the `load` method to set up the agent."
|
191
176
|
)
|
@@ -292,29 +277,21 @@ def {entrypoint_function_name}(request) -> str:
|
|
292
277
|
return f"{self.__class__.__name__.lower()}-{market_type}-{utcnow().strftime('%Y-%m-%d--%H-%M-%S')}"
|
293
278
|
|
294
279
|
|
295
|
-
class
|
280
|
+
class DeployablePredictionAgent(DeployableAgent):
|
296
281
|
bet_on_n_markets_per_run: int = 1
|
297
|
-
min_required_balance_to_operate: xDai | None = xdai_type(1)
|
298
282
|
min_balance_to_keep_in_native_currency: xDai | None = xdai_type(0.1)
|
299
283
|
allow_invalid_questions: bool = False
|
300
284
|
same_market_bet_interval: timedelta = timedelta(hours=24)
|
285
|
+
# Only Metaculus allows to post predictions without trading (buying/selling of outcome tokens).
|
286
|
+
supported_markets: t.Sequence[MarketType] = [MarketType.METACULUS]
|
301
287
|
|
302
288
|
def __init__(
|
303
289
|
self,
|
304
290
|
enable_langfuse: bool = APIKeys().default_enable_langfuse,
|
305
|
-
|
291
|
+
store_prediction: bool = True,
|
306
292
|
) -> None:
|
307
293
|
super().__init__(enable_langfuse=enable_langfuse)
|
308
|
-
self.
|
309
|
-
|
310
|
-
def get_betting_strategy(self, market: AgentMarket) -> BettingStrategy:
|
311
|
-
user_id = market.get_user_id(api_keys=APIKeys())
|
312
|
-
|
313
|
-
total_amount = market.get_tiny_bet_amount().amount
|
314
|
-
if existing_position := market.get_position(user_id=user_id):
|
315
|
-
total_amount += existing_position.total_amount.amount
|
316
|
-
|
317
|
-
return MaxAccuracyBettingStrategy(bet_amount=total_amount)
|
294
|
+
self.store_prediction = store_prediction
|
318
295
|
|
319
296
|
def initialize_langfuse(self) -> None:
|
320
297
|
super().initialize_langfuse()
|
@@ -323,7 +300,6 @@ class DeployableTraderAgent(DeployableAgent):
|
|
323
300
|
self.verify_market = observe()(self.verify_market) # type: ignore[method-assign]
|
324
301
|
self.answer_binary_market = observe()(self.answer_binary_market) # type: ignore[method-assign]
|
325
302
|
self.process_market = observe()(self.process_market) # type: ignore[method-assign]
|
326
|
-
self.build_trades = observe()(self.build_trades) # type: ignore[method-assign]
|
327
303
|
|
328
304
|
def update_langfuse_trace_by_market(
|
329
305
|
self, market_type: MarketType, market: AgentMarket
|
@@ -353,38 +329,12 @@ class DeployableTraderAgent(DeployableAgent):
|
|
353
329
|
]
|
354
330
|
)
|
355
331
|
|
356
|
-
def check_min_required_balance_to_operate(
|
357
|
-
self,
|
358
|
-
market_type: MarketType,
|
359
|
-
check_for_gas: bool = True,
|
360
|
-
check_for_trades: bool = True,
|
361
|
-
) -> None:
|
332
|
+
def check_min_required_balance_to_operate(self, market_type: MarketType) -> None:
|
362
333
|
api_keys = APIKeys()
|
363
|
-
|
364
|
-
|
365
|
-
and check_for_gas
|
366
|
-
and not is_minimum_required_balance(
|
367
|
-
api_keys.public_key,
|
368
|
-
min_required_balance=xdai_type(0.001),
|
369
|
-
sum_wxdai=False,
|
370
|
-
)
|
371
|
-
):
|
334
|
+
|
335
|
+
if not market_type.market_class.verify_operational_balance(api_keys):
|
372
336
|
raise CantPayForGasError(
|
373
|
-
f"{api_keys
|
374
|
-
)
|
375
|
-
if self.min_required_balance_to_operate is None:
|
376
|
-
return
|
377
|
-
if (
|
378
|
-
market_type == MarketType.OMEN
|
379
|
-
and check_for_trades
|
380
|
-
and not is_minimum_required_balance(
|
381
|
-
api_keys.bet_from_address,
|
382
|
-
min_required_balance=self.min_required_balance_to_operate,
|
383
|
-
)
|
384
|
-
):
|
385
|
-
raise OutOfFundsError(
|
386
|
-
f"Minimum required balance {self.min_required_balance_to_operate} "
|
387
|
-
f"for agent with address {api_keys.bet_from_address=} is not met."
|
337
|
+
f"{api_keys=} doesn't have enough operational balance."
|
388
338
|
)
|
389
339
|
|
390
340
|
def have_bet_on_market_since(self, market: AgentMarket, since: timedelta) -> bool:
|
@@ -431,21 +381,19 @@ class DeployableTraderAgent(DeployableAgent):
|
|
431
381
|
)
|
432
382
|
return available_markets
|
433
383
|
|
434
|
-
def build_trades(
|
435
|
-
self,
|
436
|
-
market: AgentMarket,
|
437
|
-
answer: ProbabilisticAnswer,
|
438
|
-
existing_position: Position | None,
|
439
|
-
) -> list[Trade]:
|
440
|
-
strategy = self.get_betting_strategy(market=market)
|
441
|
-
trades = strategy.calculate_trades(existing_position, answer, market)
|
442
|
-
BettingStrategy.assert_trades_currency_match_markets(market, trades)
|
443
|
-
return trades
|
444
|
-
|
445
384
|
def before_process_market(
|
446
385
|
self, market_type: MarketType, market: AgentMarket
|
447
386
|
) -> None:
|
448
|
-
|
387
|
+
api_keys = APIKeys()
|
388
|
+
|
389
|
+
if market_type.is_blockchain_market:
|
390
|
+
# Exchange wxdai back to xdai if the balance is getting low, so we can keep paying for fees.
|
391
|
+
if self.min_balance_to_keep_in_native_currency is not None:
|
392
|
+
withdraw_wxdai_to_xdai_to_keep_balance(
|
393
|
+
api_keys,
|
394
|
+
min_required_balance=self.min_balance_to_keep_in_native_currency,
|
395
|
+
withdraw_multiplier=2,
|
396
|
+
)
|
449
397
|
|
450
398
|
def process_market(
|
451
399
|
self,
|
@@ -453,129 +401,47 @@ class DeployableTraderAgent(DeployableAgent):
|
|
453
401
|
market: AgentMarket,
|
454
402
|
verify_market: bool = True,
|
455
403
|
) -> ProcessedMarket | None:
|
404
|
+
self.update_langfuse_trace_by_market(market_type, market)
|
456
405
|
logger.info(f"Processing market {market.question=} from {market.url=}.")
|
457
406
|
|
458
|
-
|
459
|
-
|
407
|
+
answer: ProbabilisticAnswer | None
|
460
408
|
if verify_market and not self.verify_market(market_type, market):
|
461
409
|
logger.info(f"Market '{market.question}' doesn't meet the criteria.")
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
answer = self.answer_binary_market(market)
|
466
|
-
|
467
|
-
if answer is None:
|
468
|
-
logger.info(f"No answer for market '{market.question}'.")
|
469
|
-
self.update_langfuse_trace_by_processed_market(market_type, None)
|
470
|
-
return None
|
410
|
+
answer = None
|
411
|
+
else:
|
412
|
+
answer = self.answer_binary_market(market)
|
471
413
|
|
472
|
-
|
473
|
-
|
474
|
-
market=market,
|
475
|
-
answer=answer,
|
476
|
-
existing_position=existing_position,
|
414
|
+
processed_market = (
|
415
|
+
ProcessedMarket(answer=answer) if answer is not None else None
|
477
416
|
)
|
478
417
|
|
479
|
-
placed_trades = []
|
480
|
-
if self.place_bet:
|
481
|
-
for trade in trades:
|
482
|
-
logger.info(f"Executing trade {trade} on market {market.id}")
|
483
|
-
|
484
|
-
match trade.trade_type:
|
485
|
-
case TradeType.BUY:
|
486
|
-
id = market.buy_tokens(
|
487
|
-
outcome=trade.outcome, amount=trade.amount
|
488
|
-
)
|
489
|
-
case TradeType.SELL:
|
490
|
-
id = market.sell_tokens(
|
491
|
-
outcome=trade.outcome, amount=trade.amount
|
492
|
-
)
|
493
|
-
case _:
|
494
|
-
raise ValueError(f"Unexpected trade type {trade.trade_type}.")
|
495
|
-
placed_trades.append(PlacedTrade.from_trade(trade, id))
|
496
|
-
|
497
|
-
processed_market = ProcessedMarket(answer=answer, trades=placed_trades)
|
498
418
|
self.update_langfuse_trace_by_processed_market(market_type, processed_market)
|
499
|
-
|
500
|
-
|
501
|
-
market_type, market, processed_market=processed_market
|
419
|
+
logger.info(
|
420
|
+
f"Processed market {market.question=} from {market.url=} with {answer=}."
|
502
421
|
)
|
503
|
-
|
504
|
-
logger.info(f"Processed market {market.question=} from {market.url=}.")
|
505
422
|
return processed_market
|
506
423
|
|
507
424
|
def after_process_market(
|
508
425
|
self,
|
509
426
|
market_type: MarketType,
|
510
427
|
market: AgentMarket,
|
511
|
-
processed_market: ProcessedMarket,
|
428
|
+
processed_market: ProcessedMarket | None,
|
512
429
|
) -> None:
|
513
|
-
if market_type != MarketType.OMEN:
|
514
|
-
logger.info(
|
515
|
-
f"Skipping after_process_market since market_type {market_type} != OMEN"
|
516
|
-
)
|
517
|
-
return
|
518
430
|
keys = APIKeys()
|
519
|
-
self.store_prediction
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
self, market_id: str, processed_market: ProcessedMarket, keys: APIKeys
|
525
|
-
) -> None:
|
526
|
-
reasoning = (
|
527
|
-
processed_market.answer.reasoning
|
528
|
-
if processed_market.answer.reasoning
|
529
|
-
else ""
|
530
|
-
)
|
531
|
-
|
532
|
-
ipfs_hash_decoded = HexBytes(HASH_ZERO)
|
533
|
-
if keys.enable_ipfs_upload:
|
534
|
-
logger.info("Storing prediction on IPFS.")
|
535
|
-
ipfs_hash = IPFSHandler(keys).store_agent_result(
|
536
|
-
IPFSAgentResult(reasoning=reasoning)
|
431
|
+
if self.store_prediction:
|
432
|
+
market.store_prediction(processed_market=processed_market, keys=keys)
|
433
|
+
else:
|
434
|
+
logger.info(
|
435
|
+
f"Prediction {processed_market} not stored because {self.store_prediction=}."
|
537
436
|
)
|
538
|
-
ipfs_hash_decoded = ipfscidv0_to_byte32(ipfs_hash)
|
539
|
-
|
540
|
-
tx_hashes = [
|
541
|
-
HexBytes(HexStr(i.id)) for i in processed_market.trades if i.id is not None
|
542
|
-
]
|
543
|
-
prediction = ContractPrediction(
|
544
|
-
publisher=keys.public_key,
|
545
|
-
ipfs_hash=ipfs_hash_decoded,
|
546
|
-
tx_hashes=tx_hashes,
|
547
|
-
estimated_probability_bps=int(processed_market.answer.p_yes * 10000),
|
548
|
-
)
|
549
|
-
tx_receipt = OmenAgentResultMappingContract().add_prediction(
|
550
|
-
api_keys=keys,
|
551
|
-
market_address=Web3.to_checksum_address(market_id),
|
552
|
-
prediction=prediction,
|
553
|
-
)
|
554
|
-
logger.info(
|
555
|
-
f"Added prediction to market {market_id}. - receipt {tx_receipt['transactionHash'].hex()}."
|
556
|
-
)
|
557
437
|
|
558
438
|
def before_process_markets(self, market_type: MarketType) -> None:
|
559
439
|
"""
|
560
440
|
Executes actions that occur before bets are placed.
|
561
441
|
"""
|
562
442
|
api_keys = APIKeys()
|
563
|
-
|
564
|
-
|
565
|
-
self.check_min_required_balance_to_operate(
|
566
|
-
market_type, check_for_trades=False
|
567
|
-
)
|
568
|
-
# Omen is specific, because the user (agent) needs to manually withdraw winnings from the market.
|
569
|
-
redeem_from_all_user_positions(api_keys)
|
570
|
-
# After redeeming, check if we have enough xDai to pay for gas and place bets.
|
571
|
-
self.check_min_required_balance_to_operate(market_type)
|
572
|
-
# Exchange wxdai back to xdai if the balance is getting low, so we can keep paying for fees.
|
573
|
-
if self.min_balance_to_keep_in_native_currency is not None:
|
574
|
-
withdraw_wxdai_to_xdai_to_keep_balance(
|
575
|
-
api_keys,
|
576
|
-
min_required_balance=self.min_balance_to_keep_in_native_currency,
|
577
|
-
withdraw_multiplier=2,
|
578
|
-
)
|
443
|
+
self.check_min_required_balance_to_operate(market_type)
|
444
|
+
market_type.market_class.redeem_winnings(api_keys)
|
579
445
|
|
580
446
|
def process_markets(self, market_type: MarketType) -> None:
|
581
447
|
"""
|
@@ -589,10 +455,9 @@ class DeployableTraderAgent(DeployableAgent):
|
|
589
455
|
processed = 0
|
590
456
|
|
591
457
|
for market in available_markets:
|
592
|
-
|
593
|
-
self.check_min_required_balance_to_operate(market_type)
|
594
|
-
|
458
|
+
self.before_process_market(market_type, market)
|
595
459
|
processed_market = self.process_market(market_type, market)
|
460
|
+
self.after_process_market(market_type, market, processed_market)
|
596
461
|
|
597
462
|
if processed_market is not None:
|
598
463
|
processed += 1
|
@@ -603,9 +468,142 @@ class DeployableTraderAgent(DeployableAgent):
|
|
603
468
|
logger.info("All markets processed.")
|
604
469
|
|
605
470
|
def after_process_markets(self, market_type: MarketType) -> None:
|
606
|
-
|
471
|
+
"Executes actions that occur after bets are placed."
|
607
472
|
|
608
473
|
def run(self, market_type: MarketType) -> None:
|
474
|
+
if market_type not in self.supported_markets:
|
475
|
+
raise ValueError(
|
476
|
+
f"Only {self.supported_markets} are supported by this agent."
|
477
|
+
)
|
609
478
|
self.before_process_markets(market_type)
|
610
479
|
self.process_markets(market_type)
|
611
480
|
self.after_process_markets(market_type)
|
481
|
+
|
482
|
+
|
483
|
+
class DeployableTraderAgent(DeployablePredictionAgent):
|
484
|
+
# These markets require place of bet, not just predictions.
|
485
|
+
supported_markets: t.Sequence[MarketType] = [
|
486
|
+
MarketType.OMEN,
|
487
|
+
MarketType.MANIFOLD,
|
488
|
+
MarketType.POLYMARKET,
|
489
|
+
]
|
490
|
+
|
491
|
+
def __init__(
|
492
|
+
self,
|
493
|
+
enable_langfuse: bool = APIKeys().default_enable_langfuse,
|
494
|
+
store_prediction: bool = True,
|
495
|
+
store_trades: bool = True,
|
496
|
+
place_trades: bool = True,
|
497
|
+
) -> None:
|
498
|
+
super().__init__(
|
499
|
+
enable_langfuse=enable_langfuse, store_prediction=store_prediction
|
500
|
+
)
|
501
|
+
self.store_trades = store_trades
|
502
|
+
self.place_trades = place_trades
|
503
|
+
|
504
|
+
def initialize_langfuse(self) -> None:
|
505
|
+
super().initialize_langfuse()
|
506
|
+
# Auto-observe all the methods where it makes sense, so that subclassses don't need to do it manually.
|
507
|
+
self.get_betting_strategy = observe()(self.get_betting_strategy) # type: ignore[method-assign]
|
508
|
+
self.build_trades = observe()(self.build_trades) # type: ignore[method-assign]
|
509
|
+
|
510
|
+
def check_min_required_balance_to_trade(self, market: AgentMarket) -> None:
|
511
|
+
api_keys = APIKeys()
|
512
|
+
|
513
|
+
# Get the strategy to know how much it will bet.
|
514
|
+
strategy = self.get_betting_strategy(market)
|
515
|
+
# Have a little bandwidth after the bet.
|
516
|
+
min_required_balance_to_trade = strategy.maximum_possible_bet_amount * 1.01
|
517
|
+
|
518
|
+
if market.get_trade_balance(api_keys) < min_required_balance_to_trade:
|
519
|
+
raise OutOfFundsError(
|
520
|
+
f"Minimum required balance {min_required_balance_to_trade} for agent is not met."
|
521
|
+
)
|
522
|
+
|
523
|
+
def get_betting_strategy(self, market: AgentMarket) -> BettingStrategy:
|
524
|
+
user_id = market.get_user_id(api_keys=APIKeys())
|
525
|
+
|
526
|
+
total_amount = market.get_tiny_bet_amount().amount
|
527
|
+
if existing_position := market.get_position(user_id=user_id):
|
528
|
+
total_amount += existing_position.total_amount.amount
|
529
|
+
|
530
|
+
return MaxAccuracyBettingStrategy(bet_amount=total_amount)
|
531
|
+
|
532
|
+
def build_trades(
|
533
|
+
self,
|
534
|
+
market: AgentMarket,
|
535
|
+
answer: ProbabilisticAnswer,
|
536
|
+
existing_position: Position | None,
|
537
|
+
) -> list[Trade]:
|
538
|
+
strategy = self.get_betting_strategy(market=market)
|
539
|
+
trades = strategy.calculate_trades(existing_position, answer, market)
|
540
|
+
BettingStrategy.assert_trades_currency_match_markets(market, trades)
|
541
|
+
return trades
|
542
|
+
|
543
|
+
def before_process_market(
|
544
|
+
self, market_type: MarketType, market: AgentMarket
|
545
|
+
) -> None:
|
546
|
+
super().before_process_market(market_type, market)
|
547
|
+
self.check_min_required_balance_to_trade(market)
|
548
|
+
|
549
|
+
def process_market(
|
550
|
+
self,
|
551
|
+
market_type: MarketType,
|
552
|
+
market: AgentMarket,
|
553
|
+
verify_market: bool = True,
|
554
|
+
) -> ProcessedTradedMarket | None:
|
555
|
+
processed_market = super().process_market(market_type, market, verify_market)
|
556
|
+
if processed_market is None:
|
557
|
+
return None
|
558
|
+
|
559
|
+
api_keys = APIKeys()
|
560
|
+
existing_position = market.get_position(
|
561
|
+
user_id=market.get_user_id(api_keys=api_keys)
|
562
|
+
)
|
563
|
+
trades = self.build_trades(
|
564
|
+
market=market,
|
565
|
+
answer=processed_market.answer,
|
566
|
+
existing_position=existing_position,
|
567
|
+
)
|
568
|
+
|
569
|
+
placed_trades = []
|
570
|
+
for trade in trades:
|
571
|
+
logger.info(f"Executing trade {trade} on market {market.id} ({market.url})")
|
572
|
+
|
573
|
+
if self.place_trades:
|
574
|
+
match trade.trade_type:
|
575
|
+
case TradeType.BUY:
|
576
|
+
id = market.buy_tokens(
|
577
|
+
outcome=trade.outcome, amount=trade.amount
|
578
|
+
)
|
579
|
+
case TradeType.SELL:
|
580
|
+
id = market.sell_tokens(
|
581
|
+
outcome=trade.outcome, amount=trade.amount
|
582
|
+
)
|
583
|
+
case _:
|
584
|
+
raise ValueError(f"Unexpected trade type {trade.trade_type}.")
|
585
|
+
placed_trades.append(PlacedTrade.from_trade(trade, id))
|
586
|
+
else:
|
587
|
+
logger.info(f"Trade execution skipped because {self.place_trades=}.")
|
588
|
+
|
589
|
+
traded_market = ProcessedTradedMarket(
|
590
|
+
answer=processed_market.answer, trades=placed_trades
|
591
|
+
)
|
592
|
+
logger.info(f"Traded market {market.question=} from {market.url=}.")
|
593
|
+
return traded_market
|
594
|
+
|
595
|
+
def after_process_market(
|
596
|
+
self,
|
597
|
+
market_type: MarketType,
|
598
|
+
market: AgentMarket,
|
599
|
+
processed_market: ProcessedMarket | None,
|
600
|
+
) -> None:
|
601
|
+
api_keys = APIKeys()
|
602
|
+
super().after_process_market(market_type, market, processed_market)
|
603
|
+
if isinstance(processed_market, ProcessedTradedMarket):
|
604
|
+
if self.store_trades:
|
605
|
+
market.store_trades(processed_market, api_keys)
|
606
|
+
else:
|
607
|
+
logger.info(
|
608
|
+
f"Trades {processed_market.trades} not stored because {self.store_trades=}."
|
609
|
+
)
|
@@ -24,6 +24,10 @@ from prediction_market_agent_tooling.tools.betting_strategies.utils import Simpl
|
|
24
24
|
from prediction_market_agent_tooling.tools.utils import check_not_none
|
25
25
|
|
26
26
|
|
27
|
+
class GuaranteedLossError(RuntimeError):
|
28
|
+
pass
|
29
|
+
|
30
|
+
|
27
31
|
class BettingStrategy(ABC):
|
28
32
|
@abstractmethod
|
29
33
|
def calculate_trades(
|
@@ -32,7 +36,12 @@ class BettingStrategy(ABC):
|
|
32
36
|
answer: ProbabilisticAnswer,
|
33
37
|
market: AgentMarket,
|
34
38
|
) -> list[Trade]:
|
35
|
-
|
39
|
+
raise NotImplementedError("Subclass should implement this.")
|
40
|
+
|
41
|
+
@property
|
42
|
+
@abstractmethod
|
43
|
+
def maximum_possible_bet_amount(self) -> float:
|
44
|
+
raise NotImplementedError("Subclass should implement this.")
|
36
45
|
|
37
46
|
def build_zero_token_amount(self, currency: Currency) -> TokenAmount:
|
38
47
|
return TokenAmount(amount=0, currency=currency)
|
@@ -58,7 +67,7 @@ class BettingStrategy(ABC):
|
|
58
67
|
)
|
59
68
|
|
60
69
|
if outcome_tokens_to_get.amount < trade.amount.amount:
|
61
|
-
raise
|
70
|
+
raise GuaranteedLossError(
|
62
71
|
f"Trade {trade=} would result in guaranteed loss by getting only {outcome_tokens_to_get=}."
|
63
72
|
)
|
64
73
|
|
@@ -126,6 +135,10 @@ class MaxAccuracyBettingStrategy(BettingStrategy):
|
|
126
135
|
def __init__(self, bet_amount: float):
|
127
136
|
self.bet_amount = bet_amount
|
128
137
|
|
138
|
+
@property
|
139
|
+
def maximum_possible_bet_amount(self) -> float:
|
140
|
+
return self.bet_amount
|
141
|
+
|
129
142
|
def calculate_trades(
|
130
143
|
self,
|
131
144
|
existing_position: Position | None,
|
@@ -168,6 +181,10 @@ class KellyBettingStrategy(BettingStrategy):
|
|
168
181
|
self.max_bet_amount = max_bet_amount
|
169
182
|
self.max_price_impact = max_price_impact
|
170
183
|
|
184
|
+
@property
|
185
|
+
def maximum_possible_bet_amount(self) -> float:
|
186
|
+
return self.max_bet_amount
|
187
|
+
|
171
188
|
def calculate_trades(
|
172
189
|
self,
|
173
190
|
existing_position: Position | None,
|
@@ -282,6 +299,10 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
282
299
|
def __init__(self, max_bet_amount: float = 10):
|
283
300
|
self.max_bet_amount = max_bet_amount
|
284
301
|
|
302
|
+
@property
|
303
|
+
def maximum_possible_bet_amount(self) -> float:
|
304
|
+
return self.max_bet_amount
|
305
|
+
|
285
306
|
def adjust_bet_amount(
|
286
307
|
self, existing_position: Position | None, market: AgentMarket
|
287
308
|
) -> float:
|
@@ -11,7 +11,9 @@ from prediction_market_agent_tooling.markets.data_models import (
|
|
11
11
|
Bet,
|
12
12
|
BetAmount,
|
13
13
|
Currency,
|
14
|
+
PlacedTrade,
|
14
15
|
Position,
|
16
|
+
ProbabilisticAnswer,
|
15
17
|
Resolution,
|
16
18
|
ResolvedBet,
|
17
19
|
TokenAmount,
|
@@ -25,6 +27,14 @@ from prediction_market_agent_tooling.tools.utils import (
|
|
25
27
|
)
|
26
28
|
|
27
29
|
|
30
|
+
class ProcessedMarket(BaseModel):
|
31
|
+
answer: ProbabilisticAnswer
|
32
|
+
|
33
|
+
|
34
|
+
class ProcessedTradedMarket(ProcessedMarket):
|
35
|
+
trades: list[PlacedTrade]
|
36
|
+
|
37
|
+
|
28
38
|
class SortBy(str, Enum):
|
29
39
|
CLOSING_SOONEST = "closing-soonest"
|
30
40
|
NEWEST = "newest"
|
@@ -198,6 +208,44 @@ class AgentMarket(BaseModel):
|
|
198
208
|
def get_binary_market(id: str) -> "AgentMarket":
|
199
209
|
raise NotImplementedError("Subclasses must implement this method")
|
200
210
|
|
211
|
+
@staticmethod
|
212
|
+
def redeem_winnings(api_keys: APIKeys) -> None:
|
213
|
+
"""
|
214
|
+
On some markets (like Omen), it's needed to manually claim the winner bets. If it's not needed, just implement with `pass`.
|
215
|
+
"""
|
216
|
+
raise NotImplementedError("Subclasses must implement this method")
|
217
|
+
|
218
|
+
@staticmethod
|
219
|
+
def get_trade_balance(api_keys: APIKeys) -> float:
|
220
|
+
"""
|
221
|
+
Return balance that can be used to trade on the given market.
|
222
|
+
"""
|
223
|
+
raise NotImplementedError("Subclasses must implement this method")
|
224
|
+
|
225
|
+
@staticmethod
|
226
|
+
def verify_operational_balance(api_keys: APIKeys) -> bool:
|
227
|
+
"""
|
228
|
+
Return `True` if the user has enough of operational balance. If not needed, just return `True`.
|
229
|
+
For example: Omen needs at least some xDai in the wallet to execute transactions.
|
230
|
+
"""
|
231
|
+
raise NotImplementedError("Subclasses must implement this method")
|
232
|
+
|
233
|
+
def store_prediction(
|
234
|
+
self, processed_market: ProcessedMarket | None, keys: APIKeys
|
235
|
+
) -> None:
|
236
|
+
"""
|
237
|
+
If market allows to upload predictions somewhere, implement it in this method.
|
238
|
+
"""
|
239
|
+
raise NotImplementedError("Subclasses must implement this method")
|
240
|
+
|
241
|
+
def store_trades(
|
242
|
+
self, traded_market: ProcessedTradedMarket | None, keys: APIKeys
|
243
|
+
) -> None:
|
244
|
+
"""
|
245
|
+
If market allows to upload trades somewhere, implement it in this method.
|
246
|
+
"""
|
247
|
+
raise NotImplementedError("Subclasses must implement this method")
|
248
|
+
|
201
249
|
@staticmethod
|
202
250
|
def get_bets_made_since(
|
203
251
|
better_address: ChecksumAddress, start_time: DatetimeUTC
|
@@ -125,6 +125,11 @@ class ManifoldAgentMarket(AgentMarket):
|
|
125
125
|
)
|
126
126
|
]
|
127
127
|
|
128
|
+
@staticmethod
|
129
|
+
def redeem_winnings(api_keys: APIKeys) -> None:
|
130
|
+
# It's done automatically on Manifold.
|
131
|
+
pass
|
132
|
+
|
128
133
|
@classmethod
|
129
134
|
def get_user_url(cls, keys: APIKeys) -> str:
|
130
135
|
return get_authenticated_user(keys.manifold_api_key.get_secret_value()).url
|
@@ -46,6 +46,10 @@ class MarketType(str, Enum):
|
|
46
46
|
raise ValueError(f"Unknown market type: {self}")
|
47
47
|
return MARKET_TYPE_TO_AGENT_MARKET[self]
|
48
48
|
|
49
|
+
@property
|
50
|
+
def is_blockchain_market(self) -> bool:
|
51
|
+
return self in [MarketType.OMEN, MarketType.POLYMARKET]
|
52
|
+
|
49
53
|
|
50
54
|
MARKET_TYPE_TO_AGENT_MARKET: dict[MarketType, type[AgentMarket]] = {
|
51
55
|
MarketType.MANIFOLD: ManifoldAgentMarket,
|