prediction-market-agent-tooling 0.26.0__tar.gz → 0.28.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.
Files changed (71) hide show
  1. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/PKG-INFO +1 -1
  2. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/config.py +12 -29
  3. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/agent.py +2 -4
  4. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/loggers.py +21 -0
  5. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/agent_market.py +18 -1
  6. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/markets.py +2 -3
  7. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/omen.py +63 -59
  8. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +29 -31
  9. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +15 -15
  10. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +9 -9
  11. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/markets/omen.py +3 -5
  12. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/markets/polymarket.py +2 -3
  13. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/contract.py +16 -16
  14. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/pyproject.toml +1 -1
  15. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/LICENSE +0 -0
  16. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/README.md +0 -0
  17. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
  18. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
  19. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
  20. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
  21. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
  22. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
  23. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
  24. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
  25. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/wxdai.abi.json +0 -0
  26. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
  27. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
  28. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
  29. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
  30. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
  31. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
  32. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
  33. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
  34. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
  35. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/gtypes.py +0 -0
  36. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
  37. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/data_models.py +0 -0
  38. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
  39. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
  40. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
  41. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
  42. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
  43. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
  44. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/data_models.py +0 -0
  45. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
  46. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
  47. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
  48. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
  49. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
  50. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/langfuse/langfuse_wrapper.py +0 -0
  51. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
  52. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/monitor.py +0 -0
  53. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
  54. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
  55. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/py.typed +0 -0
  56. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/balances.py +0 -0
  57. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
  58. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
  59. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
  60. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
  61. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/cache.py +0 -0
  62. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/costs.py +0 -0
  63. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -0
  64. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/google.py +0 -0
  65. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
  66. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
  67. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
  68. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/safe.py +0 -0
  69. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
  70. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/utils.py +0 -0
  71. {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.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.26.0
3
+ Version: 0.28.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
@@ -2,7 +2,6 @@ import typing as t
2
2
 
3
3
  from gnosis.eth import EthereumClient
4
4
  from gnosis.safe import Safe
5
- from pydantic import BaseModel
6
5
  from pydantic.types import SecretStr
7
6
  from pydantic_settings import BaseSettings, SettingsConfigDict
8
7
 
@@ -58,6 +57,15 @@ class APIKeys(BaseSettings):
58
57
  "BET_FROM_PRIVATE_KEY missing in the environment.",
59
58
  )
60
59
 
60
+ @property
61
+ def bet_from_address(self) -> ChecksumAddress:
62
+ """If the SAFE is available, we always route transactions via SAFE. Otherwise we use the EOA."""
63
+ return (
64
+ self.SAFE_ADDRESS
65
+ if self.SAFE_ADDRESS
66
+ else private_key_to_public_key(self.bet_from_private_key)
67
+ )
68
+
61
69
  @property
62
70
  def openai_api_key(self) -> SecretStr:
63
71
  return check_not_none(
@@ -110,35 +118,10 @@ class APIKeys(BaseSettings):
110
118
  if APIKeys.model_fields[k].annotation in SECRET_TYPES and v is not None
111
119
  }
112
120
 
113
-
114
- class PrivateCredentials(BaseModel):
115
- private_key: PrivateKey
116
- safe_address: ChecksumAddress | None
117
-
118
- @property
119
- def public_key(self) -> ChecksumAddress:
120
- """If the SAFE is available, we always route transactions via SAFE. Otherwise we use the EOA."""
121
- return (
122
- self.safe_address
123
- if self.safe_address is not None
124
- else private_key_to_public_key(self.private_key)
125
- )
126
-
127
- @property
128
- def has_safe_address(self) -> bool:
129
- return self.safe_address is not None
130
-
131
- @staticmethod
132
- def from_api_keys(api_keys: APIKeys) -> "PrivateCredentials":
133
- return PrivateCredentials(
134
- private_key=api_keys.bet_from_private_key,
135
- safe_address=api_keys.SAFE_ADDRESS,
136
- )
137
-
138
121
  def check_if_is_safe_owner(self, ethereum_client: EthereumClient) -> bool:
139
- if not self.safe_address:
122
+ if not self.SAFE_ADDRESS:
140
123
  raise ValueError("Cannot check ownership if safe_address is not defined.")
141
124
 
142
- s = Safe(self.safe_address, ethereum_client) # type: ignore[abstract]
143
- public_key_from_signer = private_key_to_public_key(self.private_key)
125
+ s = Safe(self.SAFE_ADDRESS, ethereum_client) # type: ignore[abstract]
126
+ public_key_from_signer = private_key_to_public_key(self.bet_from_private_key)
144
127
  return s.retrieve_is_owner(public_key_from_signer)
@@ -8,7 +8,7 @@ from datetime import datetime, timedelta
8
8
  from pydantic import BaseModel, BeforeValidator
9
9
  from typing_extensions import Annotated
10
10
 
11
- from prediction_market_agent_tooling.config import APIKeys, PrivateCredentials
11
+ from prediction_market_agent_tooling.config import APIKeys
12
12
  from prediction_market_agent_tooling.deploy.constants import (
13
13
  MARKET_TYPE_KEY,
14
14
  REPOSITORY_KEY,
@@ -260,11 +260,9 @@ class DeployableTraderAgent(DeployableAgent):
260
260
  """
261
261
  Executes actions that occur before bets are placed.
262
262
  """
263
- private_credentials = PrivateCredentials.from_api_keys(APIKeys())
264
-
265
263
  if market_type == MarketType.OMEN:
266
264
  # Omen is specific, because the user (agent) needs to manually withdraw winnings from the market.
267
- redeem_from_all_user_positions(private_credentials)
265
+ redeem_from_all_user_positions(APIKeys())
268
266
 
269
267
  def process_bets(self, market_type: MarketType) -> None:
270
268
  """
@@ -1,5 +1,7 @@
1
+ import builtins
1
2
  import logging
2
3
  import sys
4
+ import typing as t
3
5
  import warnings
4
6
  from enum import Enum
5
7
 
@@ -35,9 +37,11 @@ def patch_logger() -> None:
35
37
  format_loguru = GCP_LOG_LOGURU_FORMAT
36
38
  format_logging = GCP_LOG_LOGGING_FORMAT
37
39
  datefmt_logging = GCP_LOG_FORMAT_LOGGING_DATEFMT
40
+ print_logging = print_using_loguru_info
38
41
 
39
42
  elif config.LOG_FORMAT == LogFormat.DEFAULT:
40
43
  format_loguru, format_logging, datefmt_logging = None, None, None
44
+ print_logging = None
41
45
 
42
46
  else:
43
47
  raise ValueError(f"Unknown log format: {config.LOG_FORMAT}")
@@ -63,9 +67,26 @@ def patch_logger() -> None:
63
67
  # Use logging module for warnings.
64
68
  logging.captureWarnings(True)
65
69
 
70
+ # Use loguru for prints.
71
+ if print_logging is not None:
72
+ builtins.print = print_logging # type: ignore[assignment] # Monkey patching, it's messy but it works.
73
+
66
74
  logger.info(f"Patched logger for {config.LOG_FORMAT.value} format.")
67
75
 
68
76
 
77
+ def print_using_loguru_info(
78
+ *values: object,
79
+ sep: str = " ",
80
+ end: str = "\n",
81
+ **kwargs: t.Any,
82
+ ) -> None:
83
+ message = sep.join(map(str, values)) + end
84
+ message = message.strip().replace(
85
+ "\n", "\\n"
86
+ ) # Escape new lines, because otherwise logs will be broken.
87
+ logger.info(message)
88
+
89
+
69
90
  def simple_warning_format(message, category, filename, lineno, line=None): # type: ignore[no-untyped-def] # Not typed in the standard library neither.
70
91
  return f"{category.__name__}: {message}"
71
92
 
@@ -18,6 +18,7 @@ from prediction_market_agent_tooling.tools.utils import (
18
18
  add_utc_timezone_validator,
19
19
  check_not_none,
20
20
  should_not_happen,
21
+ utcnow,
21
22
  )
22
23
 
23
24
 
@@ -147,9 +148,18 @@ class AgentMarket(BaseModel):
147
148
  ) -> list[Bet]:
148
149
  raise NotImplementedError("Subclasses must implement this method")
149
150
 
151
+ def is_closed(self) -> bool:
152
+ return self.close_time is not None and self.close_time <= utcnow()
153
+
150
154
  def is_resolved(self) -> bool:
151
155
  return self.resolution is not None
152
156
 
157
+ def get_liquidity(self) -> TokenAmount:
158
+ raise NotImplementedError("Subclasses must implement this method")
159
+
160
+ def has_liquidity(self) -> bool:
161
+ return self.get_liquidity().amount > 0
162
+
153
163
  def has_successful_resolution(self) -> bool:
154
164
  return self.resolution in [Resolution.YES, Resolution.NO]
155
165
 
@@ -174,8 +184,15 @@ class AgentMarket(BaseModel):
174
184
  raise NotImplementedError("Subclasses must implement this method")
175
185
 
176
186
  @classmethod
177
- def get_positions(cls, user_id: str) -> list[Position]:
187
+ def get_positions(cls, user_id: str, liquid_only: bool = False) -> list[Position]:
178
188
  """
179
189
  Get all non-zero positions a user has in any market.
190
+
191
+ If `liquid_only` is True, only return positions that can be sold.
180
192
  """
181
193
  raise NotImplementedError("Subclasses must implement this method")
194
+
195
+ def can_be_traded(self) -> bool:
196
+ if self.is_closed() or not self.has_liquidity():
197
+ return False
198
+ return True
@@ -2,7 +2,7 @@ import typing as t
2
2
  from datetime import datetime, timedelta
3
3
  from enum import Enum
4
4
 
5
- from prediction_market_agent_tooling.config import APIKeys, PrivateCredentials
5
+ from prediction_market_agent_tooling.config import APIKeys
6
6
  from prediction_market_agent_tooling.markets.agent_market import (
7
7
  AgentMarket,
8
8
  FilterBy,
@@ -68,7 +68,6 @@ def have_bet_on_market_since(
68
68
  keys: APIKeys, market: AgentMarket, since: timedelta
69
69
  ) -> bool:
70
70
  start_time = utcnow() - since
71
- credentials = PrivateCredentials.from_api_keys(keys)
72
71
  recently_betted_questions = (
73
72
  set(
74
73
  get_manifold_market(b.contractId).question
@@ -85,7 +84,7 @@ def have_bet_on_market_since(
85
84
  set(
86
85
  b.title
87
86
  for b in OmenSubgraphHandler().get_bets(
88
- better_address=credentials.public_key,
87
+ better_address=keys.bet_from_address,
89
88
  start_time=start_time,
90
89
  )
91
90
  )
@@ -5,7 +5,7 @@ from datetime import datetime
5
5
  from web3 import Web3
6
6
  from web3.constants import HASH_ZERO
7
7
 
8
- from prediction_market_agent_tooling.config import APIKeys, PrivateCredentials
8
+ from prediction_market_agent_tooling.config import APIKeys
9
9
  from prediction_market_agent_tooling.gtypes import (
10
10
  ChecksumAddress,
11
11
  HexAddress,
@@ -117,11 +117,17 @@ class OmenAgentMarket(AgentMarket):
117
117
  else None
118
118
  )
119
119
 
120
- def get_liquidity(self) -> Wei:
120
+ def get_liquidity_in_wei(self) -> Wei:
121
121
  return self.get_contract().totalSupply()
122
122
 
123
123
  def get_liquidity_in_xdai(self) -> xDai:
124
- return wei_to_xdai(self.get_liquidity())
124
+ return wei_to_xdai(self.get_liquidity_in_wei())
125
+
126
+ def get_liquidity(self) -> TokenAmount:
127
+ return TokenAmount(
128
+ amount=self.get_liquidity_in_xdai(),
129
+ currency=Currency.xDai,
130
+ )
125
131
 
126
132
  def get_tiny_bet_amount(self) -> BetAmount:
127
133
  return BetAmount(amount=0.00001, currency=self.currency)
@@ -133,13 +139,15 @@ class OmenAgentMarket(AgentMarket):
133
139
  omen_auto_deposit: bool = True,
134
140
  web3: Web3 | None = None,
135
141
  ) -> None:
142
+ if not self.can_be_traded():
143
+ raise ValueError(
144
+ f"Market {self.id} is not open for trading. Cannot place bet."
145
+ )
136
146
  if amount.currency != self.currency:
137
147
  raise ValueError(f"Omen bets are made in xDai. Got {amount.currency}.")
138
148
  amount_xdai = xDai(amount.amount)
139
- keys = APIKeys()
140
- private_credentials = PrivateCredentials.from_api_keys(keys)
141
149
  binary_omen_buy_outcome_tx(
142
- private_credentials=private_credentials,
150
+ api_keys=APIKeys(),
143
151
  amount=amount_xdai,
144
152
  market=self,
145
153
  binary_outcome=outcome,
@@ -150,10 +158,12 @@ class OmenAgentMarket(AgentMarket):
150
158
  def sell_tokens(
151
159
  self, outcome: bool, amount: TokenAmount, auto_withdraw: bool = True
152
160
  ) -> None:
153
- keys = APIKeys()
154
- private_credentials = PrivateCredentials.from_api_keys(keys)
161
+ if not self.can_be_traded():
162
+ raise ValueError(
163
+ f"Market {self.id} is not open for trading. Cannot sell tokens."
164
+ )
155
165
  binary_omen_sell_outcome_tx(
156
- private_credentials=private_credentials,
166
+ api_keys=APIKeys(),
157
167
  amount=xDai(amount.amount),
158
168
  market=self,
159
169
  binary_outcome=outcome,
@@ -206,9 +216,9 @@ class OmenAgentMarket(AgentMarket):
206
216
 
207
217
  def redeem_positions(
208
218
  self,
209
- private_credentials: PrivateCredentials,
219
+ api_keys: APIKeys,
210
220
  ) -> None:
211
- for_public_key = private_credentials.public_key
221
+ for_public_key = api_keys.bet_from_address
212
222
  market_is_redeemable = self.market_redeemable_by(user=for_public_key)
213
223
  if not market_is_redeemable:
214
224
  logger.debug(
@@ -216,9 +226,7 @@ class OmenAgentMarket(AgentMarket):
216
226
  )
217
227
  return None
218
228
 
219
- omen_redeem_full_position_tx(
220
- private_credentials=private_credentials, market=self
221
- )
229
+ omen_redeem_full_position_tx(api_keys=api_keys, market=self)
222
230
 
223
231
  @staticmethod
224
232
  def from_data_model(model: OmenMarket) -> "OmenAgentMarket":
@@ -273,9 +281,6 @@ class OmenAgentMarket(AgentMarket):
273
281
  bets = OmenSubgraphHandler().get_bets(
274
282
  better_address=better_address, start_time=start_time
275
283
  )
276
- # get unique titles
277
- seen_titles = {bet.title: bet for bet in bets}
278
- bets = list(seen_titles.values())
279
284
  bets.sort(key=lambda x: x.creation_datetime)
280
285
  return [b.to_bet() for b in bets]
281
286
 
@@ -310,7 +315,7 @@ class OmenAgentMarket(AgentMarket):
310
315
  )
311
316
 
312
317
  @classmethod
313
- def get_positions(cls, user_id: str) -> list[Position]:
318
+ def get_positions(cls, user_id: str, liquid_only: bool = False) -> list[Position]:
314
319
  sgh = OmenSubgraphHandler()
315
320
  omen_positions = sgh.get_user_positions(
316
321
  better_address=Web3.to_checksum_address(user_id),
@@ -338,6 +343,11 @@ class OmenAgentMarket(AgentMarket):
338
343
  positions = []
339
344
  for condition_id, omen_positions in omen_positions_dict.items():
340
345
  market = cls.from_data_model(omen_markets[condition_id])
346
+
347
+ # Skip markets that cannot be traded if `liquid_only`` is True.
348
+ if liquid_only and not market.can_be_traded():
349
+ continue
350
+
341
351
  amounts: dict[OutcomeStr, TokenAmount] = {}
342
352
  for omen_position in omen_positions:
343
353
  outecome_str = market.index_set_to_outcome_str(
@@ -370,7 +380,7 @@ def pick_binary_market(
370
380
 
371
381
 
372
382
  def omen_buy_outcome_tx(
373
- private_credentials: PrivateCredentials,
383
+ api_keys: APIKeys,
374
384
  amount: xDai,
375
385
  market: OmenAgentMarket,
376
386
  outcome: str,
@@ -381,7 +391,7 @@ def omen_buy_outcome_tx(
381
391
  Bets the given amount of xDai for the given outcome in the given market.
382
392
  """
383
393
  amount_wei = xdai_to_wei(amount)
384
- from_address_checksummed = private_credentials.public_key
394
+ from_address_checksummed = api_keys.bet_from_address
385
395
 
386
396
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
387
397
 
@@ -398,7 +408,7 @@ def omen_buy_outcome_tx(
398
408
  expected_shares = remove_fraction(expected_shares, 0.01)
399
409
  # Approve the market maker to withdraw our collateral token.
400
410
  collateral_token_contract.approve(
401
- private_credentials=private_credentials,
411
+ api_keys=api_keys,
402
412
  for_address=market_contract.address,
403
413
  amount_wei=amount_wei,
404
414
  web3=web3,
@@ -410,11 +420,11 @@ def omen_buy_outcome_tx(
410
420
  )
411
421
  if auto_deposit and collateral_token_balance < amount_wei:
412
422
  collateral_token_contract.deposit(
413
- private_credentials=private_credentials, amount_wei=amount_wei, web3=web3
423
+ api_keys=api_keys, amount_wei=amount_wei, web3=web3
414
424
  )
415
425
  # Buy shares using the deposited xDai in the collateral token.
416
426
  market_contract.buy(
417
- private_credentials=private_credentials,
427
+ api_keys=api_keys,
418
428
  amount_wei=amount_wei,
419
429
  outcome_index=outcome_index,
420
430
  min_outcome_tokens_to_buy=expected_shares,
@@ -423,7 +433,7 @@ def omen_buy_outcome_tx(
423
433
 
424
434
 
425
435
  def binary_omen_buy_outcome_tx(
426
- private_credentials: PrivateCredentials,
436
+ api_keys: APIKeys,
427
437
  amount: xDai,
428
438
  market: OmenAgentMarket,
429
439
  binary_outcome: bool,
@@ -431,7 +441,7 @@ def binary_omen_buy_outcome_tx(
431
441
  web3: Web3 | None = None,
432
442
  ) -> None:
433
443
  omen_buy_outcome_tx(
434
- private_credentials=private_credentials,
444
+ api_keys=api_keys,
435
445
  amount=amount,
436
446
  market=market,
437
447
  outcome=OMEN_TRUE_OUTCOME if binary_outcome else OMEN_FALSE_OUTCOME,
@@ -441,7 +451,7 @@ def binary_omen_buy_outcome_tx(
441
451
 
442
452
 
443
453
  def omen_sell_outcome_tx(
444
- private_credentials: PrivateCredentials,
454
+ api_keys: APIKeys,
445
455
  amount: xDai, # The xDai value of shares to sell.
446
456
  market: OmenAgentMarket,
447
457
  outcome: str,
@@ -482,14 +492,14 @@ def omen_sell_outcome_tx(
482
492
 
483
493
  # Approve the market maker to move our (all) conditional tokens.
484
494
  conditional_token_contract.setApprovalForAll(
485
- private_credentials=private_credentials,
495
+ api_keys=api_keys,
486
496
  for_address=market_contract.address,
487
497
  approve=True,
488
498
  web3=web3,
489
499
  )
490
500
  # Sell the shares.
491
501
  market_contract.sell(
492
- private_credentials,
502
+ api_keys,
493
503
  amount_wei,
494
504
  outcome_index,
495
505
  max_outcome_tokens_to_sell,
@@ -497,13 +507,11 @@ def omen_sell_outcome_tx(
497
507
  )
498
508
  if auto_withdraw:
499
509
  # Optionally, withdraw from the collateral token back to the `from_address` wallet.
500
- collateral_token.withdraw(
501
- private_credentials=private_credentials, amount_wei=amount_wei, web3=web3
502
- )
510
+ collateral_token.withdraw(api_keys=api_keys, amount_wei=amount_wei, web3=web3)
503
511
 
504
512
 
505
513
  def binary_omen_sell_outcome_tx(
506
- private_credentials: PrivateCredentials,
514
+ api_keys: APIKeys,
507
515
  amount: xDai,
508
516
  market: OmenAgentMarket,
509
517
  binary_outcome: bool,
@@ -511,7 +519,7 @@ def binary_omen_sell_outcome_tx(
511
519
  web3: Web3 | None = None,
512
520
  ) -> None:
513
521
  omen_sell_outcome_tx(
514
- private_credentials=private_credentials,
522
+ api_keys=api_keys,
515
523
  amount=amount,
516
524
  market=market,
517
525
  outcome=OMEN_TRUE_OUTCOME if binary_outcome else OMEN_FALSE_OUTCOME,
@@ -521,7 +529,7 @@ def binary_omen_sell_outcome_tx(
521
529
 
522
530
 
523
531
  def omen_create_market_tx(
524
- private_credentials: PrivateCredentials,
532
+ api_keys: APIKeys,
525
533
  initial_funds: xDai,
526
534
  question: str,
527
535
  closing_time: datetime,
@@ -535,7 +543,7 @@ def omen_create_market_tx(
535
543
  """
536
544
  Based on omen-exchange TypeScript code: https://github.com/protofire/omen-exchange/blob/b0b9a3e71b415d6becf21fe428e1c4fc0dad2e80/app/src/services/cpk/cpk.ts#L308
537
545
  """
538
- from_address = private_credentials.public_key
546
+ from_address = api_keys.bet_from_address
539
547
  initial_funds_wei = xdai_to_wei(initial_funds)
540
548
 
541
549
  realitio_contract = OmenRealitioContract()
@@ -558,7 +566,7 @@ def omen_create_market_tx(
558
566
 
559
567
  # Approve the market maker to withdraw our collateral token.
560
568
  collateral_token_contract.approve(
561
- private_credentials=private_credentials,
569
+ api_keys=api_keys,
562
570
  for_address=factory_contract.address,
563
571
  amount_wei=initial_funds_wei,
564
572
  web3=web3,
@@ -574,13 +582,11 @@ def omen_create_market_tx(
574
582
  and initial_funds_wei > 0
575
583
  and collateral_token_balance < initial_funds_wei
576
584
  ):
577
- collateral_token_contract.deposit(
578
- private_credentials, initial_funds_wei, web3=web3
579
- )
585
+ collateral_token_contract.deposit(api_keys, initial_funds_wei, web3=web3)
580
586
 
581
587
  # Create the question on Realitio.
582
588
  question_id = realitio_contract.askQuestion(
583
- private_credentials=private_credentials,
589
+ api_keys=api_keys,
584
590
  question=question,
585
591
  category=category,
586
592
  outcomes=outcomes,
@@ -599,7 +605,7 @@ def omen_create_market_tx(
599
605
  )
600
606
  if not conditional_token_contract.does_condition_exists(condition_id, web3=web3):
601
607
  conditional_token_contract.prepareCondition(
602
- private_credentials=private_credentials,
608
+ api_keys=api_keys,
603
609
  question_id=question_id,
604
610
  oracle_address=oracle_contract.address,
605
611
  outcomes_slot_count=len(outcomes),
@@ -608,7 +614,7 @@ def omen_create_market_tx(
608
614
 
609
615
  # Create the market.
610
616
  create_market_receipt_tx = factory_contract.create2FixedProductMarketMaker(
611
- private_credentials=private_credentials,
617
+ api_keys=api_keys,
612
618
  condition_id=condition_id,
613
619
  fee=fee,
614
620
  initial_funds_wei=initial_funds_wei,
@@ -627,13 +633,13 @@ def omen_create_market_tx(
627
633
 
628
634
 
629
635
  def omen_fund_market_tx(
630
- private_credentials: PrivateCredentials,
636
+ api_keys: APIKeys,
631
637
  market: OmenAgentMarket,
632
638
  funds: Wei,
633
639
  auto_deposit: bool,
634
640
  web3: Web3 | None = None,
635
641
  ) -> None:
636
- from_address = private_credentials.public_key
642
+ from_address = api_keys.bet_from_address
637
643
  market_contract = market.get_contract()
638
644
  collateral_token_contract = OmenCollateralTokenContract()
639
645
 
@@ -644,16 +650,16 @@ def omen_fund_market_tx(
644
650
  and collateral_token_contract.balanceOf(for_address=from_address, web3=web3)
645
651
  < funds
646
652
  ):
647
- collateral_token_contract.deposit(private_credentials, funds, web3=web3)
653
+ collateral_token_contract.deposit(api_keys, funds, web3=web3)
648
654
 
649
655
  collateral_token_contract.approve(
650
- private_credentials=private_credentials,
656
+ api_keys=api_keys,
651
657
  for_address=market_contract.address,
652
658
  amount_wei=funds,
653
659
  web3=web3,
654
660
  )
655
661
 
656
- market_contract.addFunding(private_credentials, funds, web3=web3)
662
+ market_contract.addFunding(api_keys, funds, web3=web3)
657
663
 
658
664
 
659
665
  def build_parent_collection_id() -> HexStr:
@@ -661,7 +667,7 @@ def build_parent_collection_id() -> HexStr:
661
667
 
662
668
 
663
669
  def omen_redeem_full_position_tx(
664
- private_credentials: PrivateCredentials,
670
+ api_keys: APIKeys,
665
671
  market: OmenAgentMarket,
666
672
  web3: Web3 | None = None,
667
673
  ) -> None:
@@ -670,7 +676,7 @@ def omen_redeem_full_position_tx(
670
676
  to be redeemed before sending the transaction.
671
677
  """
672
678
 
673
- from_address = private_credentials.public_key
679
+ from_address = api_keys.bet_from_address
674
680
 
675
681
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
676
682
  conditional_token_contract = OmenConditionalTokenContract()
@@ -700,7 +706,7 @@ def omen_redeem_full_position_tx(
700
706
  return
701
707
 
702
708
  conditional_token_contract.redeemPositions(
703
- private_credentials=private_credentials,
709
+ api_keys=api_keys,
704
710
  collateral_token_address=market.collateral_token_contract_address_checksummed,
705
711
  condition_id=market.condition.id,
706
712
  parent_collection_id=parent_collection_id,
@@ -741,7 +747,7 @@ def get_conditional_tokens_balance_for_market(
741
747
 
742
748
 
743
749
  def omen_remove_fund_market_tx(
744
- private_credentials: PrivateCredentials,
750
+ api_keys: APIKeys,
745
751
  market: OmenAgentMarket,
746
752
  shares: Wei | None,
747
753
  web3: Web3 | None = None,
@@ -754,7 +760,7 @@ def omen_remove_fund_market_tx(
754
760
  After we remove funding, using the `mergePositions` we get `min(shares per index)` of wxDai back, but the remaining shares can be converted back only after the market is resolved.
755
761
  That can be done using the `redeem_from_all_user_positions` function below.
756
762
  """
757
- from_address = private_credentials.public_key
763
+ from_address = api_keys.bet_from_address
758
764
  market_contract = market.get_contract()
759
765
  original_balances = get_balances(from_address, web3=web3)
760
766
 
@@ -769,9 +775,7 @@ def omen_remove_fund_market_tx(
769
775
  )
770
776
  shares = total_shares
771
777
 
772
- market_contract.removeFunding(
773
- private_credentials=private_credentials, remove_funding=shares, web3=web3
774
- )
778
+ market_contract.removeFunding(api_keys=api_keys, remove_funding=shares, web3=web3)
775
779
 
776
780
  conditional_tokens = OmenConditionalTokenContract()
777
781
  parent_collection_id = build_parent_collection_id()
@@ -784,7 +788,7 @@ def omen_remove_fund_market_tx(
784
788
  amount_to_merge = min(amount_per_index_set.values())
785
789
 
786
790
  result = conditional_tokens.mergePositions(
787
- private_credentials=private_credentials,
791
+ api_keys=api_keys,
788
792
  collateral_token_address=market.collateral_token_contract_address_checksummed,
789
793
  parent_collection_id=parent_collection_id,
790
794
  conditionId=market.condition.id,
@@ -802,13 +806,13 @@ def omen_remove_fund_market_tx(
802
806
 
803
807
 
804
808
  def redeem_from_all_user_positions(
805
- private_credentials: PrivateCredentials,
809
+ api_keys: APIKeys,
806
810
  web3: Web3 | None = None,
807
811
  ) -> None:
808
812
  """
809
813
  Redeems from all user positions where the user didn't redeem yet.
810
814
  """
811
- public_key = private_credentials.public_key
815
+ public_key = api_keys.bet_from_address
812
816
 
813
817
  conditional_token_contract = OmenConditionalTokenContract()
814
818
  user_positions = OmenSubgraphHandler().get_user_positions(
@@ -832,7 +836,7 @@ def redeem_from_all_user_positions(
832
836
 
833
837
  original_balances = get_balances(public_key, web3)
834
838
  conditional_token_contract.redeemPositions(
835
- private_credentials=private_credentials,
839
+ api_keys=api_keys,
836
840
  collateral_token_address=user_position.position.collateral_token_contract_address_checksummed,
837
841
  condition_id=condition_id,
838
842
  parent_collection_id=build_parent_collection_id(),