prediction-market-agent-tooling 0.48.5__py3-none-any.whl → 0.48.8__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 (19) hide show
  1. prediction_market_agent_tooling/benchmark/agents.py +0 -2
  2. prediction_market_agent_tooling/benchmark/utils.py +5 -3
  3. prediction_market_agent_tooling/deploy/agent.py +35 -27
  4. prediction_market_agent_tooling/deploy/agent_example.py +5 -6
  5. prediction_market_agent_tooling/deploy/betting_strategy.py +62 -0
  6. prediction_market_agent_tooling/markets/data_models.py +44 -3
  7. prediction_market_agent_tooling/markets/omen/data_models.py +71 -3
  8. prediction_market_agent_tooling/markets/omen/omen_contracts.py +3 -2
  9. prediction_market_agent_tooling/markets/omen/omen_resolving.py +22 -44
  10. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +63 -1
  11. prediction_market_agent_tooling/markets/polymarket/data_models_web.py +41 -38
  12. prediction_market_agent_tooling/monitor/monitor_app.py +9 -8
  13. prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +6 -13
  14. prediction_market_agent_tooling/tools/is_predictable.py +1 -1
  15. {prediction_market_agent_tooling-0.48.5.dist-info → prediction_market_agent_tooling-0.48.8.dist-info}/METADATA +1 -1
  16. {prediction_market_agent_tooling-0.48.5.dist-info → prediction_market_agent_tooling-0.48.8.dist-info}/RECORD +19 -18
  17. {prediction_market_agent_tooling-0.48.5.dist-info → prediction_market_agent_tooling-0.48.8.dist-info}/LICENSE +0 -0
  18. {prediction_market_agent_tooling-0.48.5.dist-info → prediction_market_agent_tooling-0.48.8.dist-info}/WHEEL +0 -0
  19. {prediction_market_agent_tooling-0.48.5.dist-info → prediction_market_agent_tooling-0.48.8.dist-info}/entry_points.txt +0 -0
@@ -87,7 +87,6 @@ class RandomAgent(AbstractBenchmarkedAgent):
87
87
  p_yes, confidence = random.random(), random.random()
88
88
  return Prediction(
89
89
  outcome_prediction=OutcomePrediction(
90
- decision=p_yes > 0.5,
91
90
  p_yes=Probability(p_yes),
92
91
  confidence=confidence,
93
92
  info_utility=None,
@@ -111,7 +110,6 @@ class FixedAgent(AbstractBenchmarkedAgent):
111
110
  p_yes, confidence = 1.0 if self.fixed_answer else 0.0, 1.0
112
111
  return Prediction(
113
112
  outcome_prediction=OutcomePrediction(
114
- decision=self.fixed_answer,
115
113
  p_yes=Probability(p_yes),
116
114
  confidence=confidence,
117
115
  info_utility=None,
@@ -3,11 +3,13 @@ import typing as t
3
3
 
4
4
  from pydantic import BaseModel
5
5
 
6
- from prediction_market_agent_tooling.deploy.agent import Answer
7
- from prediction_market_agent_tooling.markets.data_models import Resolution
6
+ from prediction_market_agent_tooling.markets.data_models import (
7
+ ProbabilisticAnswer,
8
+ Resolution,
9
+ )
8
10
 
9
11
 
10
- class OutcomePrediction(Answer):
12
+ class OutcomePrediction(ProbabilisticAnswer):
11
13
  info_utility: t.Optional[float]
12
14
 
13
15
  @property
@@ -12,6 +12,10 @@ from pydantic import BaseModel, BeforeValidator, computed_field
12
12
  from typing_extensions import Annotated
13
13
 
14
14
  from prediction_market_agent_tooling.config import APIKeys
15
+ from prediction_market_agent_tooling.deploy.betting_strategy import (
16
+ BettingStrategy,
17
+ MaxAccuracyBettingStrategy,
18
+ )
15
19
  from prediction_market_agent_tooling.deploy.constants import (
16
20
  MARKET_TYPE_KEY,
17
21
  REPOSITORY_KEY,
@@ -25,14 +29,19 @@ from prediction_market_agent_tooling.deploy.gcp.utils import (
25
29
  gcp_function_is_active,
26
30
  gcp_resolve_api_keys_secrets,
27
31
  )
28
- from prediction_market_agent_tooling.gtypes import Probability, xDai, xdai_type
32
+ from prediction_market_agent_tooling.gtypes import xDai, xdai_type
29
33
  from prediction_market_agent_tooling.loggers import logger
30
34
  from prediction_market_agent_tooling.markets.agent_market import (
31
35
  AgentMarket,
32
36
  FilterBy,
33
37
  SortBy,
34
38
  )
35
- from prediction_market_agent_tooling.markets.data_models import BetAmount
39
+ from prediction_market_agent_tooling.markets.data_models import (
40
+ BetAmount,
41
+ ProbabilisticAnswer,
42
+ TokenAmount,
43
+ TokenAmountAndDirection,
44
+ )
36
45
  from prediction_market_agent_tooling.markets.markets import (
37
46
  MarketType,
38
47
  have_bet_on_market_since,
@@ -95,19 +104,8 @@ class OutOfFundsError(ValueError):
95
104
  pass
96
105
 
97
106
 
98
- class Answer(BaseModel):
99
- decision: Decision # Warning: p_yes > 0.5 doesn't necessarily mean decision is True! For example, if our p_yes is 55%, but market's p_yes is 80%, then it might be profitable to bet on False.
100
- p_yes: Probability
101
- confidence: float
102
- reasoning: str | None = None
103
-
104
- @property
105
- def p_no(self) -> Probability:
106
- return Probability(1 - self.p_yes)
107
-
108
-
109
107
  class ProcessedMarket(BaseModel):
110
- answer: Answer
108
+ answer: ProbabilisticAnswer
111
109
  amount: BetAmount
112
110
 
113
111
 
@@ -280,6 +278,7 @@ class DeployableTraderAgent(DeployableAgent):
280
278
  bet_on_n_markets_per_run: int = 1
281
279
  min_required_balance_to_operate: xDai | None = xdai_type(1)
282
280
  min_balance_to_keep_in_native_currency: xDai | None = xdai_type(0.1)
281
+ strategy: BettingStrategy = MaxAccuracyBettingStrategy()
283
282
 
284
283
  def __init__(
285
284
  self,
@@ -295,7 +294,7 @@ class DeployableTraderAgent(DeployableAgent):
295
294
  self.have_bet_on_market_since = observe()(self.have_bet_on_market_since) # type: ignore[method-assign]
296
295
  self.verify_market = observe()(self.verify_market) # type: ignore[method-assign]
297
296
  self.answer_binary_market = observe()(self.answer_binary_market) # type: ignore[method-assign]
298
- self.calculate_bet_amount = observe()(self.calculate_bet_amount) # type: ignore[method-assign]
297
+ self.calculate_bet_amount_and_direction = observe()(self.calculate_bet_amount_and_direction) # type: ignore[method-assign]
299
298
  self.process_market = observe()(self.process_market) # type: ignore[method-assign]
300
299
 
301
300
  def update_langfuse_trace_by_market(
@@ -311,6 +310,18 @@ class DeployableTraderAgent(DeployableAgent):
311
310
  },
312
311
  )
313
312
 
313
+ def calculate_bet_amount_and_direction(
314
+ self, answer: ProbabilisticAnswer, market: AgentMarket
315
+ ) -> TokenAmountAndDirection:
316
+ amount_and_direction = self.strategy.calculate_bet_amount_and_direction(
317
+ answer, market
318
+ )
319
+ if amount_and_direction.currency != market.currency:
320
+ raise ValueError(
321
+ f"Currency mismatch. Strategy yields {amount_and_direction.currency}, market has currency {market.currency}"
322
+ )
323
+ return amount_and_direction
324
+
314
325
  def update_langfuse_trace_by_processed_market(
315
326
  self, market_type: MarketType, processed_market: ProcessedMarket | None
316
327
  ) -> None:
@@ -360,18 +371,12 @@ class DeployableTraderAgent(DeployableAgent):
360
371
 
361
372
  return True
362
373
 
363
- def answer_binary_market(self, market: AgentMarket) -> Answer | None:
374
+ def answer_binary_market(self, market: AgentMarket) -> ProbabilisticAnswer | None:
364
375
  """
365
376
  Answer the binary market. This method must be implemented by the subclass.
366
377
  """
367
378
  raise NotImplementedError("This method must be implemented by the subclass")
368
379
 
369
- def calculate_bet_amount(self, answer: Answer, market: AgentMarket) -> BetAmount:
370
- """
371
- Calculate the bet amount. By default, it returns the minimum bet amount.
372
- """
373
- return market.get_tiny_bet_amount()
374
-
375
380
  def get_markets(
376
381
  self,
377
382
  market_type: MarketType,
@@ -408,22 +413,25 @@ class DeployableTraderAgent(DeployableAgent):
408
413
  self.update_langfuse_trace_by_processed_market(market_type, None)
409
414
  return None
410
415
 
411
- amount = self.calculate_bet_amount(answer, market)
416
+ amount_and_direction = self.calculate_bet_amount_and_direction(answer, market)
412
417
 
413
418
  if self.place_bet:
414
419
  logger.info(
415
- f"Placing bet on {market} with result {answer} and amount {amount}"
420
+ f"Placing bet on {market} with direction {amount_and_direction.direction} and amount {amount_and_direction.amount}"
416
421
  )
417
422
  market.place_bet(
418
- amount=amount,
419
- outcome=answer.decision,
423
+ amount=TokenAmount(
424
+ amount=amount_and_direction.amount,
425
+ currency=amount_and_direction.currency,
426
+ ),
427
+ outcome=amount_and_direction.direction,
420
428
  )
421
429
 
422
430
  self.after_process_market(market_type, market)
423
431
 
424
432
  processed_market = ProcessedMarket(
425
433
  answer=answer,
426
- amount=amount,
434
+ amount=amount_and_direction,
427
435
  )
428
436
  self.update_langfuse_trace_by_processed_market(market_type, processed_market)
429
437
 
@@ -1,10 +1,10 @@
1
1
  import random
2
2
 
3
3
  from prediction_market_agent_tooling.deploy.agent import (
4
- Answer,
5
4
  DeployableTraderAgent,
6
- Probability,
5
+ ProbabilisticAnswer,
7
6
  )
7
+ from prediction_market_agent_tooling.gtypes import Probability
8
8
  from prediction_market_agent_tooling.markets.agent_market import AgentMarket
9
9
  from prediction_market_agent_tooling.markets.markets import MarketType
10
10
 
@@ -13,10 +13,9 @@ class DeployableCoinFlipAgent(DeployableTraderAgent):
13
13
  def verify_market(self, market_type: MarketType, market: AgentMarket) -> bool:
14
14
  return True
15
15
 
16
- def answer_binary_market(self, market: AgentMarket) -> Answer | None:
16
+ def answer_binary_market(self, market: AgentMarket) -> ProbabilisticAnswer | None:
17
17
  decision = random.choice([True, False])
18
- return Answer(
19
- decision=decision,
18
+ return ProbabilisticAnswer(
20
19
  p_yes=Probability(float(decision)),
21
20
  confidence=0.5,
22
21
  reasoning="I flipped a coin to decide.",
@@ -24,5 +23,5 @@ class DeployableCoinFlipAgent(DeployableTraderAgent):
24
23
 
25
24
 
26
25
  class DeployableAlwaysRaiseAgent(DeployableTraderAgent):
27
- def answer_binary_market(self, market: AgentMarket) -> Answer | None:
26
+ def answer_binary_market(self, market: AgentMarket) -> ProbabilisticAnswer | None:
28
27
  raise RuntimeError("I always raise!")
@@ -0,0 +1,62 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from prediction_market_agent_tooling.markets.agent_market import AgentMarket
4
+ from prediction_market_agent_tooling.markets.data_models import (
5
+ ProbabilisticAnswer,
6
+ TokenAmountAndDirection,
7
+ )
8
+ from prediction_market_agent_tooling.tools.betting_strategies.kelly_criterion import (
9
+ get_kelly_bet,
10
+ )
11
+
12
+
13
+ class BettingStrategy(ABC):
14
+ @abstractmethod
15
+ def calculate_bet_amount_and_direction(
16
+ self, answer: ProbabilisticAnswer, market: AgentMarket
17
+ ) -> TokenAmountAndDirection:
18
+ pass
19
+
20
+
21
+ class MaxAccuracyBettingStrategy(BettingStrategy):
22
+ def __init__(self, bet_amount: float | None = None):
23
+ self.bet_amount = bet_amount
24
+
25
+ @staticmethod
26
+ def calculate_direction(market_p_yes: float, estimate_p_yes: float) -> bool:
27
+ # If estimate_p_yes >= market.current_p_yes, then bet TRUE, else bet FALSE.
28
+ # This is equivalent to saying EXPECTED_VALUE = (estimate_p_yes * num_tokens_obtained_by_betting_yes) -
29
+ # ((1 - estimate_p_yes) * num_tokens_obtained_by_betting_no) >= 0
30
+ return estimate_p_yes >= market_p_yes
31
+
32
+ def calculate_bet_amount_and_direction(
33
+ self, answer: ProbabilisticAnswer, market: AgentMarket
34
+ ) -> TokenAmountAndDirection:
35
+ bet_amount = (
36
+ market.get_tiny_bet_amount().amount
37
+ if self.bet_amount is None
38
+ else self.bet_amount
39
+ )
40
+ direction = self.calculate_direction(market.current_p_yes, answer.p_yes)
41
+ return TokenAmountAndDirection(
42
+ amount=bet_amount,
43
+ currency=market.currency,
44
+ direction=direction,
45
+ )
46
+
47
+
48
+ class KellyBettingStrategy(BettingStrategy):
49
+ def __init__(self, max_bet_amount: float = 10):
50
+ self.max_bet_amount = max_bet_amount
51
+
52
+ def calculate_bet_amount_and_direction(
53
+ self, answer: ProbabilisticAnswer, market: AgentMarket
54
+ ) -> TokenAmountAndDirection:
55
+ kelly_bet = get_kelly_bet(
56
+ self.max_bet_amount, market.current_p_yes, answer.p_yes, answer.confidence
57
+ )
58
+ return TokenAmountAndDirection(
59
+ amount=kelly_bet.size,
60
+ currency=market.currency,
61
+ direction=kelly_bet.direction,
62
+ )
@@ -1,10 +1,10 @@
1
1
  from datetime import datetime
2
2
  from enum import Enum
3
- from typing import TypeAlias
3
+ from typing import Annotated, TypeAlias
4
4
 
5
- from pydantic import BaseModel, computed_field
5
+ from pydantic import BaseModel, BeforeValidator, computed_field
6
6
 
7
- from prediction_market_agent_tooling.gtypes import OutcomeStr
7
+ from prediction_market_agent_tooling.gtypes import OutcomeStr, Probability
8
8
 
9
9
 
10
10
  class Currency(str, Enum):
@@ -19,6 +19,10 @@ class Resolution(str, Enum):
19
19
  CANCEL = "CANCEL"
20
20
  MKT = "MKT"
21
21
 
22
+ @staticmethod
23
+ def from_bool(value: bool) -> "Resolution":
24
+ return Resolution.YES if value else Resolution.NO
25
+
22
26
 
23
27
  class TokenAmount(BaseModel):
24
28
  amount: float
@@ -57,6 +61,43 @@ class ResolvedBet(Bet):
57
61
  return f"Resolved bet for market {self.market_id} for question {self.market_question} created at {self.created_time}: {self.amount} on {self.outcome}. Bet was resolved at {self.resolved_time} and was {'correct' if self.is_correct else 'incorrect'}. Profit was {self.profit}"
58
62
 
59
63
 
64
+ class TokenAmountAndDirection(TokenAmount):
65
+ direction: bool
66
+
67
+
68
+ def to_boolean_outcome(value: str | bool) -> bool:
69
+ if isinstance(value, bool):
70
+ return value
71
+
72
+ elif isinstance(value, str):
73
+ value = value.lower().strip()
74
+
75
+ if value in {"true", "yes", "y", "1"}:
76
+ return True
77
+
78
+ elif value in {"false", "no", "n", "0"}:
79
+ return False
80
+
81
+ else:
82
+ raise ValueError(f"Expected a boolean string, but got {value}")
83
+
84
+ else:
85
+ raise ValueError(f"Expected a boolean or a string, but got {value}")
86
+
87
+
88
+ Decision = Annotated[bool, BeforeValidator(to_boolean_outcome)]
89
+
90
+
91
+ class ProbabilisticAnswer(BaseModel):
92
+ p_yes: Probability
93
+ confidence: float
94
+ reasoning: str | None = None
95
+
96
+ @property
97
+ def p_no(self) -> Probability:
98
+ return Probability(1 - self.p_yes)
99
+
100
+
60
101
  class Position(BaseModel):
61
102
  market_id: str
62
103
  amounts: dict[OutcomeStr, TokenAmount]
@@ -77,6 +77,10 @@ class Question(BaseModel):
77
77
  def opening_datetime(self) -> datetime:
78
78
  return datetime.fromtimestamp(self.openingTimestamp)
79
79
 
80
+ @property
81
+ def has_answer(self) -> bool:
82
+ return self.currentAnswer is not None
83
+
80
84
  @property
81
85
  def outcome_index(self) -> int | None:
82
86
  return (
@@ -88,6 +92,34 @@ class Question(BaseModel):
88
92
  else None
89
93
  )
90
94
 
95
+ @property
96
+ def is_binary(self) -> bool:
97
+ return len(self.outcomes) == 2
98
+
99
+ @property
100
+ def has_valid_answer(self) -> bool:
101
+ return self.outcome_index is not None and self.outcome_index != INVALID_ANSWER
102
+
103
+ @property
104
+ def boolean_outcome(self) -> bool:
105
+ if not self.is_binary:
106
+ raise ValueError(
107
+ f"Question with title {self.title} is not binary, it has {len(self.outcomes)} outcomes."
108
+ )
109
+
110
+ if not self.has_answer:
111
+ raise ValueError(f"Question with title {self.title} is not answered.")
112
+
113
+ outcome_index = check_not_none(self.outcome_index)
114
+
115
+ if not self.has_valid_answer:
116
+ raise ValueError(
117
+ f"Question with title {self.title} has invalid answer {outcome_index}."
118
+ )
119
+
120
+ outcome: str = self.outcomes[outcome_index]
121
+ return get_boolean_outcome(outcome)
122
+
91
123
 
92
124
  class OmenPosition(BaseModel):
93
125
  id: HexBytes
@@ -132,7 +164,15 @@ class OmenUserPosition(BaseModel):
132
164
 
133
165
  class OmenMarket(BaseModel):
134
166
  """
135
- https://aiomen.eth.limo
167
+ https://presagio.pages.dev
168
+
169
+ An Omen market goes through the following stages:
170
+
171
+ 1. creation - can add liquidty immediately, and trade immediately if there is liquidity
172
+ 2. closing - market is closed, and a question is simultaneously opened for answers on Reality
173
+ 3. finalizing - the question is finalized on reality (including any disputes)
174
+ 4. resolving - a manual step required by calling the Omen oracle contract
175
+ 5. redeeming - a user withdraws collateral tokens from the market
136
176
  """
137
177
 
138
178
  BET_AMOUNT_CURRENCY: t.ClassVar[Currency] = Currency.xDai
@@ -347,7 +387,7 @@ class OmenBet(BaseModel):
347
387
  collateralAmountUSD: USD
348
388
  feeAmount: Wei
349
389
  outcomeIndex: int
350
- outcomeTokensTraded: int
390
+ outcomeTokensTraded: Wei
351
391
  transactionHash: HexAddress
352
392
  fpmm: OmenMarket
353
393
 
@@ -372,7 +412,7 @@ class OmenBet(BaseModel):
372
412
  def get_profit(self) -> ProfitAmount:
373
413
  bet_amount_xdai = wei_to_xdai(self.collateralAmount)
374
414
  profit = (
375
- wei_to_xdai(Wei(self.outcomeTokensTraded)) - bet_amount_xdai
415
+ wei_to_xdai(self.outcomeTokensTraded) - bet_amount_xdai
376
416
  if self.boolean_outcome == self.fpmm.boolean_outcome
377
417
  else -bet_amount_xdai
378
418
  )
@@ -430,6 +470,8 @@ class RealityQuestion(BaseModel):
430
470
  updatedTimestamp: datetime
431
471
  contentHash: HexBytes
432
472
  questionId: HexBytes
473
+ answerFinalizedTimestamp: datetime
474
+ currentScheduledFinalizationTimestamp: datetime
433
475
 
434
476
  @property
435
477
  def url(self) -> str:
@@ -446,6 +488,32 @@ class RealityAnswer(BaseModel):
446
488
  createdBlock: int
447
489
 
448
490
 
491
+ class RealityResponse(BaseModel):
492
+ """
493
+ This is similar to `RealityAnswer`, but contains additional fields, most importantly `historyHash`.
494
+ """
495
+
496
+ id: str
497
+ timestamp: datetime
498
+ answer: HexBytes
499
+ isUnrevealed: bool
500
+ isCommitment: bool
501
+ bond: Wei
502
+ user: HexAddress
503
+ historyHash: HexBytes
504
+ question: RealityQuestion
505
+ createdBlock: int
506
+ revealedBlock: int | None
507
+
508
+ @property
509
+ def bond_xdai(self) -> xDai:
510
+ return wei_to_xdai(self.bond)
511
+
512
+ @property
513
+ def user_checksummed(self) -> ChecksumAddress:
514
+ return Web3.to_checksum_address(self.user)
515
+
516
+
449
517
  class RealityAnswers(BaseModel):
450
518
  answers: list[RealityAnswer]
451
519
 
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import random
3
3
  import typing as t
4
- from datetime import datetime
4
+ from datetime import datetime, timedelta
5
5
  from enum import Enum
6
6
 
7
7
  from web3 import Web3
@@ -521,6 +521,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
521
521
  language: str,
522
522
  arbitrator: Arbitrator,
523
523
  opening: datetime,
524
+ timeout: timedelta = timedelta(days=1),
524
525
  nonce: int | None = None,
525
526
  tx_params: t.Optional[TxParams] = None,
526
527
  web3: Web3 | None = None,
@@ -547,7 +548,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
547
548
  template_id=template_id,
548
549
  question=realitio_question,
549
550
  arbitrator=arbitrator_contract_address,
550
- timeout=86400, # See https://github.com/protofire/omen-exchange/blob/2cfdf6bfe37afa8b169731d51fea69d42321d66c/app/src/util/networks.ts#L278.
551
+ timeout=int(timeout.total_seconds()),
551
552
  opening_ts=int(opening.timestamp()),
552
553
  nonce=(
553
554
  nonce if nonce is not None else random.randint(0, 1000000)
@@ -33,7 +33,6 @@ from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
33
33
  from prediction_market_agent_tooling.markets.polymarket.utils import (
34
34
  find_resolution_on_polymarket,
35
35
  )
36
- from prediction_market_agent_tooling.tools.utils import check_not_none
37
36
  from prediction_market_agent_tooling.tools.web3_utils import ZERO_BYTES, xdai_to_wei
38
37
 
39
38
 
@@ -42,7 +41,6 @@ def claim_bonds_on_realitio_questions(
42
41
  questions: list[RealityQuestion],
43
42
  auto_withdraw: bool,
44
43
  web3: Web3 | None = None,
45
- silent_errors: bool = False,
46
44
  ) -> list[HexBytes]:
47
45
  claimed_questions: list[HexBytes] = []
48
46
 
@@ -50,19 +48,10 @@ def claim_bonds_on_realitio_questions(
50
48
  logger.info(
51
49
  f"[{idx+1} / {len(questions)}] Claiming bond for {question.questionId=} {question.url=}"
52
50
  )
53
- try:
54
- claim_bonds_on_realitio_question(
55
- api_keys, question, auto_withdraw=auto_withdraw, web3=web3
56
- )
57
- claimed_questions.append(question.questionId)
58
- except Exception as e:
59
- # TODO: This shouldn't be required once `claim_bonds_on_realitio_question` below is fixed.
60
- if silent_errors:
61
- logger.warning(
62
- f"Error while claiming bond for {question.questionId=} {question.url=}: {e}"
63
- )
64
- else:
65
- raise
51
+ claim_bonds_on_realitio_question(
52
+ api_keys, question, auto_withdraw=auto_withdraw, web3=web3
53
+ )
54
+ claimed_questions.append(question.questionId)
66
55
 
67
56
  return claimed_questions
68
57
 
@@ -77,50 +66,39 @@ def claim_bonds_on_realitio_question(
77
66
  realitio_contract = OmenRealitioContract()
78
67
 
79
68
  # Get all answers for the question.
80
- answers_objects = OmenSubgraphHandler().get_answers(question_id=question.questionId)
69
+ responses = OmenSubgraphHandler().get_responses(question_id=question.questionId)
81
70
 
82
- if not answers_objects:
83
- raise ValueError(f"No answers found for {question.questionId=}")
71
+ # They need to be processed in order.
72
+ responses = sorted(responses, key=lambda x: x.timestamp)
84
73
 
85
- if answers_objects[-1].question.historyHash == ZERO_BYTES:
86
- raise ValueError(f"Already claimed {question.questionId=}.")
74
+ if not responses:
75
+ raise ValueError(f"No answers found for {question.questionId.hex()=}")
87
76
 
88
- if len(answers_objects) > 1:
89
- # As you can see below, we need `history_hash` for every answer.
90
- # The trouble is, that historyHash is updated after each new answer and the contract holds only the latest one.
91
- # So if we have more than 1 answer, we missing the historyHash n-1 of them and this would fail.
92
- # You can find how to calculate history hash at https://realitio.github.io/docs/html/contract_explanation.html#answer-history-entries.
93
- # At the moment, we support only 1 answer, as for that one answer we will have the hash.
94
- raise NotImplementedError()
77
+ if responses[-1].question.historyHash == ZERO_BYTES:
78
+ raise ValueError(f"Already claimed {question.questionId.hex()=}.")
95
79
 
96
- # Logic taken from packages/valory/skills/decision_maker_abci/models.py in `def claim_params`.
97
80
  history_hashes: list[HexBytes] = []
98
81
  addresses: list[ChecksumAddress] = []
99
82
  bonds: list[Wei] = []
100
83
  answers: list[HexBytes] = []
101
84
 
102
- for i, answer in enumerate(reversed(answers_objects)):
103
- # history_hashes second-last-to-first, the hash of each history entry, calculated as described here:
104
- # https://realitio.github.io/docs/html/contract_explanation.html#answer-history-entries.
105
- if i == len(answers_objects) - 1:
85
+ # Caller must provide the answer history, in reverse order.
86
+ # See https://gnosisscan.io/address/0x79e32aE03fb27B07C89c0c568F80287C01ca2E57#code#L625 for the `claimWinnings` logic.
87
+ reversed_responses = list(reversed(responses))
88
+
89
+ for i, response in enumerate(reversed_responses):
90
+ # second-last-to-first, the hash of each history entry. (Final one should be empty).
91
+ if i == len(reversed_responses) - 1:
106
92
  history_hashes.append(ZERO_BYTES)
107
93
  else:
108
- # TODO: See `if len(answers_objects) > 1` above.
109
- # This is from the original Olas implementation (https://github.com/kongzii/trader/blob/700af475a4538cc3d5d22caf9dec9e9d22d72af1/packages/valory/skills/market_manager_abci/graph_tooling/requests.py#L297),
110
- # but it's most probably wrong (see comment above).
111
- history_hashes.append(
112
- check_not_none(
113
- answers_objects[i + 1].question.historyHash,
114
- "Shouldn't be None here.",
115
- )
116
- )
94
+ history_hashes.append(reversed_responses[i + 1].historyHash)
117
95
 
118
96
  # last-to-first, the address of each answerer or commitment sender
119
- addresses.append(Web3.to_checksum_address(answer.question.user))
97
+ addresses.append(Web3.to_checksum_address(response.user))
120
98
  # last-to-first, the bond supplied with each answer or commitment
121
- bonds.append(answer.lastBond)
99
+ bonds.append(response.bond)
122
100
  # last-to-first, each answer supplied, or commitment ID if the answer was supplied with commit->reveal
123
- answers.append(answer.answer)
101
+ answers.append(response.answer)
124
102
 
125
103
  realitio_contract.claimWinnings(
126
104
  api_keys=api_keys,
@@ -22,6 +22,7 @@ from prediction_market_agent_tooling.markets.omen.data_models import (
22
22
  OmenUserPosition,
23
23
  RealityAnswer,
24
24
  RealityQuestion,
25
+ RealityResponse,
25
26
  )
26
27
  from prediction_market_agent_tooling.markets.omen.omen_contracts import (
27
28
  OmenThumbnailMapping,
@@ -118,6 +119,8 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
118
119
  questions_field.questionId,
119
120
  questions_field.contentHash,
120
121
  questions_field.historyHash,
122
+ questions_field.answerFinalizedTimestamp,
123
+ questions_field.currentScheduledFinalizationTimestamp,
121
124
  ]
122
125
 
123
126
  def _get_fields_for_answers(self, answers_field: FieldPath) -> list[FieldPath]:
@@ -130,6 +133,20 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
130
133
  answers_field.createdBlock,
131
134
  ] + self._get_fields_for_reality_questions(answers_field.question)
132
135
 
136
+ def _get_fields_for_responses(self, responses_field: FieldPath) -> list[FieldPath]:
137
+ return [
138
+ responses_field.id,
139
+ responses_field.timestamp,
140
+ responses_field.answer,
141
+ responses_field.isUnrevealed,
142
+ responses_field.isCommitment,
143
+ responses_field.bond,
144
+ responses_field.user,
145
+ responses_field.historyHash,
146
+ responses_field.createdBlock,
147
+ responses_field.revealedBlock,
148
+ ] + self._get_fields_for_reality_questions(responses_field.question)
149
+
133
150
  def _get_fields_for_market_questions(
134
151
  self, questions_field: FieldPath
135
152
  ) -> list[FieldPath]:
@@ -175,11 +192,13 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
175
192
  def _build_where_statements(
176
193
  self,
177
194
  creator: t.Optional[HexAddress] = None,
195
+ creator_in: t.Optional[t.Sequence[HexAddress]] = None,
178
196
  outcomes: list[str] = [OMEN_TRUE_OUTCOME, OMEN_FALSE_OUTCOME],
179
197
  created_after: t.Optional[datetime] = None,
180
198
  opened_before: t.Optional[datetime] = None,
181
199
  opened_after: t.Optional[datetime] = None,
182
200
  finalized_before: t.Optional[datetime] = None,
201
+ finalized_after: t.Optional[datetime] = None,
183
202
  finalized: bool | None = None,
184
203
  resolved: bool | None = None,
185
204
  liquidity_bigger_than: Wei | None = None,
@@ -202,7 +221,10 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
202
221
  ]
203
222
 
204
223
  if creator:
205
- where_stms["creator"] = creator
224
+ where_stms["creator"] = creator.lower()
225
+
226
+ if creator_in:
227
+ where_stms["creator_in"] = [x.lower() for x in creator_in]
206
228
 
207
229
  if created_after:
208
230
  where_stms["creationTimestamp_gt"] = to_int_timestamp(created_after)
@@ -244,6 +266,11 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
244
266
  finalized_before
245
267
  )
246
268
 
269
+ if finalized_after:
270
+ where_stms["answerFinalizedTimestamp_gt"] = to_int_timestamp(
271
+ finalized_after
272
+ )
273
+
247
274
  # `excluded_question_titles` can not be an empty list, otherwise the API bugs out and returns nothing.
248
275
  excluded_question_titles = [""]
249
276
  if excluded_questions:
@@ -331,9 +358,11 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
331
358
  opened_before: t.Optional[datetime] = None,
332
359
  opened_after: t.Optional[datetime] = None,
333
360
  finalized_before: t.Optional[datetime] = None,
361
+ finalized_after: t.Optional[datetime] = None,
334
362
  finalized: bool | None = None,
335
363
  resolved: bool | None = None,
336
364
  creator: t.Optional[HexAddress] = None,
365
+ creator_in: t.Optional[t.Sequence[HexAddress]] = None,
337
366
  liquidity_bigger_than: Wei | None = None,
338
367
  condition_id_in: list[HexBytes] | None = None,
339
368
  id_in: list[str] | None = None,
@@ -353,11 +382,13 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
353
382
  """
354
383
  where_stms = self._build_where_statements(
355
384
  creator=creator,
385
+ creator_in=creator_in,
356
386
  outcomes=outcomes,
357
387
  created_after=created_after,
358
388
  opened_before=opened_before,
359
389
  opened_after=opened_after,
360
390
  finalized_before=finalized_before,
391
+ finalized_after=finalized_after,
361
392
  finalized=finalized,
362
393
  resolved=resolved,
363
394
  condition_id_in=condition_id_in,
@@ -582,6 +613,10 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
582
613
  user: HexAddress | None = None,
583
614
  claimed: bool | None = None,
584
615
  current_answer_before: datetime | None = None,
616
+ finalized_before: datetime | None = None,
617
+ finalized_after: datetime | None = None,
618
+ id_in: list[str] | None = None,
619
+ question_id_in: list[HexBytes] | None = None,
585
620
  ) -> list[RealityQuestion]:
586
621
  where_stms: dict[str, t.Any] = {}
587
622
 
@@ -599,6 +634,22 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
599
634
  current_answer_before
600
635
  )
601
636
 
637
+ if finalized_before is not None:
638
+ where_stms["answerFinalizedTimestamp_lt"] = to_int_timestamp(
639
+ finalized_before
640
+ )
641
+
642
+ if finalized_after is not None:
643
+ where_stms["answerFinalizedTimestamp_gt"] = to_int_timestamp(
644
+ finalized_after
645
+ )
646
+
647
+ if id_in is not None:
648
+ where_stms["id_in"] = id_in
649
+
650
+ if question_id_in is not None:
651
+ where_stms["questionId_in"] = [x.hex() for x in question_id_in]
652
+
602
653
  questions = self.realityeth_subgraph.Query.questions(where=where_stms)
603
654
  fields = self._get_fields_for_reality_questions(questions)
604
655
  result = self.sg.query_json(fields)
@@ -618,6 +669,17 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
618
669
  items = self._parse_items_from_json(result)
619
670
  return [RealityAnswer.model_validate(i) for i in items]
620
671
 
672
+ def get_responses(self, question_id: HexBytes) -> list[RealityResponse]:
673
+ response = self.realityeth_subgraph.Response
674
+ where_stms = [
675
+ response.question.questionId == question_id.hex(),
676
+ ]
677
+ responses = self.realityeth_subgraph.Query.responses(where=where_stms)
678
+ fields = self._get_fields_for_responses(responses)
679
+ result = self.sg.query_json(fields)
680
+ items = self._parse_items_from_json(result)
681
+ return [RealityResponse.model_validate(i) for i in items]
682
+
621
683
  def get_markets_from_all_user_positions(
622
684
  self, user_positions: list[OmenUserPosition]
623
685
  ) -> list[OmenMarket]:
@@ -38,7 +38,7 @@ class Event(BaseModel):
38
38
 
39
39
 
40
40
  class Event1(BaseModel):
41
- startDate: datetime
41
+ startDate: datetime | None = None
42
42
  slug: str
43
43
 
44
44
 
@@ -78,13 +78,13 @@ class Market(BaseModel):
78
78
  conditionId: str
79
79
  slug: str
80
80
  twitterCardImage: t.Any | None = None
81
- resolutionSource: str
81
+ resolutionSource: str | None = None
82
82
  endDate: datetime
83
83
  category: t.Any | None = None
84
84
  ammType: t.Any | None = None
85
85
  description: str
86
86
  liquidity: str | None = None
87
- startDate: datetime
87
+ startDate: datetime | None = None
88
88
  createdAt: datetime
89
89
  xAxisValue: t.Any | None = None
90
90
  yAxisValue: t.Any | None = None
@@ -93,8 +93,8 @@ class Market(BaseModel):
93
93
  lowerBound: t.Any | None = None
94
94
  upperBound: t.Any | None = None
95
95
  outcomes: list[str]
96
- image: str
97
- icon: str
96
+ image: str | None = None
97
+ icon: str | None = None
98
98
  imageOptimized: t.Any | None = None
99
99
  iconOptimized: t.Any | None = None
100
100
  outcomePrices: list[USDC]
@@ -108,23 +108,23 @@ class Market(BaseModel):
108
108
  marketMakerAddress: HexAddress
109
109
  closedTime: datetime | None = None
110
110
  wideFormat: bool | None = None
111
- new: bool
111
+ new: bool | None = None
112
112
  sentDiscord: t.Any | None = None
113
113
  mailchimpTag: t.Any | None = None
114
- featured: bool
115
- submitted_by: str
114
+ featured: bool | None = None
115
+ submitted_by: str | None = None
116
116
  subcategory: t.Any | None = None
117
117
  categoryMailchimpTag: t.Any | None = None
118
- archived: bool
119
- resolvedBy: str
120
- restricted: bool
121
- groupItemTitle: str
122
- groupItemThreshold: str
123
- questionID: str
118
+ archived: bool | None = None
119
+ resolvedBy: str | None = None
120
+ restricted: bool | None = None
121
+ groupItemTitle: str | None = None
122
+ groupItemThreshold: str | None = None
123
+ questionID: str | None = None
124
124
  umaEndDate: t.Any | None = None
125
- enableOrderBook: bool
126
- orderPriceMinTickSize: float
127
- orderMinSize: int
125
+ enableOrderBook: bool | None = None
126
+ orderPriceMinTickSize: float | None = None
127
+ orderMinSize: int | None = None
128
128
  umaResolutionStatus: t.Any | None = None
129
129
  curationOrder: t.Any | None = None
130
130
  volumeNum: USDC | None = None
@@ -134,9 +134,9 @@ class Market(BaseModel):
134
134
  umaEndDateIso: datetime | None = None
135
135
  commentsEnabled: bool | None = None
136
136
  disqusThread: t.Any | None = None
137
- gameStartTime: datetime | None = None
137
+ gameStartTime: t.Any | None = None
138
138
  secondsDelay: int | None = None
139
- clobTokenIds: list[str]
139
+ clobTokenIds: list[str] | None = None
140
140
  liquidityAmm: float | None = None
141
141
  liquidityClob: float | None = None
142
142
  makerBaseFee: int | None = None
@@ -144,27 +144,27 @@ class Market(BaseModel):
144
144
  negRisk: t.Any | None = None
145
145
  negRiskRequestID: t.Any | None = None
146
146
  negRiskMarketID: t.Any | None = None
147
- events: list[Event]
148
- markets: list[Market1]
147
+ events: list[Event] | None = None
148
+ markets: list[Market1] | None = None
149
149
  lower_bound_date: t.Any | None = None
150
150
  upper_bound_date: t.Any | None = None
151
151
  market_type: str | None = None
152
- resolution_source: str
153
- end_date: str
152
+ resolution_source: str | None = None
153
+ end_date: str | None = None
154
154
  amm_type: t.Any | None = None
155
155
  x_axis_value: t.Any | None = None
156
156
  y_axis_value: t.Any | None = None
157
157
  denomination_token: t.Any | None = None
158
- resolved_by: str
158
+ resolved_by: str | None = None
159
159
  upper_bound: t.Any | None = None
160
160
  lower_bound: t.Any | None = None
161
- created_at: str
161
+ created_at: str | None = None
162
162
  updated_at: t.Any | None = None
163
163
  closed_time: t.Any | None = None
164
164
  wide_format: bool | None = None
165
165
  volume_num: USDC | None = None
166
166
  liquidity_num: USDC | None = None
167
- image_raw: str
167
+ image_raw: str | None = None
168
168
  resolutionData: ResolutionData
169
169
 
170
170
  @field_validator("closedTime", mode="before")
@@ -234,19 +234,19 @@ class PolymarketFullMarket(BaseModel):
234
234
  title: str
235
235
  subtitle: t.Any | None = None
236
236
  description: str
237
- commentCount: int
238
- resolutionSource: str
239
- startDate: datetime
237
+ commentCount: int | None = None
238
+ resolutionSource: str | None = None
239
+ startDate: datetime | None = None
240
240
  endDate: datetime
241
- image: str
242
- icon: str
241
+ image: str | None = None
242
+ icon: str | None = None
243
243
  featuredImage: str | None = None
244
244
  active: bool
245
245
  closed: bool
246
- archived: bool
247
- new: bool
248
- featured: bool
249
- restricted: bool
246
+ archived: bool | None = None
247
+ new: bool | None = None
248
+ featured: bool | None = None
249
+ restricted: bool | None = None
250
250
  liquidity: USDC | None = None
251
251
  volume: USDC | None = None
252
252
  volume24hr: USDC | None = None
@@ -257,7 +257,7 @@ class PolymarketFullMarket(BaseModel):
257
257
  commentsEnabled: bool | None = None
258
258
  disqusThread: t.Any | None = None
259
259
  updatedAt: datetime
260
- enableOrderBook: bool
260
+ enableOrderBook: bool | None = None
261
261
  liquidityAmm: float | None = None
262
262
  liquidityClob: float | None = None
263
263
  imageOptimized: ImageOptimized | None = None
@@ -269,7 +269,7 @@ class PolymarketFullMarket(BaseModel):
269
269
  markets: list[Market]
270
270
  categories: list[Category] | None = None
271
271
  series: t.Any | None = None
272
- image_raw: str
272
+ image_raw: str | None = None
273
273
 
274
274
  @property
275
275
  def url(self) -> str:
@@ -298,6 +298,8 @@ class PolymarketFullMarket(BaseModel):
298
298
 
299
299
  Warning: This is a very slow operation, as it requires fetching the website. Use it only when necessary.
300
300
  """
301
+ logger.info(f"Fetching full market from {url}")
302
+
301
303
  # Fetch the website as a normal browser would.
302
304
  headers = {
303
305
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
@@ -352,7 +354,8 @@ class State(BaseModel):
352
354
  | dict[str, MarketBidsAndAsks]
353
355
  | dict[str, PriceSide]
354
356
  | None
355
- ) # It's none if you go to the website and it says "Oops...we didn't forecast this".
357
+ # It's none if you go to the website and it says "Oops...we didn't forecast this".
358
+ )
356
359
  dataUpdateCount: int
357
360
  dataUpdatedAt: int
358
361
  error: t.Any | None = None
@@ -135,15 +135,16 @@ def monitor_app(
135
135
  )
136
136
 
137
137
  st.header("Market Info")
138
- with st.spinner("Loading markets"):
139
- open_markets, resolved_markets = get_open_and_resolved_markets(
140
- start_time=oldest_start_time, market_type=market_type
138
+ if st.checkbox("Show Market Info"):
139
+ with st.spinner("Loading markets"):
140
+ open_markets, resolved_markets = get_open_and_resolved_markets(
141
+ start_time=oldest_start_time, market_type=market_type
142
+ )
143
+ (
144
+ monitor_market(open_markets=open_markets, resolved_markets=resolved_markets)
145
+ if open_markets and resolved_markets
146
+ else st.warning("No market data found.")
141
147
  )
142
- (
143
- monitor_market(open_markets=open_markets, resolved_markets=resolved_markets)
144
- if open_markets and resolved_markets
145
- else st.warning("No market data found.")
146
- )
147
148
 
148
149
  st.header("Agent Info")
149
150
  if st.button("Export agents"):
@@ -1,23 +1,16 @@
1
- from enum import Enum
2
-
3
1
  from pydantic import BaseModel
4
2
 
5
3
 
6
- class BetDirection(str, Enum):
7
- YES = "Yes"
8
- NO = "No"
4
+ def check_is_valid_probability(probability: float) -> None:
5
+ if not 0 <= probability <= 1:
6
+ raise ValueError("Probability must be between 0 and 1")
9
7
 
10
8
 
11
9
  class KellyBet(BaseModel):
12
- direction: BetDirection
10
+ direction: bool
13
11
  size: float
14
12
 
15
13
 
16
- def check_is_valid_probability(probability: float) -> None:
17
- if not 0 <= probability <= 1:
18
- raise ValueError("Probability must be between 0 and 1")
19
-
20
-
21
14
  def get_kelly_bet(
22
15
  max_bet: float,
23
16
  market_p_yes: float,
@@ -47,10 +40,10 @@ def get_kelly_bet(
47
40
  check_is_valid_probability(confidence)
48
41
 
49
42
  if estimated_p_yes > market_p_yes:
50
- bet_direction = BetDirection.YES
43
+ bet_direction = True
51
44
  market_prob = market_p_yes
52
45
  else:
53
- bet_direction = BetDirection.NO
46
+ bet_direction = False
54
47
  market_prob = 1 - market_p_yes
55
48
 
56
49
  # Handle the case where market_prob is 0
@@ -143,7 +143,7 @@ def is_predictable_without_description(
143
143
  description=description,
144
144
  )
145
145
  completion = str(
146
- llm(
146
+ llm.invoke(
147
147
  messages, max_tokens=max_tokens, config=get_langfuse_langchain_config()
148
148
  ).content
149
149
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.48.5
3
+ Version: 0.48.8
4
4
  Summary: Tools to benchmark, deploy and monitor prediction market agents.
5
5
  Author: Gnosis
6
6
  Requires-Python: >=3.10,<3.12
@@ -11,12 +11,13 @@ prediction_market_agent_tooling/abis/omen_realitio.abi.json,sha256=7HmFkBF_rq83U
11
11
  prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json,sha256=u1-3B8FB3Ys9KVJCH-lw9ArkicdxbNMf34dV-VEGMMU,930
12
12
  prediction_market_agent_tooling/abis/proxy.abi.json,sha256=h24GXZ6Q0bSZlwh7zOv0EiDvbqUz_PHtWfKHTyPJ1w4,644
13
13
  prediction_market_agent_tooling/benchmark/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- prediction_market_agent_tooling/benchmark/agents.py,sha256=HPIFJvackW110ch3UkktbxhU48gMRVo4gQse84Klhdc,4000
14
+ prediction_market_agent_tooling/benchmark/agents.py,sha256=BwE3U11tQq0rfOJBn-Xn5ZgN1DTXBEehvmdZx6A7DuE,3918
15
15
  prediction_market_agent_tooling/benchmark/benchmark.py,sha256=xiHKzZx5GHSsDerFHMZ9j_LXAXnSaITSvv67iPe3MEU,21095
16
- prediction_market_agent_tooling/benchmark/utils.py,sha256=iS1BzyXcCMfMm1Rx--1QCH0pHvBTblTndcDQFbTUJ2s,2897
16
+ prediction_market_agent_tooling/benchmark/utils.py,sha256=D0MfUkVZllmvcU0VOurk9tcKT7JTtwwOp-63zuCBVuc,2880
17
17
  prediction_market_agent_tooling/config.py,sha256=9h68Nb9O1YZabZqtOBrH1S-4U5aIdLKfVYLSKspfUeA,6008
18
- prediction_market_agent_tooling/deploy/agent.py,sha256=khZ7zoAkeKTgSnBzKaD5b-59B2ZKCvBBKRXu6E9Secc,17312
19
- prediction_market_agent_tooling/deploy/agent_example.py,sha256=eV7vuaX77PF-gs1x0ILUy9nWoPLOF3jzG5SCuroHF-4,934
18
+ prediction_market_agent_tooling/deploy/agent.py,sha256=MdNiUG2y-E6S_Hc7d31ISIPF7e18-2bmO8SULg7RDd4,17760
19
+ prediction_market_agent_tooling/deploy/agent_example.py,sha256=dIIdZashExWk9tOdyDjw87AuUcGyM7jYxNChYrVK2dM,1001
20
+ prediction_market_agent_tooling/deploy/betting_strategy.py,sha256=nJizN4d_jsw5WA8uukaKModVezAgVwoLrCOXsaBOwXo,2223
20
21
  prediction_market_agent_tooling/deploy/constants.py,sha256=M5ty8URipYMGe_G-RzxRydK3AFL6CyvmqCraJUrLBnE,82
21
22
  prediction_market_agent_tooling/deploy/gcp/deploy.py,sha256=CYUgnfy-9XVk04kkxA_5yp0GE9Mw5caYqlFUZQ2j3ks,3739
22
23
  prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py,sha256=qYIHRxQLac3yxtZ8ChikiPG9O1aUQucHW0muTSm1nto,2627
@@ -25,7 +26,7 @@ prediction_market_agent_tooling/gtypes.py,sha256=ezM2iAycTRJ0uHKK03s0z76a8YFSF43
25
26
  prediction_market_agent_tooling/loggers.py,sha256=JiBTgvb34O9dKHYKZyQ0UzojPUy6KSFQSTfbBIXopSY,3721
26
27
  prediction_market_agent_tooling/markets/agent_market.py,sha256=BELq6x3F4xLZwi0XmoN84RA7ttRQIclyHL2CY6a4Ixc,8409
27
28
  prediction_market_agent_tooling/markets/categorize.py,sha256=jsoHWvZk9pU6n17oWSCcCxNNYVwlb_NXsZxKRI7vmsk,1301
28
- prediction_market_agent_tooling/markets/data_models.py,sha256=jtQU2GAsT3uDXqj_08KYBk3Qf3T65fC7QTIk-4scdjY,2095
29
+ prediction_market_agent_tooling/markets/data_models.py,sha256=muGWJ8Y3UeDhpwAAGovYGfMMdbbVQcJlS5OruFmaKD4,3108
29
30
  prediction_market_agent_tooling/markets/manifold/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
31
  prediction_market_agent_tooling/markets/manifold/api.py,sha256=AC2zmkzpBU3P4kyybs7CgPbDg4hLAx3GY5mjgDi7qDo,7221
31
32
  prediction_market_agent_tooling/markets/manifold/data_models.py,sha256=jHqOzOiN21wYvDNyh4VtbGtj4adWr6vA4liOQmh24cc,6239
@@ -36,14 +37,14 @@ prediction_market_agent_tooling/markets/metaculus/api.py,sha256=gvPQVAM5NlCyWzEM
36
37
  prediction_market_agent_tooling/markets/metaculus/data_models.py,sha256=6TBy17xntdLBR61QCE5wddwTa_k2D0D8ZgK6p7sGUuc,2448
37
38
  prediction_market_agent_tooling/markets/metaculus/metaculus.py,sha256=uNF7LP4evvubk818g2zbX1VlnFxeUQOkNgx_e_LwaJA,3416
38
39
  prediction_market_agent_tooling/markets/omen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- prediction_market_agent_tooling/markets/omen/data_models.py,sha256=VCY-TD4RBCd63T1PtF5AwjPWbZ3MC02TGw_BAOEZSyc,14591
40
+ prediction_market_agent_tooling/markets/omen/data_models.py,sha256=7KXT8a_WYyXMFR8OtcPlaazeigc8eE_AvBkx2q-CNi8,16764
40
41
  prediction_market_agent_tooling/markets/omen/omen.py,sha256=fL8Lk1H0guwNBcgvT8Ymy3jRewbWLbJ9m8br4HN7vPg,40014
41
- prediction_market_agent_tooling/markets/omen/omen_contracts.py,sha256=DWJk7GZgw_UxxFxdVeDJTcskWlJ8AchN0QaXWZrrh4E,23633
42
- prediction_market_agent_tooling/markets/omen/omen_resolving.py,sha256=8uHWH1nMYiop4wOhSSoz3tdaexa-qb6KX10SiyaYYhA,10981
43
- prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py,sha256=4F4QR8MDwyEw52rolEJNxtbCcIipX6ccNHANfWyCBjg,25945
42
+ prediction_market_agent_tooling/markets/omen/omen_contracts.py,sha256=MfaWfDDfEzHYVAbeT3Dgtl8KG7XsqEpdY3m3-rsOPwo,23588
43
+ prediction_market_agent_tooling/markets/omen/omen_resolving.py,sha256=Awaw1r32IBAClCktrXbYJ24RNyLDWcLb8RqAx6FGSkI,9529
44
+ prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py,sha256=XMCXEZi5TWpxxw5hDJ3QU-19VpD77otw3qhNLT_OhRE,28452
44
45
  prediction_market_agent_tooling/markets/polymarket/api.py,sha256=HXmA1akA0qDj0m3e-GEvWG8x75pm6BX4H7YJPQcST7I,4767
45
46
  prediction_market_agent_tooling/markets/polymarket/data_models.py,sha256=9CJzakyEcsn6DQBK2nOXjOMzTZBLAmK_KqevXvW17DI,4292
46
- prediction_market_agent_tooling/markets/polymarket/data_models_web.py,sha256=yK0uxLQrwImVAXbvwscdmxTjSxMpAjCcN760EWEK_8M,11914
47
+ prediction_market_agent_tooling/markets/polymarket/data_models_web.py,sha256=IPsFT3FX9Ge5l5zR1nBd2w-sd5ue7oR8PJSW710vFWY,12479
47
48
  prediction_market_agent_tooling/markets/polymarket/polymarket.py,sha256=f7r79fAhLzwS22urfuhVW1Si2m2pZrr5r45WNt-Q3VU,2737
48
49
  prediction_market_agent_tooling/markets/polymarket/utils.py,sha256=m4JG6WULh5epCJt4XBMHg0ae5NoVhqlOvAl0A7DR9iM,2023
49
50
  prediction_market_agent_tooling/monitor/markets/manifold.py,sha256=GdYpgRX1GahDi-75Mr53jgtEg6nWcs_rHDUkg4o_7dQ,3352
@@ -51,11 +52,11 @@ prediction_market_agent_tooling/monitor/markets/metaculus.py,sha256=S8zeDVN2aA6y
51
52
  prediction_market_agent_tooling/monitor/markets/omen.py,sha256=jOLPnIbDU9syjnYtHfOb2xa6-Ize3vbplgh-8WWkuT4,3323
52
53
  prediction_market_agent_tooling/monitor/markets/polymarket.py,sha256=I9z9aO1wncyGI3a09ihrw17JkeBKjAuMmC0I9pl_9o4,1781
53
54
  prediction_market_agent_tooling/monitor/monitor.py,sha256=snMSPmoHFV7QchqsFBaNkOEQhHJshF1qmIGPuID1giQ,14579
54
- prediction_market_agent_tooling/monitor/monitor_app.py,sha256=THyZ67baByakoOm3hIqWOFOBCzg1ZMb_ILgXQ6y0NwE,4763
55
+ prediction_market_agent_tooling/monitor/monitor_app.py,sha256=1e4LuzhAVjb7cPS6rGPZuZHMwMiNOeRhSxG8AVG-e0o,4839
55
56
  prediction_market_agent_tooling/monitor/monitor_settings.py,sha256=Xiozs3AsufuJ04JOe1vjUri-IAMWHjjmc2ugGGiHNH4,947
56
57
  prediction_market_agent_tooling/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
58
  prediction_market_agent_tooling/tools/balances.py,sha256=nR8_dSfbm3yTOOmMAwhGlurftEiNo1w1WIVzbskjdmM,837
58
- prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py,sha256=d3QEg1Bia8D7SPHGr-SgP0OHSLIzm_hf4sN4iz06qiM,1951
59
+ prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py,sha256=IoLx8fIOqjC9d2gSWIc5Y-3wlukib6cuJaJzguHqNbU,1835
59
60
  prediction_market_agent_tooling/tools/betting_strategies/market_moving.py,sha256=wtrHVQRuA0uDx06z0OxQLYbswuOpHQ1UyCWwLCrD_oM,4400
60
61
  prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py,sha256=-FUSuQQgjcWSSnoFxnlAyTeilY6raJABJVM2QKkFqAY,438
61
62
  prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py,sha256=THMXwFlskvzbjnX_OiYtDSzI8XVFyULWfP2525_9UGc,429
@@ -67,7 +68,7 @@ prediction_market_agent_tooling/tools/google.py,sha256=SfVDxb3oEOUK8mpd0l3mTX9yb
67
68
  prediction_market_agent_tooling/tools/hexbytes_custom.py,sha256=Bp94qgPjvjWf1Vb4lNzGFDXRdThw1rJ91vL6r2PWq5E,2096
68
69
  prediction_market_agent_tooling/tools/image_gen/image_gen.py,sha256=HzRwBx62hOXBOmrtpkXaP9Qq1Ku03uUGdREocyjLQ_k,1266
69
70
  prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py,sha256=8A3U2uxsCsOfLjru-6R_PPIAuiKY4qFkWp_GSBPV6-s,1280
70
- prediction_market_agent_tooling/tools/is_predictable.py,sha256=w-p75LWVr5Pelau1ea2NmDzZE5VbbzFGAZPq3zwq02Q,6551
71
+ prediction_market_agent_tooling/tools/is_predictable.py,sha256=GqBgp4aHbY97PdprKfCHV-lJy2bbGIrd9yCtkqg6gEc,6558
71
72
  prediction_market_agent_tooling/tools/langfuse_.py,sha256=jI_4ROxqo41CCnWGS1vN_AeDVhRzLMaQLxH3kxDu3L8,1153
72
73
  prediction_market_agent_tooling/tools/parallelism.py,sha256=Rz8QdVUWX8KCbr8UZfaC_b1GBWIb3bXwITUumuvBJ60,1633
73
74
  prediction_market_agent_tooling/tools/safe.py,sha256=h0xOO0eNtitClf0fPkn-0oTc6A_bflDTee98V_aiV-A,5195
@@ -77,8 +78,8 @@ prediction_market_agent_tooling/tools/tavily_storage/tavily_models.py,sha256=dr-
77
78
  prediction_market_agent_tooling/tools/tavily_storage/tavily_storage.py,sha256=eln3BygdfsDf8WOlSQPL7qH946QnGnThRkazRZKBA8o,3194
78
79
  prediction_market_agent_tooling/tools/utils.py,sha256=JE9YWtPPhnTgLiOyGAZDNG5K8nCwUY9IZEuAlm9UcxA,6611
79
80
  prediction_market_agent_tooling/tools/web3_utils.py,sha256=euq_MH-LhTowACq42colks2IXxZQjqjuisYl91EYZtU,10440
80
- prediction_market_agent_tooling-0.48.5.dist-info/LICENSE,sha256=6or154nLLU6bELzjh0mCreFjt0m2v72zLi3yHE0QbeE,7650
81
- prediction_market_agent_tooling-0.48.5.dist-info/METADATA,sha256=T6nk1eHBTZTrt6UXFqHHb2gPP7K_2TEe_orSRBQIuCM,7810
82
- prediction_market_agent_tooling-0.48.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
83
- prediction_market_agent_tooling-0.48.5.dist-info/entry_points.txt,sha256=m8PukHbeH5g0IAAmOf_1Ahm-sGAMdhSSRQmwtpmi2s8,81
84
- prediction_market_agent_tooling-0.48.5.dist-info/RECORD,,
81
+ prediction_market_agent_tooling-0.48.8.dist-info/LICENSE,sha256=6or154nLLU6bELzjh0mCreFjt0m2v72zLi3yHE0QbeE,7650
82
+ prediction_market_agent_tooling-0.48.8.dist-info/METADATA,sha256=-l7BCizaFtD0scKftcebwoel16w9o2nggRSRjMJ_EEc,7810
83
+ prediction_market_agent_tooling-0.48.8.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
84
+ prediction_market_agent_tooling-0.48.8.dist-info/entry_points.txt,sha256=m8PukHbeH5g0IAAmOf_1Ahm-sGAMdhSSRQmwtpmi2s8,81
85
+ prediction_market_agent_tooling-0.48.8.dist-info/RECORD,,