prediction-market-agent-tooling 0.61.1.dev463__py3-none-any.whl → 0.61.1.dev482__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. prediction_market_agent_tooling/deploy/agent.py +5 -4
  2. prediction_market_agent_tooling/deploy/betting_strategy.py +69 -53
  3. prediction_market_agent_tooling/gtypes.py +27 -105
  4. prediction_market_agent_tooling/jobs/jobs_models.py +7 -5
  5. prediction_market_agent_tooling/jobs/omen/omen_jobs.py +17 -13
  6. prediction_market_agent_tooling/markets/agent_market.py +52 -96
  7. prediction_market_agent_tooling/markets/blockchain_utils.py +27 -1
  8. prediction_market_agent_tooling/markets/data_models.py +44 -40
  9. prediction_market_agent_tooling/markets/manifold/api.py +6 -2
  10. prediction_market_agent_tooling/markets/manifold/data_models.py +25 -33
  11. prediction_market_agent_tooling/markets/manifold/manifold.py +11 -8
  12. prediction_market_agent_tooling/markets/market_fees.py +2 -4
  13. prediction_market_agent_tooling/markets/omen/data_models.py +57 -66
  14. prediction_market_agent_tooling/markets/omen/omen.py +249 -214
  15. prediction_market_agent_tooling/markets/omen/omen_contracts.py +29 -31
  16. prediction_market_agent_tooling/markets/omen/omen_resolving.py +14 -7
  17. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +14 -20
  18. prediction_market_agent_tooling/markets/polymarket/data_models.py +3 -3
  19. prediction_market_agent_tooling/markets/polymarket/data_models_web.py +4 -4
  20. prediction_market_agent_tooling/markets/polymarket/polymarket.py +5 -3
  21. prediction_market_agent_tooling/markets/seer/data_models.py +12 -8
  22. prediction_market_agent_tooling/markets/seer/seer.py +71 -85
  23. prediction_market_agent_tooling/markets/seer/seer_contracts.py +5 -10
  24. prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +14 -9
  25. prediction_market_agent_tooling/monitor/monitor.py +2 -2
  26. prediction_market_agent_tooling/tools/balances.py +11 -9
  27. prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +10 -12
  28. prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +24 -27
  29. prediction_market_agent_tooling/tools/betting_strategies/utils.py +1 -3
  30. prediction_market_agent_tooling/tools/contract.py +10 -14
  31. prediction_market_agent_tooling/tools/cow/cow_manager.py +4 -3
  32. prediction_market_agent_tooling/tools/cow/cow_order.py +4 -3
  33. prediction_market_agent_tooling/tools/langfuse_client_utils.py +1 -13
  34. prediction_market_agent_tooling/tools/omen/sell_positions.py +3 -6
  35. prediction_market_agent_tooling/tools/safe.py +6 -5
  36. prediction_market_agent_tooling/tools/tokens/auto_deposit.py +30 -32
  37. prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +22 -5
  38. prediction_market_agent_tooling/tools/tokens/main_token.py +2 -2
  39. prediction_market_agent_tooling/tools/utils.py +8 -14
  40. prediction_market_agent_tooling/tools/web3_utils.py +41 -24
  41. {prediction_market_agent_tooling-0.61.1.dev463.dist-info → prediction_market_agent_tooling-0.61.1.dev482.dist-info}/METADATA +1 -2
  42. {prediction_market_agent_tooling-0.61.1.dev463.dist-info → prediction_market_agent_tooling-0.61.1.dev482.dist-info}/RECORD +45 -48
  43. prediction_market_agent_tooling/tools/_generic_value.py +0 -255
  44. prediction_market_agent_tooling/tools/tokens/token_utils.py +0 -46
  45. prediction_market_agent_tooling/tools/tokens/usd.py +0 -63
  46. {prediction_market_agent_tooling-0.61.1.dev463.dist-info → prediction_market_agent_tooling-0.61.1.dev482.dist-info}/LICENSE +0 -0
  47. {prediction_market_agent_tooling-0.61.1.dev463.dist-info → prediction_market_agent_tooling-0.61.1.dev482.dist-info}/WHEEL +0 -0
  48. {prediction_market_agent_tooling-0.61.1.dev463.dist-info → prediction_market_agent_tooling-0.61.1.dev482.dist-info}/entry_points.txt +0 -0
@@ -4,16 +4,15 @@ from eth_typing import ChecksumAddress
4
4
  from web3 import Web3
5
5
  from web3.types import TxReceipt
6
6
 
7
- from prediction_market_agent_tooling.config import APIKeys, RPCConfig
7
+ from prediction_market_agent_tooling.config import APIKeys
8
8
  from prediction_market_agent_tooling.gtypes import (
9
- USD,
10
9
  HexAddress,
11
10
  HexBytes,
12
11
  OutcomeStr,
13
- OutcomeToken,
14
- OutcomeWei,
15
- Token,
12
+ Wei,
13
+ wei_type,
16
14
  xDai,
15
+ xdai_type,
17
16
  )
18
17
  from prediction_market_agent_tooling.loggers import logger
19
18
  from prediction_market_agent_tooling.markets.agent_market import (
@@ -24,9 +23,15 @@ from prediction_market_agent_tooling.markets.agent_market import (
24
23
  SortBy,
25
24
  )
26
25
  from prediction_market_agent_tooling.markets.blockchain_utils import store_trades
27
- from prediction_market_agent_tooling.markets.data_models import ExistingPosition
26
+ from prediction_market_agent_tooling.markets.data_models import (
27
+ BetAmount,
28
+ Currency,
29
+ Position,
30
+ TokenAmount,
31
+ )
28
32
  from prediction_market_agent_tooling.markets.market_fees import MarketFees
29
33
  from prediction_market_agent_tooling.markets.omen.omen import OmenAgentMarket
34
+ from prediction_market_agent_tooling.markets.omen.omen_contracts import sDaiContract
30
35
  from prediction_market_agent_tooling.markets.seer.data_models import (
31
36
  NewMarketEvent,
32
37
  SeerMarket,
@@ -38,6 +43,7 @@ from prediction_market_agent_tooling.markets.seer.seer_contracts import (
38
43
  from prediction_market_agent_tooling.markets.seer.seer_subgraph_handler import (
39
44
  SeerSubgraphHandler,
40
45
  )
46
+ from prediction_market_agent_tooling.tools.balances import get_balances
41
47
  from prediction_market_agent_tooling.tools.contract import (
42
48
  ContractERC20OnGnosisChain,
43
49
  init_collateral_token_contract,
@@ -51,16 +57,14 @@ from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC
51
57
  from prediction_market_agent_tooling.tools.tokens.auto_deposit import (
52
58
  auto_deposit_collateral_token,
53
59
  )
54
- from prediction_market_agent_tooling.tools.tokens.usd import (
55
- get_token_in_usd,
56
- get_usd_in_token,
57
- )
60
+ from prediction_market_agent_tooling.tools.web3_utils import wei_to_xdai, xdai_to_wei
58
61
 
59
62
  # We place a larger bet amount by default than Omen so that cow presents valid quotes.
60
- SEER_TINY_BET_AMOUNT = USD(0.1)
63
+ SEER_TINY_BET_AMOUNT = xdai_type(0.1)
61
64
 
62
65
 
63
66
  class SeerAgentMarket(AgentMarket):
67
+ currency = Currency.sDai
64
68
  wrapped_tokens: list[ChecksumAddress]
65
69
  creator: HexAddress
66
70
  collateral_token_contract_address_checksummed: ChecksumAddress
@@ -70,16 +74,6 @@ class SeerAgentMarket(AgentMarket):
70
74
  None # Seer markets don't have a description, so just default to None.
71
75
  )
72
76
 
73
- def get_collateral_token_contract(
74
- self, web3: Web3 | None = None
75
- ) -> ContractERC20OnGnosisChain:
76
- web3 = web3 or RPCConfig().get_web3()
77
- return to_gnosis_chain_contract(
78
- init_collateral_token_contract(
79
- self.collateral_token_contract_address_checksummed, web3
80
- )
81
- )
82
-
83
77
  def store_prediction(
84
78
  self,
85
79
  processed_market: ProcessedMarket | None,
@@ -101,28 +95,29 @@ class SeerAgentMarket(AgentMarket):
101
95
  agent_name=agent_name,
102
96
  )
103
97
 
104
- def get_token_in_usd(self, x: Token) -> USD:
105
- return get_token_in_usd(x, self.collateral_token_contract_address_checksummed)
106
-
107
- def get_usd_in_token(self, x: USD) -> Token:
108
- return get_usd_in_token(x, self.collateral_token_contract_address_checksummed)
98
+ def _convert_bet_amount_into_wei(self, bet_amount: BetAmount) -> Wei:
99
+ if bet_amount.currency == self.currency:
100
+ return xdai_to_wei(xdai_type(bet_amount.amount))
101
+ raise ValueError(
102
+ f"Currencies don't match. Currency bet amount {bet_amount.currency} currency market: {self.currency}"
103
+ )
109
104
 
110
105
  def get_buy_token_amount(
111
- self, bet_amount: USD | Token, direction: bool
112
- ) -> OutcomeToken:
106
+ self, bet_amount: BetAmount, direction: bool
107
+ ) -> TokenAmount:
113
108
  """Returns number of outcome tokens returned for a given bet expressed in collateral units."""
114
109
 
115
110
  outcome_token = self.get_wrapped_token_for_outcome(direction)
116
- bet_amount_in_tokens = self.get_in_token(bet_amount)
117
- bet_amount_in_wei = bet_amount_in_tokens.as_wei
111
+
112
+ bet_amount_in_wei = self._convert_bet_amount_into_wei(bet_amount=bet_amount)
118
113
 
119
114
  quote = CowManager().get_quote(
120
115
  buy_token=outcome_token,
121
116
  sell_amount=bet_amount_in_wei,
122
117
  collateral_token=self.collateral_token_contract_address_checksummed,
123
118
  )
124
- sell_amount = OutcomeWei(quote.quote.buyAmount.root).as_outcome_token
125
- return sell_amount
119
+ sell_amount = wei_to_xdai(wei_type(quote.quote.buyAmount.root))
120
+ return TokenAmount(amount=sell_amount, currency=bet_amount.currency)
126
121
 
127
122
  def get_outcome_str_from_bool(self, outcome: bool) -> OutcomeStr:
128
123
  outcome_translated = SeerOutcomeEnum.from_bool(outcome)
@@ -130,46 +125,33 @@ class SeerAgentMarket(AgentMarket):
130
125
  return OutcomeStr(self.outcomes[idx])
131
126
 
132
127
  @staticmethod
133
- def get_trade_balance(api_keys: APIKeys) -> USD:
128
+ def get_trade_balance(api_keys: APIKeys) -> float:
134
129
  return OmenAgentMarket.get_trade_balance(api_keys=api_keys)
135
130
 
136
- def get_tiny_bet_amount(self) -> Token:
137
- return self.get_in_token(SEER_TINY_BET_AMOUNT)
131
+ @classmethod
132
+ def get_tiny_bet_amount(cls) -> BetAmount:
133
+ return BetAmount(amount=SEER_TINY_BET_AMOUNT, currency=cls.currency)
138
134
 
139
- def get_position(
140
- self, user_id: str, web3: Web3 | None = None
141
- ) -> ExistingPosition | None:
135
+ def get_position(self, user_id: str, web3: Web3 | None = None) -> Position | None:
142
136
  """
143
137
  Fetches position from the user in a given market.
144
138
  We ignore the INVALID balances since we are only interested in binary outcomes.
145
139
  """
146
140
 
147
- amounts_ot: dict[OutcomeStr, OutcomeToken] = {}
141
+ amounts = {}
148
142
 
149
143
  for outcome in [True, False]:
150
144
  wrapped_token = self.get_wrapped_token_for_outcome(outcome)
151
145
 
152
- outcome_token_balance_wei = OutcomeWei.from_wei(
153
- ContractERC20OnGnosisChain(address=wrapped_token).balanceOf(
154
- for_address=Web3.to_checksum_address(user_id), web3=web3
155
- )
156
- )
146
+ outcome_token_balance = ContractERC20OnGnosisChain(
147
+ address=wrapped_token
148
+ ).balanceOf(for_address=Web3.to_checksum_address(user_id), web3=web3)
157
149
  outcome_str = self.get_outcome_str_from_bool(outcome=outcome)
158
- amounts_ot[outcome_str] = outcome_token_balance_wei.as_outcome_token
159
-
160
- amounts_current = {
161
- k: self.get_token_in_usd(self.get_sell_value_of_outcome_token(k, v))
162
- for k, v in amounts_ot.items()
163
- }
164
- amounts_potential = {
165
- k: self.get_token_in_usd(v.as_token) for k, v in amounts_ot.items()
166
- }
167
- return ExistingPosition(
168
- market_id=self.id,
169
- amounts_current=amounts_current,
170
- amounts_potential=amounts_potential,
171
- amounts_ot=amounts_ot,
172
- )
150
+ amounts[outcome_str] = TokenAmount(
151
+ amount=wei_to_xdai(outcome_token_balance), currency=self.currency
152
+ )
153
+
154
+ return Position(market_id=self.id, amounts=amounts)
173
155
 
174
156
  @staticmethod
175
157
  def get_user_id(api_keys: APIKeys) -> str:
@@ -228,9 +210,9 @@ class SeerAgentMarket(AgentMarket):
228
210
  CowManager().get_quote(
229
211
  collateral_token=self.collateral_token_contract_address_checksummed,
230
212
  buy_token=outcome_token,
231
- sell_amount=Token(
232
- 1
233
- ).as_wei, # we take 1 as a baseline value for common trades the agents take.
213
+ sell_amount=xdai_to_wei(
214
+ xdai_type(1)
215
+ ), # we take 1 xDai as a baseline value for common trades the agents take.
234
216
  )
235
217
  return True
236
218
  except NoLiquidityAvailableOnCowException:
@@ -254,7 +236,7 @@ class SeerAgentMarket(AgentMarket):
254
236
  def place_bet(
255
237
  self,
256
238
  outcome: bool,
257
- amount: USD,
239
+ amount: BetAmount,
258
240
  auto_deposit: bool = True,
259
241
  web3: Web3 | None = None,
260
242
  api_keys: APIKeys | None = None,
@@ -265,27 +247,32 @@ class SeerAgentMarket(AgentMarket):
265
247
  f"Market {self.id} is not open for trading. Cannot place bet."
266
248
  )
267
249
 
268
- amount_in_token = self.get_usd_in_token(amount)
269
- amount_wei = amount_in_token.as_wei
270
- collateral_contract = self.get_collateral_token_contract()
250
+ if amount.currency != self.currency:
251
+ raise ValueError(f"Seer bets are made in xDai. Got {amount.currency}.")
271
252
 
253
+ collateral_contract = sDaiContract()
272
254
  if auto_deposit:
255
+ # We convert the deposit amount (in sDai) to assets in order to convert.
256
+ asset_amount = collateral_contract.convertToAssets(
257
+ xdai_to_wei(xdai_type(amount.amount))
258
+ )
273
259
  auto_deposit_collateral_token(
274
- collateral_contract, amount_wei, api_keys, web3
260
+ collateral_contract, asset_amount, api_keys, web3
275
261
  )
276
262
 
277
- collateral_balance = collateral_contract.balanceOf(api_keys.bet_from_address)
278
- if collateral_balance < amount_wei:
263
+ # We require that amount is given in sDAI.
264
+ collateral_balance = get_balances(address=api_keys.bet_from_address, web3=web3)
265
+ if collateral_balance.sdai < amount.amount:
279
266
  raise ValueError(
280
- f"Balance {collateral_balance} not enough for bet size {amount}"
267
+ f"Balance {collateral_balance.sdai} not enough for bet size {amount.amount}"
281
268
  )
282
269
 
283
270
  outcome_token = self.get_wrapped_token_for_outcome(outcome)
284
- # Sell using token address
271
+ # Sell sDAI using token address
285
272
  order_metadata = CowManager().swap(
286
- amount=amount_in_token,
273
+ amount=xdai_type(amount.amount),
287
274
  sell_token=collateral_contract.address,
288
- buy_token=outcome_token,
275
+ buy_token=Web3.to_checksum_address(outcome_token),
289
276
  api_keys=api_keys,
290
277
  web3=web3,
291
278
  )
@@ -295,17 +282,18 @@ class SeerAgentMarket(AgentMarket):
295
282
 
296
283
  def seer_create_market_tx(
297
284
  api_keys: APIKeys,
298
- initial_funds: USD | Token,
285
+ initial_funds: xDai,
299
286
  question: str,
300
287
  opening_time: DatetimeUTC,
301
288
  language: str,
302
- outcomes: t.Sequence[OutcomeStr],
289
+ outcomes: list[str],
303
290
  auto_deposit: bool,
304
291
  category: str,
305
292
  min_bond_xdai: xDai,
306
293
  web3: Web3 | None = None,
307
294
  ) -> ChecksumAddress:
308
295
  web3 = web3 or SeerMarketFactory.get_web3() # Default to Gnosis web3.
296
+ initial_funds_wei = xdai_to_wei(initial_funds)
309
297
 
310
298
  factory_contract = SeerMarketFactory()
311
299
  collateral_token_address = factory_contract.collateral_token(web3=web3)
@@ -313,26 +301,24 @@ def seer_create_market_tx(
313
301
  init_collateral_token_contract(collateral_token_address, web3)
314
302
  )
315
303
 
316
- initial_funds_in_collateral = (
317
- get_usd_in_token(initial_funds, collateral_token_address)
318
- if isinstance(initial_funds, USD)
319
- else initial_funds
320
- )
321
- initial_funds_in_collateral_wei = initial_funds_in_collateral.as_wei
322
-
323
304
  if auto_deposit:
324
305
  auto_deposit_collateral_token(
325
306
  collateral_token_contract=collateral_token_contract,
326
307
  api_keys=api_keys,
327
- collateral_amount_wei_or_usd=initial_funds_in_collateral_wei,
308
+ amount_wei=initial_funds_wei,
328
309
  web3=web3,
329
310
  )
330
311
 
312
+ # In case of ERC4626, obtained (for example) sDai out of xDai could be lower than the `amount_wei`, so we need to handle it.
313
+ initial_funds_in_shares = collateral_token_contract.get_in_shares(
314
+ amount=initial_funds_wei, web3=web3
315
+ )
316
+
331
317
  # Approve the market maker to withdraw our collateral token.
332
318
  collateral_token_contract.approve(
333
319
  api_keys=api_keys,
334
320
  for_address=factory_contract.address,
335
- amount_wei=initial_funds_in_collateral_wei,
321
+ amount_wei=initial_funds_in_shares,
336
322
  web3=web3,
337
323
  )
338
324
 
@@ -343,7 +329,7 @@ def seer_create_market_tx(
343
329
  opening_time=opening_time,
344
330
  language=language,
345
331
  category=category,
346
- min_bond=min_bond_xdai,
332
+ min_bond_xdai=min_bond_xdai,
347
333
  )
348
334
  tx_receipt = factory_contract.create_categorical_market(
349
335
  api_keys=api_keys, params=params, web3=web3
@@ -1,16 +1,10 @@
1
1
  import os
2
- import typing as t
3
2
 
4
3
  from web3 import Web3
5
4
  from web3.types import TxReceipt
6
5
 
7
6
  from prediction_market_agent_tooling.config import APIKeys
8
- from prediction_market_agent_tooling.gtypes import (
9
- ABI,
10
- ChecksumAddress,
11
- OutcomeStr,
12
- xDai,
13
- )
7
+ from prediction_market_agent_tooling.gtypes import ABI, ChecksumAddress, xDai
14
8
  from prediction_market_agent_tooling.markets.seer.data_models import (
15
9
  CreateCategoricalMarketsParams,
16
10
  )
@@ -19,6 +13,7 @@ from prediction_market_agent_tooling.tools.contract import (
19
13
  abi_field_validator,
20
14
  )
21
15
  from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC
16
+ from prediction_market_agent_tooling.tools.web3_utils import xdai_to_wei
22
17
 
23
18
 
24
19
  class SeerMarketFactory(ContractOnGnosisChain):
@@ -36,9 +31,9 @@ class SeerMarketFactory(ContractOnGnosisChain):
36
31
  @staticmethod
37
32
  def build_market_params(
38
33
  market_question: str,
39
- outcomes: t.Sequence[OutcomeStr],
34
+ outcomes: list[str],
40
35
  opening_time: DatetimeUTC,
41
- min_bond: xDai,
36
+ min_bond_xdai: xDai,
42
37
  language: str = "en_US",
43
38
  category: str = "misc",
44
39
  ) -> CreateCategoricalMarketsParams:
@@ -47,7 +42,7 @@ class SeerMarketFactory(ContractOnGnosisChain):
47
42
  token_names=[
48
43
  o.upper() for o in outcomes
49
44
  ], # Following usual token names on Seer (YES,NO).
50
- min_bond=min_bond.as_xdai_wei.value,
45
+ min_bond=xdai_to_wei(min_bond_xdai),
51
46
  opening_time=int(opening_time.timestamp()),
52
47
  outcomes=outcomes,
53
48
  lang=language,
@@ -15,7 +15,6 @@ from prediction_market_agent_tooling.markets.seer.data_models import (
15
15
  )
16
16
  from prediction_market_agent_tooling.tools.hexbytes_custom import HexBytes
17
17
  from prediction_market_agent_tooling.tools.utils import to_int_timestamp, utcnow
18
- from prediction_market_agent_tooling.tools.web3_utils import unwrap_generic_value
19
18
 
20
19
 
21
20
  class SeerSubgraphHandler(BaseSubgraphHandler):
@@ -50,6 +49,7 @@ class SeerSubgraphHandler(BaseSubgraphHandler):
50
49
  markets_field.creator,
51
50
  markets_field.conditionId,
52
51
  markets_field.marketName,
52
+ markets_field.outcomesSupply,
53
53
  markets_field.parentOutcome,
54
54
  markets_field.outcomes,
55
55
  markets_field.payoutReported,
@@ -121,12 +121,16 @@ class SeerSubgraphHandler(BaseSubgraphHandler):
121
121
  match sort_by:
122
122
  case SortBy.NEWEST:
123
123
  sort_direction = "desc"
124
- sort_by_field = self.seer_subgraph.Market.block_timestamp
124
+ sort_by_field = self.seer_subgraph.Market.blockTimestamp
125
125
  case SortBy.CLOSING_SOONEST:
126
126
  sort_direction = "asc"
127
- sort_by_field = self.seer_subgraph.Market.opening_ts
128
- # ToDo - Implement liquidity conditions by looking up Swapr subgraph.
129
- case SortBy.NONE | SortBy.HIGHEST_LIQUIDITY | SortBy.LOWEST_LIQUIDITY:
127
+ sort_by_field = self.seer_subgraph.Market.openingTs
128
+ case SortBy.HIGHEST_LIQUIDITY | SortBy.LOWEST_LIQUIDITY:
129
+ sort_direction = (
130
+ "desc" if sort_by == SortBy.HIGHEST_LIQUIDITY else "asc"
131
+ )
132
+ sort_by_field = self.seer_subgraph.Market.outcomesSupply
133
+ case SortBy.NONE:
130
134
  sort_direction = None
131
135
  sort_by_field = None
132
136
  case _:
@@ -159,7 +163,7 @@ class SeerSubgraphHandler(BaseSubgraphHandler):
159
163
  first=(
160
164
  limit if limit else sys.maxsize
161
165
  ), # if not limit, we fetch all possible markets,
162
- where=unwrap_generic_value(where_stms),
166
+ where=where_stms,
163
167
  **optional_params,
164
168
  )
165
169
  fields = self._get_fields_for_markets(markets_field)
@@ -201,6 +205,9 @@ class SeerSubgraphHandler(BaseSubgraphHandler):
201
205
  fields = [
202
206
  pools_field.id,
203
207
  pools_field.liquidity,
208
+ pools_field.sqrtPrice,
209
+ pools_field.token0Price,
210
+ pools_field.token1Price,
204
211
  pools_field.token0.id,
205
212
  pools_field.token0.name,
206
213
  pools_field.token0.symbol,
@@ -220,9 +227,7 @@ class SeerSubgraphHandler(BaseSubgraphHandler):
220
227
  {"token1": wrapped_token.lower()},
221
228
  ]
222
229
  )
223
- pools_field = self.swapr_algebra_subgraph.Query.pools(
224
- where=unwrap_generic_value({"or": wheres})
225
- )
230
+ pools_field = self.swapr_algebra_subgraph.Query.pools(where={"or": wheres})
226
231
  fields = self._get_fields_for_pools(pools_field)
227
232
  pools = self.do_query(fields=fields, pydantic_model=SeerPool)
228
233
  return pools
@@ -186,12 +186,12 @@ def monitor_agent(agent: DeployedAgent) -> None:
186
186
  return
187
187
  bets_info = {
188
188
  "Market Question": [bet.market_question for bet in agent_bets],
189
- "Bet Amount": [bet.amount for bet in agent_bets],
189
+ "Bet Amount": [bet.amount.amount for bet in agent_bets],
190
190
  "Bet Outcome": [bet.outcome for bet in agent_bets],
191
191
  "Created Time": [bet.created_time for bet in agent_bets],
192
192
  "Resolved Time": [bet.resolved_time for bet in agent_bets],
193
193
  "Is Correct": [bet.is_correct for bet in agent_bets],
194
- "Profit": [round(bet.profit, 2) for bet in agent_bets],
194
+ "Profit": [round(bet.profit.amount, 2) for bet in agent_bets],
195
195
  }
196
196
 
197
197
  # Time column to use for x-axes and sorting
@@ -1,30 +1,32 @@
1
1
  from pydantic import BaseModel
2
2
  from tenacity import retry, stop_after_attempt, wait_fixed
3
3
  from web3 import Web3
4
+ from web3.types import Wei
4
5
 
5
- from prediction_market_agent_tooling.gtypes import ChecksumAddress, Token, xDai, xDaiWei
6
+ from prediction_market_agent_tooling.gtypes import ChecksumAddress, xDai
6
7
  from prediction_market_agent_tooling.markets.omen.omen_contracts import (
7
8
  WrappedxDaiContract,
8
9
  sDaiContract,
9
10
  )
11
+ from prediction_market_agent_tooling.tools.web3_utils import wei_to_xdai
10
12
 
11
13
 
12
14
  class Balances(BaseModel):
13
15
  xdai: xDai
14
- wxdai: Token
15
- sdai: Token
16
+ wxdai: xDai
17
+ sdai: xDai
16
18
 
17
19
  @property
18
- def total(self) -> Token:
19
- return self.xdai.as_token + self.wxdai + self.sdai
20
+ def total(self) -> xDai:
21
+ return xDai(self.xdai + self.wxdai + self.sdai)
20
22
 
21
23
 
22
24
  @retry(stop=stop_after_attempt(3), wait=wait_fixed(1))
23
25
  def get_balances(address: ChecksumAddress, web3: Web3 | None = None) -> Balances:
24
26
  if not web3:
25
27
  web3 = WrappedxDaiContract().get_web3()
26
- xdai_balance = xDaiWei(web3.eth.get_balance(address))
27
- xdai = xdai_balance.as_xdai
28
- wxdai = WrappedxDaiContract().balanceOf(address, web3=web3).as_token
29
- sdai = sDaiContract().balanceOf(address, web3=web3).as_token
28
+ xdai_balance = Wei(web3.eth.get_balance(address))
29
+ xdai = wei_to_xdai(xdai_balance)
30
+ wxdai = wei_to_xdai(WrappedxDaiContract().balanceOf(address, web3=web3))
31
+ sdai = wei_to_xdai(sDaiContract().balanceOf(address, web3=web3))
30
32
  return Balances(xdai=xdai, wxdai=wxdai, sdai=sdai)
@@ -1,4 +1,3 @@
1
- from prediction_market_agent_tooling.gtypes import OutcomeToken, Token
2
1
  from prediction_market_agent_tooling.markets.market_fees import MarketFees
3
2
  from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet
4
3
 
@@ -9,7 +8,7 @@ def check_is_valid_probability(probability: float) -> None:
9
8
 
10
9
 
11
10
  def get_kelly_bet_simplified(
12
- max_bet: Token,
11
+ max_bet: float,
13
12
  market_p_yes: float,
14
13
  estimated_p_yes: float,
15
14
  confidence: float,
@@ -52,17 +51,17 @@ def get_kelly_bet_simplified(
52
51
  kelly_fraction = edge / odds
53
52
 
54
53
  # Ensure bet size is non-negative does not exceed the wallet balance
55
- bet_size = Token(min(kelly_fraction * max_bet.value, max_bet.value))
54
+ bet_size = min(kelly_fraction * max_bet, max_bet)
56
55
 
57
56
  return SimpleBet(direction=bet_direction, size=bet_size)
58
57
 
59
58
 
60
59
  def get_kelly_bet_full(
61
- yes_outcome_pool_size: OutcomeToken,
62
- no_outcome_pool_size: OutcomeToken,
60
+ yes_outcome_pool_size: float,
61
+ no_outcome_pool_size: float,
63
62
  estimated_p_yes: float,
64
63
  confidence: float,
65
- max_bet: Token,
64
+ max_bet: float,
66
65
  fees: MarketFees,
67
66
  ) -> SimpleBet:
68
67
  """
@@ -98,13 +97,13 @@ def get_kelly_bet_full(
98
97
  check_is_valid_probability(confidence)
99
98
 
100
99
  if max_bet == 0:
101
- return SimpleBet(direction=True, size=Token(0))
100
+ return SimpleBet(direction=True, size=0)
102
101
 
103
- x = yes_outcome_pool_size.value
104
- y = no_outcome_pool_size.value
102
+ x = yes_outcome_pool_size
103
+ y = no_outcome_pool_size
105
104
  p = estimated_p_yes
106
105
  c = confidence
107
- b = max_bet.value
106
+ b = max_bet
108
107
  f = 1 - fee
109
108
 
110
109
  if x == y:
@@ -145,6 +144,5 @@ def get_kelly_bet_full(
145
144
 
146
145
  # Clip the bet size to max_bet to account for rounding errors.
147
146
  return SimpleBet(
148
- direction=kelly_bet_amount > 0,
149
- size=Token(min(max_bet.value, abs(kelly_bet_amount))),
147
+ direction=kelly_bet_amount > 0, size=min(max_bet, abs(kelly_bet_amount))
150
148
  )
@@ -2,18 +2,19 @@ from functools import reduce
2
2
 
3
3
  import numpy as np
4
4
 
5
- from prediction_market_agent_tooling.gtypes import OutcomeToken, Probability, Token
5
+ from prediction_market_agent_tooling.gtypes import Probability, Wei, xDai
6
6
  from prediction_market_agent_tooling.markets.omen.omen import (
7
7
  MarketFees,
8
8
  OmenAgentMarket,
9
9
  )
10
10
  from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet
11
11
  from prediction_market_agent_tooling.tools.utils import check_not_none
12
+ from prediction_market_agent_tooling.tools.web3_utils import wei_to_xdai, xdai_to_wei
12
13
 
13
14
 
14
15
  def get_market_moving_bet(
15
- yes_outcome_pool_size: OutcomeToken,
16
- no_outcome_pool_size: OutcomeToken,
16
+ yes_outcome_pool_size: float,
17
+ no_outcome_pool_size: float,
17
18
  market_p_yes: float,
18
19
  target_p_yes: float,
19
20
  fees: MarketFees,
@@ -41,21 +42,20 @@ def get_market_moving_bet(
41
42
  fixed_product = yes_outcome_pool_size * no_outcome_pool_size
42
43
  bet_direction: bool = target_p_yes > market_p_yes
43
44
 
44
- min_bet_amount = Token(0.0)
45
- max_bet_amount = (
45
+ min_bet_amount = 0.0
46
+ max_bet_amount = 100 * (
46
47
  yes_outcome_pool_size + no_outcome_pool_size
47
- ).as_token * 100 # TODO set a better upper bound
48
+ ) # TODO set a better upper bound
48
49
 
49
50
  # Binary search for the optimal bet amount
50
51
  for _ in range(max_iters):
51
52
  bet_amount = (min_bet_amount + max_bet_amount) / 2
52
- amounts_diff = fees.get_after_fees(bet_amount)
53
- amounts_diff_as_ot = OutcomeToken.from_token(amounts_diff)
53
+ amounts_diff = fees.get_bet_size_after_fees(bet_amount)
54
54
 
55
55
  # Initial new amounts are old amounts + equal new amounts for each outcome
56
- yes_outcome_new_pool_size = yes_outcome_pool_size + amounts_diff_as_ot
57
- no_outcome_new_pool_size = no_outcome_pool_size + amounts_diff_as_ot
58
- new_amounts: dict[bool, OutcomeToken] = {
56
+ yes_outcome_new_pool_size = yes_outcome_pool_size + amounts_diff
57
+ no_outcome_new_pool_size = no_outcome_pool_size + amounts_diff
58
+ new_amounts = {
59
59
  True: yes_outcome_new_pool_size,
60
60
  False: no_outcome_new_pool_size,
61
61
  }
@@ -63,20 +63,15 @@ def get_market_moving_bet(
63
63
  # Now give away tokens at `bet_outcome_index` to restore invariant
64
64
  new_product = yes_outcome_new_pool_size * no_outcome_new_pool_size
65
65
  dx = (new_product - fixed_product) / new_amounts[not bet_direction]
66
- new_amounts[bet_direction] -= OutcomeToken(dx)
66
+ new_amounts[bet_direction] -= dx
67
67
 
68
68
  # Check that the invariant is restored
69
69
  assert np.isclose(
70
- reduce(lambda x, y: x * y.value, list(new_amounts.values()), 1.0),
70
+ reduce(lambda x, y: x * y, list(new_amounts.values()), 1.0),
71
71
  float(fixed_product),
72
72
  )
73
73
 
74
- new_p_yes = Probability(
75
- (
76
- new_amounts[False]
77
- / sum(list(new_amounts.values()), start=OutcomeToken(0))
78
- )
79
- )
74
+ new_p_yes = Probability(new_amounts[False] / sum(list(new_amounts.values())))
80
75
  if abs(target_p_yes - new_p_yes) < 1e-6:
81
76
  break
82
77
  elif new_p_yes > target_p_yes:
@@ -102,31 +97,33 @@ def _sanity_check_omen_market_moving_bet(
102
97
  using the adjusted outcome pool sizes to calculate the new p_yes.
103
98
  """
104
99
  buy_amount_ = market.get_contract().calcBuyAmount(
105
- investment_amount=bet_to_check.size.as_wei,
100
+ investment_amount=xdai_to_wei(xDai(bet_to_check.size)),
106
101
  outcome_index=market.get_outcome_index(
107
102
  market.get_outcome_str_from_bool(bet_to_check.direction)
108
103
  ),
109
104
  )
110
- buy_amount = buy_amount_.as_outcome_token
105
+ buy_amount = float(wei_to_xdai(Wei(buy_amount_)))
111
106
 
112
107
  outcome_token_pool = check_not_none(market.outcome_token_pool)
113
108
  yes_outcome_pool_size = outcome_token_pool[market.get_outcome_str_from_bool(True)]
114
109
  no_outcome_pool_size = outcome_token_pool[market.get_outcome_str_from_bool(False)]
115
- market_const = yes_outcome_pool_size.value * no_outcome_pool_size.value
110
+ market_const = yes_outcome_pool_size * no_outcome_pool_size
116
111
 
117
- bet_to_check_size_after_fees = market.fees.get_after_fees(bet_to_check.size).value
112
+ bet_to_check_size_after_fees = market.fees.get_bet_size_after_fees(
113
+ bet_to_check.size
114
+ )
118
115
 
119
116
  # When you buy 'yes' tokens, you add your bet size to the both pools, then
120
117
  # subtract `buy_amount` from the 'yes' pool. And vice versa for 'no' tokens.
121
118
  new_yes_outcome_pool_size = (
122
- yes_outcome_pool_size.value
119
+ yes_outcome_pool_size
123
120
  + bet_to_check_size_after_fees
124
- - float(bet_to_check.direction) * buy_amount.value
121
+ - float(bet_to_check.direction) * buy_amount
125
122
  )
126
123
  new_no_outcome_pool_size = (
127
- no_outcome_pool_size.value
124
+ no_outcome_pool_size
128
125
  + bet_to_check_size_after_fees
129
- - float(not bet_to_check.direction) * buy_amount.value
126
+ - float(not bet_to_check.direction) * buy_amount
130
127
  )
131
128
  new_market_const = new_yes_outcome_pool_size * new_no_outcome_pool_size
132
129
  # Check the invariant is restored
@@ -1,8 +1,6 @@
1
1
  from pydantic import BaseModel
2
2
 
3
- from prediction_market_agent_tooling.gtypes import Token
4
-
5
3
 
6
4
  class SimpleBet(BaseModel):
7
5
  direction: bool
8
- size: Token
6
+ size: float