prediction-market-agent-tooling 0.52.1__py3-none-any.whl → 0.53.0__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 (23) hide show
  1. prediction_market_agent_tooling/deploy/agent.py +2 -1
  2. prediction_market_agent_tooling/deploy/betting_strategy.py +56 -46
  3. prediction_market_agent_tooling/jobs/omen/omen_jobs.py +1 -1
  4. prediction_market_agent_tooling/markets/agent_market.py +19 -1
  5. prediction_market_agent_tooling/markets/manifold/manifold.py +8 -0
  6. prediction_market_agent_tooling/markets/market_fees.py +36 -0
  7. prediction_market_agent_tooling/markets/metaculus/metaculus.py +2 -0
  8. prediction_market_agent_tooling/markets/omen/omen.py +32 -14
  9. prediction_market_agent_tooling/markets/omen/omen_contracts.py +1 -1
  10. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +15 -1
  11. prediction_market_agent_tooling/markets/polymarket/polymarket.py +7 -0
  12. prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +8 -2
  13. prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +12 -5
  14. prediction_market_agent_tooling/tools/langfuse_client_utils.py +4 -1
  15. prediction_market_agent_tooling/tools/tavily/tavily_models.py +84 -0
  16. prediction_market_agent_tooling/tools/{tavily_storage/tavily_storage.py → tavily/tavily_search.py} +28 -2
  17. prediction_market_agent_tooling/tools/{tavily_storage/tavily_models.py → tavily/tavily_storage.py} +10 -87
  18. prediction_market_agent_tooling/tools/utils.py +3 -6
  19. {prediction_market_agent_tooling-0.52.1.dist-info → prediction_market_agent_tooling-0.53.0.dist-info}/METADATA +1 -1
  20. {prediction_market_agent_tooling-0.52.1.dist-info → prediction_market_agent_tooling-0.53.0.dist-info}/RECORD +23 -21
  21. {prediction_market_agent_tooling-0.52.1.dist-info → prediction_market_agent_tooling-0.53.0.dist-info}/LICENSE +0 -0
  22. {prediction_market_agent_tooling-0.52.1.dist-info → prediction_market_agent_tooling-0.53.0.dist-info}/WHEEL +0 -0
  23. {prediction_market_agent_tooling-0.52.1.dist-info → prediction_market_agent_tooling-0.53.0.dist-info}/entry_points.txt +0 -0
@@ -297,6 +297,7 @@ class DeployableTraderAgent(DeployableAgent):
297
297
  min_required_balance_to_operate: xDai | None = xdai_type(1)
298
298
  min_balance_to_keep_in_native_currency: xDai | None = xdai_type(0.1)
299
299
  allow_invalid_questions: bool = False
300
+ same_market_bet_interval: timedelta = timedelta(hours=24)
300
301
 
301
302
  def __init__(
302
303
  self,
@@ -394,7 +395,7 @@ class DeployableTraderAgent(DeployableAgent):
394
395
  Subclasses can implement their own logic instead of this one, or on top of this one.
395
396
  By default, it allows only markets where user didn't bet recently and it's a reasonable question.
396
397
  """
397
- if self.have_bet_on_market_since(market, since=timedelta(hours=24)):
398
+ if self.have_bet_on_market_since(market, since=self.same_market_bet_interval):
398
399
  return False
399
400
 
400
401
  # Manifold allows to bet only on markets with probability between 1 and 99.
@@ -4,7 +4,7 @@ from scipy.optimize import minimize_scalar
4
4
 
5
5
  from prediction_market_agent_tooling.gtypes import xDai
6
6
  from prediction_market_agent_tooling.loggers import logger
7
- from prediction_market_agent_tooling.markets.agent_market import AgentMarket
7
+ from prediction_market_agent_tooling.markets.agent_market import AgentMarket, MarketFees
8
8
  from prediction_market_agent_tooling.markets.data_models import (
9
9
  Currency,
10
10
  Position,
@@ -19,7 +19,6 @@ from prediction_market_agent_tooling.markets.omen.omen import (
19
19
  )
20
20
  from prediction_market_agent_tooling.tools.betting_strategies.kelly_criterion import (
21
21
  get_kelly_bet_full,
22
- get_kelly_bet_simplified,
23
22
  )
24
23
  from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet
25
24
  from prediction_market_agent_tooling.tools.utils import check_not_none
@@ -48,6 +47,26 @@ class BettingStrategy(ABC):
48
47
  "Cannot handle trades with currencies that deviate from market's currency"
49
48
  )
50
49
 
50
+ @staticmethod
51
+ def assert_buy_trade_wont_be_guaranteed_loss(
52
+ market: AgentMarket, trades: list[Trade]
53
+ ) -> None:
54
+ for trade in trades:
55
+ if trade.trade_type == TradeType.BUY:
56
+ outcome_tokens_to_get = market.get_buy_token_amount(
57
+ trade.amount, trade.outcome
58
+ )
59
+
60
+ if outcome_tokens_to_get.amount < trade.amount.amount:
61
+ raise RuntimeError(
62
+ f"Trade {trade=} would result in guaranteed loss by getting only {outcome_tokens_to_get=}."
63
+ )
64
+
65
+ @staticmethod
66
+ def check_trades(market: AgentMarket, trades: list[Trade]) -> None:
67
+ BettingStrategy.assert_trades_currency_match_markets(market, trades)
68
+ BettingStrategy.assert_buy_trade_wont_be_guaranteed_loss(market, trades)
69
+
51
70
  def _build_rebalance_trades_from_positions(
52
71
  self,
53
72
  existing_position: Position | None,
@@ -96,7 +115,10 @@ class BettingStrategy(ABC):
96
115
 
97
116
  # Sort inplace with SELL last
98
117
  trades.sort(key=lambda t: t.trade_type == TradeType.SELL)
99
- BettingStrategy.assert_trades_currency_match_markets(market, trades)
118
+
119
+ # Run some sanity checks to not place unreasonable bets.
120
+ BettingStrategy.check_trades(market, trades)
121
+
100
122
  return trades
101
123
 
102
124
 
@@ -153,32 +175,24 @@ class KellyBettingStrategy(BettingStrategy):
153
175
  market: AgentMarket,
154
176
  ) -> list[Trade]:
155
177
  outcome_token_pool = check_not_none(market.outcome_token_pool)
156
- kelly_bet = (
157
- get_kelly_bet_full(
158
- yes_outcome_pool_size=outcome_token_pool[
159
- market.get_outcome_str_from_bool(True)
160
- ],
161
- no_outcome_pool_size=outcome_token_pool[
162
- market.get_outcome_str_from_bool(False)
163
- ],
164
- estimated_p_yes=answer.p_yes,
165
- max_bet=self.max_bet_amount,
166
- confidence=answer.confidence,
167
- )
168
- if market.has_token_pool()
169
- else get_kelly_bet_simplified(
170
- self.max_bet_amount,
171
- market.current_p_yes,
172
- answer.p_yes,
173
- answer.confidence,
174
- )
178
+ kelly_bet = get_kelly_bet_full(
179
+ yes_outcome_pool_size=outcome_token_pool[
180
+ market.get_outcome_str_from_bool(True)
181
+ ],
182
+ no_outcome_pool_size=outcome_token_pool[
183
+ market.get_outcome_str_from_bool(False)
184
+ ],
185
+ estimated_p_yes=answer.p_yes,
186
+ max_bet=self.max_bet_amount,
187
+ confidence=answer.confidence,
188
+ fees=market.fees,
175
189
  )
176
190
 
177
191
  kelly_bet_size = kelly_bet.size
178
192
  if self.max_price_impact:
179
193
  # Adjust amount
180
194
  max_price_impact_bet_amount = self.calculate_bet_amount_for_price_impact(
181
- market, kelly_bet, 0
195
+ market, kelly_bet
182
196
  )
183
197
 
184
198
  # We just don't want Kelly size to extrapolate price_impact - hence we take the min.
@@ -196,7 +210,12 @@ class KellyBettingStrategy(BettingStrategy):
196
210
  return trades
197
211
 
198
212
  def calculate_price_impact_for_bet_amount(
199
- self, buy_direction: bool, bet_amount: float, yes: float, no: float, fee: float
213
+ self,
214
+ buy_direction: bool,
215
+ bet_amount: float,
216
+ yes: float,
217
+ no: float,
218
+ fees: MarketFees,
200
219
  ) -> float:
201
220
  total_outcome_tokens = yes + no
202
221
  expected_price = (
@@ -204,7 +223,7 @@ class KellyBettingStrategy(BettingStrategy):
204
223
  )
205
224
 
206
225
  tokens_to_buy = get_buy_outcome_token_amount(
207
- bet_amount, buy_direction, yes, no, fee
226
+ bet_amount, buy_direction, yes, no, fees
208
227
  )
209
228
 
210
229
  actual_price = bet_amount / tokens_to_buy
@@ -216,7 +235,6 @@ class KellyBettingStrategy(BettingStrategy):
216
235
  self,
217
236
  market: AgentMarket,
218
237
  kelly_bet: SimpleBet,
219
- fee: float,
220
238
  ) -> float:
221
239
  def calculate_price_impact_deviation_from_target_price_impact(
222
240
  bet_amount: xDai,
@@ -226,7 +244,7 @@ class KellyBettingStrategy(BettingStrategy):
226
244
  bet_amount,
227
245
  yes_outcome_pool_size,
228
246
  no_outcome_pool_size,
229
- fee,
247
+ market.fees,
230
248
  )
231
249
  # We return abs for the algorithm to converge to 0 instead of the min (and possibly negative) value.
232
250
 
@@ -285,25 +303,17 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
285
303
  estimated_p_yes = float(answer.p_yes > 0.5)
286
304
  confidence = 1.0
287
305
 
288
- kelly_bet = (
289
- get_kelly_bet_full(
290
- yes_outcome_pool_size=outcome_token_pool[
291
- market.get_outcome_str_from_bool(True)
292
- ],
293
- no_outcome_pool_size=outcome_token_pool[
294
- market.get_outcome_str_from_bool(False)
295
- ],
296
- estimated_p_yes=estimated_p_yes,
297
- max_bet=adjusted_bet_amount,
298
- confidence=confidence,
299
- )
300
- if market.has_token_pool()
301
- else get_kelly_bet_simplified(
302
- adjusted_bet_amount,
303
- market.current_p_yes,
304
- estimated_p_yes,
305
- confidence,
306
- )
306
+ kelly_bet = get_kelly_bet_full(
307
+ yes_outcome_pool_size=outcome_token_pool[
308
+ market.get_outcome_str_from_bool(True)
309
+ ],
310
+ no_outcome_pool_size=outcome_token_pool[
311
+ market.get_outcome_str_from_bool(False)
312
+ ],
313
+ estimated_p_yes=estimated_p_yes,
314
+ max_bet=adjusted_bet_amount,
315
+ confidence=confidence,
316
+ fees=market.fees,
307
317
  )
308
318
 
309
319
  amounts = {
@@ -75,7 +75,7 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
75
75
  market_maker_contract_address_checksummed=market.market_maker_contract_address_checksummed,
76
76
  condition=market.condition,
77
77
  finalized_time=market.finalized_time,
78
- fee=market.fee,
78
+ fees=market.fees,
79
79
  )
80
80
 
81
81
 
@@ -2,7 +2,7 @@ import typing as t
2
2
  from enum import Enum
3
3
 
4
4
  from eth_typing import ChecksumAddress
5
- from pydantic import BaseModel, field_validator
5
+ from pydantic import BaseModel, field_validator, model_validator
6
6
  from pydantic_core.core_schema import FieldValidationInfo
7
7
 
8
8
  from prediction_market_agent_tooling.config import APIKeys
@@ -16,6 +16,7 @@ from prediction_market_agent_tooling.markets.data_models import (
16
16
  ResolvedBet,
17
17
  TokenAmount,
18
18
  )
19
+ from prediction_market_agent_tooling.markets.market_fees import MarketFees
19
20
  from prediction_market_agent_tooling.tools.utils import (
20
21
  DatetimeUTC,
21
22
  check_not_none,
@@ -60,6 +61,7 @@ class AgentMarket(BaseModel):
60
61
  current_p_yes: Probability
61
62
  url: str
62
63
  volume: float | None # Should be in currency of `currency` above.
64
+ fees: MarketFees
63
65
 
64
66
  @field_validator("outcome_token_pool")
65
67
  def validate_outcome_token_pool(
@@ -77,6 +79,14 @@ class AgentMarket(BaseModel):
77
79
  )
78
80
  return outcome_token_pool
79
81
 
82
+ @model_validator(mode="before")
83
+ def handle_legacy_fee(cls, data: dict[str, t.Any]) -> dict[str, t.Any]:
84
+ # Backward compatibility for older `AgentMarket` without `fees`.
85
+ if "fees" not in data and "fee" in data:
86
+ data["fees"] = MarketFees(absolute=0.0, bet_proportion=data["fee"])
87
+ del data["fee"]
88
+ return data
89
+
80
90
  @property
81
91
  def current_p_no(self) -> Probability:
82
92
  return Probability(1 - self.current_p_yes)
@@ -166,6 +176,11 @@ class AgentMarket(BaseModel):
166
176
  def buy_tokens(self, outcome: bool, amount: TokenAmount) -> str:
167
177
  return self.place_bet(outcome=outcome, amount=amount)
168
178
 
179
+ def get_buy_token_amount(
180
+ self, bet_amount: BetAmount, direction: bool
181
+ ) -> TokenAmount:
182
+ raise NotImplementedError("Subclasses must implement this method")
183
+
169
184
  def sell_tokens(self, outcome: bool, amount: TokenAmount) -> str:
170
185
  raise NotImplementedError("Subclasses must implement this method")
171
186
 
@@ -285,3 +300,6 @@ class AgentMarket(BaseModel):
285
300
  @staticmethod
286
301
  def get_user_id(api_keys: APIKeys) -> str:
287
302
  raise NotImplementedError("Subclasses must implement this method")
303
+
304
+ def get_most_recent_trade_datetime(self, user_id: str) -> DatetimeUTC | None:
305
+ raise NotImplementedError("Subclasses must implement this method")
@@ -6,6 +6,7 @@ from prediction_market_agent_tooling.gtypes import Mana, Probability, mana_type
6
6
  from prediction_market_agent_tooling.markets.agent_market import (
7
7
  AgentMarket,
8
8
  FilterBy,
9
+ MarketFees,
9
10
  SortBy,
10
11
  )
11
12
  from prediction_market_agent_tooling.markets.data_models import BetAmount, Currency
@@ -33,6 +34,13 @@ class ManifoldAgentMarket(AgentMarket):
33
34
  currency: t.ClassVar[Currency] = Currency.Mana
34
35
  base_url: t.ClassVar[str] = MANIFOLD_BASE_URL
35
36
 
37
+ # Manifold has additional fees than `platform_absolute`, but they don't expose them in the API before placing the bet, see https://docs.manifold.markets/api.
38
+ # So we just consider them as 0, which anyway is true for all markets I randomly checked on Manifold.
39
+ fees: MarketFees = MarketFees(
40
+ bet_proportion=0,
41
+ absolute=0.25, # For doing trades via API.
42
+ )
43
+
36
44
  def get_last_trade_p_yes(self) -> Probability:
37
45
  """On Manifold, probablities aren't updated after the closure, so we can just use the current probability"""
38
46
  return self.current_p_yes
@@ -0,0 +1,36 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class MarketFees(BaseModel):
5
+ bet_proportion: float = Field(
6
+ ..., ge=0.0, lt=1.0
7
+ ) # proportion of the bet, from 0 to 1
8
+ absolute: float # absolute value paid in the currency of the market
9
+
10
+ @staticmethod
11
+ def get_zero_fees(
12
+ bet_proportion: float = 0.0,
13
+ absolute: float = 0.0,
14
+ ) -> "MarketFees":
15
+ return MarketFees(
16
+ bet_proportion=bet_proportion,
17
+ absolute=absolute,
18
+ )
19
+
20
+ def total_fee_absolute_value(self, bet_amount: float) -> float:
21
+ """
22
+ Returns the total fee in absolute terms, including both proportional and fixed fees.
23
+ """
24
+ return self.bet_proportion * bet_amount + self.absolute
25
+
26
+ def total_fee_relative_value(self, bet_amount: float) -> float:
27
+ """
28
+ Returns the total fee relative to the bet amount, including both proportional and fixed fees.
29
+ """
30
+ if bet_amount == 0:
31
+ return 0.0
32
+ total_fee = self.total_fee_absolute_value(bet_amount)
33
+ return total_fee / bet_amount
34
+
35
+ def get_bet_size_after_fees(self, bet_amount: float) -> float:
36
+ return bet_amount - self.total_fee_absolute_value(bet_amount)
@@ -5,6 +5,7 @@ from prediction_market_agent_tooling.gtypes import Probability
5
5
  from prediction_market_agent_tooling.markets.agent_market import (
6
6
  AgentMarket,
7
7
  FilterBy,
8
+ MarketFees,
8
9
  SortBy,
9
10
  )
10
11
  from prediction_market_agent_tooling.markets.metaculus.api import (
@@ -29,6 +30,7 @@ class MetaculusAgentMarket(AgentMarket):
29
30
  description: str | None = (
30
31
  None # Metaculus markets don't have a description, so just default to None.
31
32
  )
33
+ fees: MarketFees = MarketFees.get_zero_fees() # No fees on Metaculus.
32
34
 
33
35
  @staticmethod
34
36
  def from_data_model(model: MetaculusQuestion) -> "MetaculusAgentMarket":
@@ -22,6 +22,7 @@ from prediction_market_agent_tooling.loggers import logger
22
22
  from prediction_market_agent_tooling.markets.agent_market import (
23
23
  AgentMarket,
24
24
  FilterBy,
25
+ MarketFees,
25
26
  SortBy,
26
27
  )
27
28
  from prediction_market_agent_tooling.markets.data_models import (
@@ -101,7 +102,6 @@ class OmenAgentMarket(AgentMarket):
101
102
  finalized_time: DatetimeUTC | None
102
103
  created_time: DatetimeUTC
103
104
  close_time: DatetimeUTC
104
- fee: float # proportion, from 0 to 1
105
105
 
106
106
  _binary_market_p_yes_history: list[Probability] | None = None
107
107
  description: str | None = (
@@ -138,11 +138,11 @@ class OmenAgentMarket(AgentMarket):
138
138
  else None
139
139
  )
140
140
 
141
- def get_liquidity_in_wei(self) -> Wei:
142
- return self.get_contract().totalSupply()
141
+ def get_liquidity_in_wei(self, web3: Web3 | None = None) -> Wei:
142
+ return self.get_contract().totalSupply(web3)
143
143
 
144
- def get_liquidity_in_xdai(self) -> xDai:
145
- return wei_to_xdai(self.get_liquidity_in_wei())
144
+ def get_liquidity_in_xdai(self, web3: Web3 | None = None) -> xDai:
145
+ return wei_to_xdai(self.get_liquidity_in_wei(web3))
146
146
 
147
147
  def get_liquidity(self) -> TokenAmount:
148
148
  return TokenAmount(
@@ -186,6 +186,7 @@ class OmenAgentMarket(AgentMarket):
186
186
  amount=token_amount,
187
187
  auto_withdraw=False,
188
188
  web3=web3,
189
+ api_keys=api_keys,
189
190
  )
190
191
 
191
192
  def place_bet(
@@ -240,7 +241,7 @@ class OmenAgentMarket(AgentMarket):
240
241
  shares_to_sell=amount.amount,
241
242
  holdings=wei_to_xdai(pool_balance[self.get_index_set(sell_str)]),
242
243
  other_holdings=wei_to_xdai(pool_balance[self.get_index_set(other_str)]),
243
- fee=self.fee,
244
+ fees=self.fees,
244
245
  )
245
246
  return xDai(collateral)
246
247
 
@@ -352,7 +353,12 @@ class OmenAgentMarket(AgentMarket):
352
353
  url=model.url,
353
354
  volume=wei_to_xdai(model.collateralVolume),
354
355
  close_time=model.close_time,
355
- fee=float(wei_to_xdai(model.fee)) if model.fee is not None else 0.0,
356
+ fees=MarketFees(
357
+ bet_proportion=(
358
+ float(wei_to_xdai(model.fee)) if model.fee is not None else 0.0
359
+ ),
360
+ absolute=0,
361
+ ),
356
362
  outcome_token_pool={
357
363
  model.outcomes[i]: wei_to_xdai(Wei(model.outcomeTokenAmounts[i]))
358
364
  for i in range(len(model.outcomes))
@@ -598,7 +604,7 @@ class OmenAgentMarket(AgentMarket):
598
604
  buy_direction=direction,
599
605
  yes_outcome_pool_size=outcome_token_pool[OMEN_TRUE_OUTCOME],
600
606
  no_outcome_pool_size=outcome_token_pool[OMEN_FALSE_OUTCOME],
601
- fee=self.fee,
607
+ fees=self.fees,
602
608
  )
603
609
  return TokenAmount(amount=amount, currency=self.currency)
604
610
 
@@ -628,10 +634,10 @@ class OmenAgentMarket(AgentMarket):
628
634
  no_outcome_pool_size = outcome_token_pool[self.get_outcome_str_from_bool(False)]
629
635
 
630
636
  new_yes_outcome_pool_size = yes_outcome_pool_size + (
631
- bet_amount.amount * (1 - self.fee)
637
+ self.fees.get_bet_size_after_fees(bet_amount.amount)
632
638
  )
633
639
  new_no_outcome_pool_size = no_outcome_pool_size + (
634
- bet_amount.amount * (1 - self.fee)
640
+ self.fees.get_bet_size_after_fees(bet_amount.amount)
635
641
  )
636
642
 
637
643
  received_token_amount = self.get_buy_token_amount(bet_amount, direction).amount
@@ -653,6 +659,20 @@ class OmenAgentMarket(AgentMarket):
653
659
  def get_user_id(api_keys: APIKeys) -> str:
654
660
  return api_keys.bet_from_address
655
661
 
662
+ def get_most_recent_trade_datetime(self, user_id: str) -> DatetimeUTC | None:
663
+ sgh = OmenSubgraphHandler()
664
+ trades = sgh.get_trades(
665
+ sort_by_field=sgh.trades_subgraph.FpmmTrade.creationTimestamp,
666
+ sort_direction="desc",
667
+ limit=1,
668
+ better_address=Web3.to_checksum_address(user_id),
669
+ market_id=Web3.to_checksum_address(self.id),
670
+ )
671
+ if not trades:
672
+ return None
673
+
674
+ return trades[0].creation_datetime
675
+
656
676
 
657
677
  def get_omen_user_url(address: ChecksumAddress) -> str:
658
678
  return f"https://gnosisscan.io/address/{address}"
@@ -1104,7 +1124,6 @@ def omen_remove_fund_market_tx(
1104
1124
  market_contract.removeFunding(api_keys=api_keys, remove_funding=shares, web3=web3)
1105
1125
 
1106
1126
  conditional_tokens = OmenConditionalTokenContract()
1107
- parent_collection_id = build_parent_collection_id()
1108
1127
  amount_per_index_set = get_conditional_tokens_balance_for_market(
1109
1128
  market, from_address, web3
1110
1129
  )
@@ -1116,7 +1135,6 @@ def omen_remove_fund_market_tx(
1116
1135
  result = conditional_tokens.mergePositions(
1117
1136
  api_keys=api_keys,
1118
1137
  collateral_token_address=market.collateral_token_contract_address_checksummed,
1119
- parent_collection_id=parent_collection_id,
1120
1138
  conditionId=market.condition.id,
1121
1139
  index_sets=market.condition.index_sets,
1122
1140
  amount=amount_to_merge,
@@ -1266,14 +1284,14 @@ def get_buy_outcome_token_amount(
1266
1284
  buy_direction: bool,
1267
1285
  yes_outcome_pool_size: float,
1268
1286
  no_outcome_pool_size: float,
1269
- fee: float,
1287
+ fees: MarketFees,
1270
1288
  ) -> float:
1271
1289
  """
1272
1290
  Calculates the amount of outcome tokens received for a given investment
1273
1291
 
1274
1292
  Taken from https://github.com/gnosis/conditional-tokens-market-makers/blob/6814c0247c745680bb13298d4f0dd7f5b574d0db/contracts/FixedProductMarketMaker.sol#L264
1275
1293
  """
1276
- investment_amount_minus_fees = investment_amount * (1 - fee)
1294
+ investment_amount_minus_fees = fees.get_bet_size_after_fees(investment_amount)
1277
1295
  buy_token_pool_balance = (
1278
1296
  yes_outcome_pool_size if buy_direction else no_outcome_pool_size
1279
1297
  )
@@ -163,10 +163,10 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
163
163
  self,
164
164
  api_keys: APIKeys,
165
165
  collateral_token_address: ChecksumAddress,
166
- parent_collection_id: HexStr,
167
166
  conditionId: HexBytes,
168
167
  index_sets: t.List[int],
169
168
  amount: Wei,
169
+ parent_collection_id: HexStr = build_parent_collection_id(),
170
170
  web3: Web3 | None = None,
171
171
  ) -> TxReceipt:
172
172
  return self.send(
@@ -340,6 +340,7 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
340
340
  tuple[ChecksumAddress, ...] | None
341
341
  ) = SAFE_COLLATERAL_TOKEN_MARKETS,
342
342
  category: str | None = None,
343
+ creator_in: t.Sequence[HexAddress] | None = None,
343
344
  ) -> t.List[OmenMarket]:
344
345
  """
345
346
  Simplified `get_omen_binary_markets` method, which allows to fetch markets based on the filter_by and sort_by values.
@@ -375,6 +376,7 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
375
376
  question_excluded_titles=excluded_questions,
376
377
  collateral_token_address_in=collateral_token_address_in,
377
378
  category=category,
379
+ creator_in=creator_in,
378
380
  )
379
381
 
380
382
  def get_omen_binary_markets(
@@ -546,6 +548,7 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
546
548
 
547
549
  def get_trades(
548
550
  self,
551
+ limit: int | None = None,
549
552
  better_address: ChecksumAddress | None = None,
550
553
  start_time: DatetimeUTC | None = None,
551
554
  end_time: t.Optional[DatetimeUTC] = None,
@@ -554,6 +557,8 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
554
557
  type_: t.Literal["Buy", "Sell"] | None = None,
555
558
  market_opening_after: DatetimeUTC | None = None,
556
559
  collateral_amount_more_than: Wei | None = None,
560
+ sort_by_field: FieldPath | None = None,
561
+ sort_direction: str | None = None,
557
562
  ) -> list[OmenBet]:
558
563
  if not end_time:
559
564
  end_time = utcnow()
@@ -579,8 +584,17 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
579
584
  if collateral_amount_more_than is not None:
580
585
  where_stms.append(trade.collateralAmount > collateral_amount_more_than)
581
586
 
587
+ # These values can not be set to `None`, but they can be omitted.
588
+ optional_params = {}
589
+ if sort_by_field is not None:
590
+ optional_params["orderBy"] = sort_by_field
591
+ if sort_direction is not None:
592
+ optional_params["orderDirection"] = sort_direction
593
+
582
594
  trades = self.trades_subgraph.Query.fpmmTrades(
583
- first=sys.maxsize, where=where_stms
595
+ first=limit if limit else sys.maxsize,
596
+ where=where_stms,
597
+ **optional_params,
584
598
  )
585
599
  fields = self._get_fields_for_bets(trades)
586
600
  result = self.sg.query_json(fields)
@@ -3,6 +3,7 @@ import typing as t
3
3
  from prediction_market_agent_tooling.markets.agent_market import (
4
4
  AgentMarket,
5
5
  FilterBy,
6
+ MarketFees,
6
7
  SortBy,
7
8
  )
8
9
  from prediction_market_agent_tooling.markets.data_models import BetAmount, Currency
@@ -26,6 +27,12 @@ class PolymarketAgentMarket(AgentMarket):
26
27
  currency: t.ClassVar[Currency] = Currency.USDC
27
28
  base_url: t.ClassVar[str] = POLYMARKET_BASE_URL
28
29
 
30
+ # Based on https://docs.polymarket.com/#fees, there are currently no fees, except for transactions fees.
31
+ # However they do have `maker_fee_base_rate` and `taker_fee_base_rate`, but impossible to test out our implementation without them actually taking the fees.
32
+ # But then in the new subgraph API, they have `fee: BigInt! (Percentage fee of trades taken by market maker. A 2% fee is represented as 2*10^16)`.
33
+ # TODO: Check out the fees while integrating the subgraph API or if we implement placing of bets on Polymarket.
34
+ fees: MarketFees = MarketFees.get_zero_fees()
35
+
29
36
  @staticmethod
30
37
  def from_data_model(model: PolymarketMarketWithPrices) -> "PolymarketAgentMarket":
31
38
  return PolymarketAgentMarket(
@@ -1,3 +1,4 @@
1
+ from prediction_market_agent_tooling.markets.market_fees import MarketFees
1
2
  from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet
2
3
 
3
4
 
@@ -61,7 +62,7 @@ def get_kelly_bet_full(
61
62
  estimated_p_yes: float,
62
63
  confidence: float,
63
64
  max_bet: float,
64
- fee: float = 0.0, # proportion, 0 to 1
65
+ fees: MarketFees,
65
66
  ) -> SimpleBet:
66
67
  """
67
68
  Calculate the optimal bet amount using the Kelly Criterion for a binary outcome market.
@@ -86,9 +87,14 @@ def get_kelly_bet_full(
86
87
  limitations under the License.
87
88
  ```
88
89
  """
90
+ fee = fees.bet_proportion
91
+ if fees.absolute > 0:
92
+ raise RuntimeError(
93
+ f"Kelly works only with bet-proportional fees, but the fees are {fees=}."
94
+ )
95
+
89
96
  check_is_valid_probability(estimated_p_yes)
90
97
  check_is_valid_probability(confidence)
91
- check_is_valid_probability(fee)
92
98
 
93
99
  if max_bet == 0:
94
100
  return SimpleBet(direction=True, size=0)
@@ -3,7 +3,10 @@ from functools import reduce
3
3
  import numpy as np
4
4
 
5
5
  from prediction_market_agent_tooling.gtypes import Probability, Wei, xDai
6
- from prediction_market_agent_tooling.markets.omen.omen import OmenAgentMarket
6
+ from prediction_market_agent_tooling.markets.omen.omen import (
7
+ MarketFees,
8
+ OmenAgentMarket,
9
+ )
7
10
  from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet
8
11
  from prediction_market_agent_tooling.tools.utils import check_not_none
9
12
  from prediction_market_agent_tooling.tools.web3_utils import wei_to_xdai, xdai_to_wei
@@ -14,7 +17,7 @@ def get_market_moving_bet(
14
17
  no_outcome_pool_size: float,
15
18
  market_p_yes: float,
16
19
  target_p_yes: float,
17
- fee: float = 0.0, # proportion, 0 to 1
20
+ fees: MarketFees,
18
21
  max_iters: int = 100,
19
22
  ) -> SimpleBet:
20
23
  """
@@ -47,7 +50,7 @@ def get_market_moving_bet(
47
50
  # Binary search for the optimal bet amount
48
51
  for _ in range(max_iters):
49
52
  bet_amount = (min_bet_amount + max_bet_amount) / 2
50
- amounts_diff = bet_amount * (1 - fee)
53
+ amounts_diff = fees.get_bet_size_after_fees(bet_amount)
51
54
 
52
55
  # Initial new amounts are old amounts + equal new amounts for each outcome
53
56
  yes_outcome_new_pool_size = yes_outcome_pool_size + amounts_diff
@@ -106,16 +109,20 @@ def _sanity_check_omen_market_moving_bet(
106
109
  no_outcome_pool_size = outcome_token_pool[market.get_outcome_str_from_bool(False)]
107
110
  market_const = yes_outcome_pool_size * no_outcome_pool_size
108
111
 
112
+ bet_to_check_size_after_fees = market.fees.get_bet_size_after_fees(
113
+ bet_to_check.size
114
+ )
115
+
109
116
  # When you buy 'yes' tokens, you add your bet size to the both pools, then
110
117
  # subtract `buy_amount` from the 'yes' pool. And vice versa for 'no' tokens.
111
118
  new_yes_outcome_pool_size = (
112
119
  yes_outcome_pool_size
113
- + (bet_to_check.size * (1 - market.fee))
120
+ + bet_to_check_size_after_fees
114
121
  - float(bet_to_check.direction) * buy_amount
115
122
  )
116
123
  new_no_outcome_pool_size = (
117
124
  no_outcome_pool_size
118
- + (bet_to_check.size * (1 - market.fee))
125
+ + bet_to_check_size_after_fees
119
126
  - float(not bet_to_check.direction) * buy_amount
120
127
  )
121
128
  new_market_const = new_yes_outcome_pool_size * new_no_outcome_pool_size
@@ -93,15 +93,18 @@ def get_traces_for_agent(
93
93
 
94
94
  def trace_to_omen_agent_market(trace: TraceWithDetails) -> OmenAgentMarket | None:
95
95
  if not trace.input:
96
+ logger.warning(f"No input in the trace: {trace}")
96
97
  return None
97
98
  if not trace.input["args"]:
99
+ logger.warning(f"No args in the trace: {trace}")
98
100
  return None
99
101
  assert len(trace.input["args"]) == 2 and trace.input["args"][0] == "omen"
100
102
  try:
101
103
  # If the market model is invalid (e.g. outdated), it will raise an exception
102
104
  market = OmenAgentMarket.model_validate(trace.input["args"][1])
103
105
  return market
104
- except Exception:
106
+ except Exception as e:
107
+ logger.warning(f"Market not parsed from langfuse because: {e}")
105
108
  return None
106
109
 
107
110
 
@@ -0,0 +1,84 @@
1
+ import typing as t
2
+
3
+ from pydantic import BaseModel
4
+ from sqlalchemy import Column
5
+ from sqlalchemy.dialects.postgresql import JSONB
6
+ from sqlmodel import ARRAY, Field, SQLModel, String
7
+
8
+ from prediction_market_agent_tooling.tools.utils import DatetimeUTC, utcnow
9
+
10
+
11
+ class TavilyResult(BaseModel):
12
+ title: str
13
+ url: str
14
+ content: str
15
+ score: float
16
+ raw_content: str | None
17
+
18
+
19
+ class TavilyResponse(BaseModel):
20
+ query: str
21
+ follow_up_questions: str | None = None
22
+ answer: str
23
+ images: list[str]
24
+ results: list[TavilyResult]
25
+ response_time: float
26
+
27
+
28
+ class TavilyResponseModel(SQLModel, table=True):
29
+ __tablename__ = "tavily_response"
30
+ __table_args__ = {"extend_existing": True}
31
+ id: int | None = Field(None, primary_key=True)
32
+ agent_id: str = Field(index=True, nullable=False)
33
+ # Parameters used to execute the search
34
+ query: str = Field(index=True, nullable=False)
35
+ search_depth: str
36
+ topic: str
37
+ days: int | None = Field(default=None, nullable=True)
38
+ max_results: int
39
+ include_domains: list[str] | None = Field(
40
+ None, sa_column=Column(ARRAY(String), nullable=True)
41
+ )
42
+ exclude_domains: list[str] | None = Field(
43
+ None, sa_column=Column(ARRAY(String), nullable=True)
44
+ )
45
+ include_answer: bool
46
+ include_raw_content: bool
47
+ include_images: bool
48
+ use_cache: bool
49
+ # Datetime at the time of search response and response from the search
50
+ datetime_: DatetimeUTC = Field(index=True, nullable=False)
51
+ response: dict[str, t.Any] = Field(sa_column=Column(JSONB, nullable=False))
52
+
53
+ @staticmethod
54
+ def from_model(
55
+ agent_id: str,
56
+ query: str,
57
+ search_depth: t.Literal["basic", "advanced"],
58
+ topic: t.Literal["general", "news"],
59
+ days: int | None,
60
+ max_results: int,
61
+ include_domains: t.Sequence[str] | None,
62
+ exclude_domains: t.Sequence[str] | None,
63
+ include_answer: bool,
64
+ include_raw_content: bool,
65
+ include_images: bool,
66
+ use_cache: bool,
67
+ response: TavilyResponse,
68
+ ) -> "TavilyResponseModel":
69
+ return TavilyResponseModel(
70
+ agent_id=agent_id,
71
+ query=query,
72
+ search_depth=search_depth,
73
+ topic=topic,
74
+ days=days,
75
+ max_results=max_results,
76
+ include_domains=sorted(include_domains) if include_domains else None,
77
+ exclude_domains=sorted(exclude_domains) if exclude_domains else None,
78
+ include_answer=include_answer,
79
+ include_raw_content=include_raw_content,
80
+ include_images=include_images,
81
+ use_cache=use_cache,
82
+ datetime_=utcnow(),
83
+ response=response.model_dump(),
84
+ )
@@ -4,16 +4,20 @@ import tenacity
4
4
  from tavily import TavilyClient
5
5
 
6
6
  from prediction_market_agent_tooling.config import APIKeys
7
- from prediction_market_agent_tooling.tools.tavily_storage.tavily_models import (
7
+ from prediction_market_agent_tooling.tools.tavily.tavily_models import (
8
8
  TavilyResponse,
9
- TavilyStorage,
9
+ TavilyResult,
10
10
  )
11
+ from prediction_market_agent_tooling.tools.tavily.tavily_storage import TavilyStorage
12
+
13
+ DEFAULT_SCORE_THRESHOLD = 0.75 # Based on some empirical testing, anything lower wasn't very relevant to the question being asked
11
14
 
12
15
 
13
16
  def tavily_search(
14
17
  query: str,
15
18
  search_depth: t.Literal["basic", "advanced"] = "advanced",
16
19
  topic: t.Literal["general", "news"] = "general",
20
+ days: int | None = None,
17
21
  max_results: int = 5,
18
22
  include_domains: t.Sequence[str] | None = None,
19
23
  exclude_domains: t.Sequence[str] | None = None,
@@ -35,6 +39,7 @@ def tavily_search(
35
39
  search_depth=search_depth,
36
40
  topic=topic,
37
41
  max_results=max_results,
42
+ days=days,
38
43
  include_domains=include_domains,
39
44
  exclude_domains=exclude_domains,
40
45
  include_answer=include_answer,
@@ -49,6 +54,7 @@ def tavily_search(
49
54
  search_depth=search_depth,
50
55
  topic=topic,
51
56
  max_results=max_results,
57
+ days=days,
52
58
  include_domains=include_domains,
53
59
  exclude_domains=exclude_domains,
54
60
  include_answer=include_answer,
@@ -63,6 +69,7 @@ def tavily_search(
63
69
  query=query,
64
70
  search_depth=search_depth,
65
71
  topic=topic,
72
+ days=days,
66
73
  max_results=max_results,
67
74
  include_domains=include_domains,
68
75
  exclude_domains=exclude_domains,
@@ -80,6 +87,7 @@ def _tavily_search(
80
87
  query: str,
81
88
  search_depth: t.Literal["basic", "advanced"],
82
89
  topic: t.Literal["general", "news"],
90
+ days: int | None,
83
91
  max_results: int,
84
92
  include_domains: t.Sequence[str] | None,
85
93
  exclude_domains: t.Sequence[str] | None,
@@ -99,6 +107,7 @@ def _tavily_search(
99
107
  query=query,
100
108
  search_depth=search_depth,
101
109
  topic=topic,
110
+ days=days,
102
111
  max_results=max_results,
103
112
  include_domains=include_domains,
104
113
  exclude_domains=exclude_domains,
@@ -108,3 +117,20 @@ def _tavily_search(
108
117
  use_cache=use_cache,
109
118
  )
110
119
  return response
120
+
121
+
122
+ def get_related_news_since(
123
+ question: str,
124
+ days_ago: int,
125
+ score_threshold: float = DEFAULT_SCORE_THRESHOLD,
126
+ max_results: int = 3,
127
+ tavily_storage: TavilyStorage | None = None,
128
+ ) -> list[TavilyResult]:
129
+ news = tavily_search(
130
+ query=question,
131
+ days=days_ago,
132
+ max_results=max_results,
133
+ topic="news",
134
+ tavily_storage=tavily_storage,
135
+ )
136
+ return [r for r in news.results if r.score > score_threshold]
@@ -2,96 +2,15 @@ import typing as t
2
2
  from datetime import timedelta
3
3
 
4
4
  import tenacity
5
- from pydantic import BaseModel
6
- from sqlalchemy import Column
7
- from sqlalchemy.dialects.postgresql import JSONB
8
- from sqlmodel import (
9
- ARRAY,
10
- Field,
11
- Session,
12
- SQLModel,
13
- String,
14
- create_engine,
15
- desc,
16
- select,
17
- )
5
+ from sqlmodel import Session, SQLModel, create_engine, desc, select
18
6
 
19
7
  from prediction_market_agent_tooling.config import APIKeys
20
8
  from prediction_market_agent_tooling.loggers import logger
21
- from prediction_market_agent_tooling.tools.utils import DatetimeUTC, utcnow
22
-
23
-
24
- class TavilyResult(BaseModel):
25
- title: str
26
- url: str
27
- content: str
28
- score: float
29
- raw_content: str | None
30
-
31
-
32
- class TavilyResponse(BaseModel):
33
- query: str
34
- follow_up_questions: None = None
35
- answer: str
36
- images: list[str]
37
- results: list[TavilyResult]
38
- response_time: float
39
-
40
-
41
- class TavilyResponseModel(SQLModel, table=True):
42
- __tablename__ = "tavily_response"
43
- __table_args__ = {"extend_existing": True}
44
- id: int | None = Field(None, primary_key=True)
45
- agent_id: str = Field(index=True, nullable=False)
46
- # Parameters used to execute the search
47
- query: str = Field(index=True, nullable=False)
48
- search_depth: str
49
- topic: str
50
- max_results: int
51
- include_domains: list[str] | None = Field(
52
- None, sa_column=Column(ARRAY(String), nullable=True)
53
- )
54
- exclude_domains: list[str] | None = Field(
55
- None, sa_column=Column(ARRAY(String), nullable=True)
56
- )
57
- include_answer: bool
58
- include_raw_content: bool
59
- include_images: bool
60
- use_cache: bool
61
- # Datetime at the time of search response and response from the search
62
- datetime_: DatetimeUTC = Field(index=True, nullable=False)
63
- response: dict[str, t.Any] = Field(sa_column=Column(JSONB, nullable=False))
64
-
65
- @staticmethod
66
- def from_model(
67
- agent_id: str,
68
- query: str,
69
- search_depth: t.Literal["basic", "advanced"],
70
- topic: t.Literal["general", "news"],
71
- max_results: int,
72
- include_domains: t.Sequence[str] | None,
73
- exclude_domains: t.Sequence[str] | None,
74
- include_answer: bool,
75
- include_raw_content: bool,
76
- include_images: bool,
77
- use_cache: bool,
78
- response: TavilyResponse,
79
- ) -> "TavilyResponseModel":
80
- return TavilyResponseModel(
81
- agent_id=agent_id,
82
- query=query,
83
- search_depth=search_depth,
84
- topic=topic,
85
- max_results=max_results,
86
- include_domains=sorted(include_domains) if include_domains else None,
87
- exclude_domains=sorted(exclude_domains) if exclude_domains else None,
88
- include_answer=include_answer,
89
- include_raw_content=include_raw_content,
90
- include_images=include_images,
91
- use_cache=use_cache,
92
- datetime_=utcnow(),
93
- response=response.model_dump(),
94
- )
9
+ from prediction_market_agent_tooling.tools.tavily.tavily_models import (
10
+ TavilyResponse,
11
+ TavilyResponseModel,
12
+ )
13
+ from prediction_market_agent_tooling.tools.utils import utcnow
95
14
 
96
15
 
97
16
  class TavilyStorage:
@@ -119,6 +38,7 @@ class TavilyStorage:
119
38
  query: str,
120
39
  search_depth: t.Literal["basic", "advanced"],
121
40
  topic: t.Literal["general", "news"],
41
+ days: int | None,
122
42
  max_results: int,
123
43
  include_domains: t.Sequence[str] | None,
124
44
  exclude_domains: t.Sequence[str] | None,
@@ -134,6 +54,7 @@ class TavilyStorage:
134
54
  search_depth=search_depth,
135
55
  topic=topic,
136
56
  max_results=max_results,
57
+ days=days,
137
58
  include_domains=include_domains,
138
59
  exclude_domains=exclude_domains,
139
60
  include_answer=include_answer,
@@ -152,6 +73,7 @@ class TavilyStorage:
152
73
  query: str,
153
74
  search_depth: t.Literal["basic", "advanced"],
154
75
  topic: t.Literal["general", "news"],
76
+ days: int | None,
155
77
  max_results: int,
156
78
  include_domains: t.Sequence[str] | None,
157
79
  exclude_domains: t.Sequence[str] | None,
@@ -167,6 +89,7 @@ class TavilyStorage:
167
89
  .where(TavilyResponseModel.query == query)
168
90
  .where(TavilyResponseModel.search_depth == search_depth)
169
91
  .where(TavilyResponseModel.topic == topic)
92
+ .where(TavilyResponseModel.days == days)
170
93
  .where(TavilyResponseModel.max_results == max_results)
171
94
  .where(TavilyResponseModel.include_domains == include_domains)
172
95
  .where(TavilyResponseModel.exclude_domains == exclude_domains)
@@ -18,6 +18,7 @@ from prediction_market_agent_tooling.gtypes import (
18
18
  SecretStr,
19
19
  )
20
20
  from prediction_market_agent_tooling.loggers import logger
21
+ from prediction_market_agent_tooling.markets.market_fees import MarketFees
21
22
 
22
23
  T = TypeVar("T")
23
24
 
@@ -189,7 +190,7 @@ def calculate_sell_amount_in_collateral(
189
190
  shares_to_sell: float,
190
191
  holdings: float,
191
192
  other_holdings: float,
192
- fee: float,
193
+ fees: MarketFees,
193
194
  ) -> float:
194
195
  """
195
196
  Computes the amount of collateral that needs to be sold to get `shares`
@@ -198,16 +199,12 @@ def calculate_sell_amount_in_collateral(
198
199
  Taken from https://github.com/protofire/omen-exchange/blob/29d0ab16bdafa5cc0d37933c1c7608a055400c73/app/src/util/tools/fpmm/trading/index.ts#L99
199
200
  Simplified for binary markets.
200
201
  """
201
-
202
- if not (0 <= fee < 1.0):
203
- raise ValueError("Fee must be between 0 and 1")
204
-
205
202
  for v in [shares_to_sell, holdings, other_holdings]:
206
203
  if v <= 0:
207
204
  raise ValueError("All share args must be greater than 0")
208
205
 
209
206
  def f(r: float) -> float:
210
- R = r / (1 - fee)
207
+ R = (r + fees.absolute) / (1 - fees.bet_proportion)
211
208
  first_term = other_holdings - R
212
209
  second_term = holdings + shares_to_sell - R
213
210
  third_term = holdings * other_holdings
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.52.1
3
+ Version: 0.53.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
@@ -17,9 +17,9 @@ prediction_market_agent_tooling/benchmark/agents.py,sha256=B1-uWdyeN4GGKMWGK_-Cc
17
17
  prediction_market_agent_tooling/benchmark/benchmark.py,sha256=MqTiaaJ3cYiOLUVR7OyImLWxcEya3Rl5JyFYW-K0lwM,17097
18
18
  prediction_market_agent_tooling/benchmark/utils.py,sha256=D0MfUkVZllmvcU0VOurk9tcKT7JTtwwOp-63zuCBVuc,2880
19
19
  prediction_market_agent_tooling/config.py,sha256=WC30Nr16RGueTafA9i67OIB-6KDHZRryhiLPzebg9_I,6740
20
- prediction_market_agent_tooling/deploy/agent.py,sha256=wGrjwWIh27xPLhA1fFzR1ytq-tT_9TmeJIjLzEZkB5E,22222
20
+ prediction_market_agent_tooling/deploy/agent.py,sha256=3yookl4xiLLcIzvE5h-Rf6_NmBRZuKDsJu9vFJaSCtk,22294
21
21
  prediction_market_agent_tooling/deploy/agent_example.py,sha256=dIIdZashExWk9tOdyDjw87AuUcGyM7jYxNChYrVK2dM,1001
22
- prediction_market_agent_tooling/deploy/betting_strategy.py,sha256=cOPznMX0jd380qHw06A-l1XUyoicV54AXBghirtPw0Q,12127
22
+ prediction_market_agent_tooling/deploy/betting_strategy.py,sha256=6PceKCNa4CM8ws033JFoCDb2Xm9OmtMjCtdSWXD5BpQ,12495
23
23
  prediction_market_agent_tooling/deploy/constants.py,sha256=M5ty8URipYMGe_G-RzxRydK3AFL6CyvmqCraJUrLBnE,82
24
24
  prediction_market_agent_tooling/deploy/gcp/deploy.py,sha256=CYUgnfy-9XVk04kkxA_5yp0GE9Mw5caYqlFUZQ2j3ks,3739
25
25
  prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py,sha256=OsPboCFGiZKsvGyntGZHwdqPlLTthITkNF5rJFvGgU8,2582
@@ -28,30 +28,31 @@ prediction_market_agent_tooling/gtypes.py,sha256=tqp03PyY0Yhievl4XELfwAn0xOoecaT
28
28
  prediction_market_agent_tooling/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  prediction_market_agent_tooling/jobs/jobs.py,sha256=I07yh0GJ-xhlvQaOUQB8xlSnihhcbU2c7DZ4ZND14c0,1246
30
30
  prediction_market_agent_tooling/jobs/jobs_models.py,sha256=I5uBTHJ2S1Wi3H4jDxxU7nsswSIP9r3BevHmljLh5Pg,1370
31
- prediction_market_agent_tooling/jobs/omen/omen_jobs.py,sha256=TdQHFI8DTnCvZBhzpN-lJY2ozbmYg6xPCtZpHrGDjk0,3987
31
+ prediction_market_agent_tooling/jobs/omen/omen_jobs.py,sha256=I2_vGrEJj1reSI8M377ab5QCsYNp_l4l4QeYEmDBkFM,3989
32
32
  prediction_market_agent_tooling/loggers.py,sha256=Am6HHXRNO545BO3l7Ue9Wb2TkYE1OK8KKhGbI3XypVU,3751
33
- prediction_market_agent_tooling/markets/agent_market.py,sha256=olfZ1S4T5Dut_072rsXreZpPAP4jctd5f50XpsKQtkk,10304
33
+ prediction_market_agent_tooling/markets/agent_market.py,sha256=09Guz5y5Uq0K8nKFmy8SqxNfCYJX3auyxWLzIuOek2I,11119
34
34
  prediction_market_agent_tooling/markets/categorize.py,sha256=jsoHWvZk9pU6n17oWSCcCxNNYVwlb_NXsZxKRI7vmsk,1301
35
35
  prediction_market_agent_tooling/markets/data_models.py,sha256=jMqrSFO_w2z-5N3PFVgZqTHdVdkzSDhhzky2lHsGGKA,3621
36
36
  prediction_market_agent_tooling/markets/manifold/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  prediction_market_agent_tooling/markets/manifold/api.py,sha256=Fd0HYnstvvHO6AZkp1xiRlvCwQUc8kLR8DAj6PAZu0s,7297
38
38
  prediction_market_agent_tooling/markets/manifold/data_models.py,sha256=ylXIEHymx2RcCdOVUpKP4BcTqbzLu_Fd5gV1TGBntVk,6099
39
- prediction_market_agent_tooling/markets/manifold/manifold.py,sha256=JEEIPz9-U3avWggciyNFzUVCpybGCcvGPwcJmNY0HqM,4491
39
+ prediction_market_agent_tooling/markets/manifold/manifold.py,sha256=IeVS3Suifryym-aLFDNEyyhdT3Gg03l4O39-PDpXmE8,4895
40
40
  prediction_market_agent_tooling/markets/manifold/utils.py,sha256=cPPFWXm3vCYH1jy7_ctJZuQH9ZDaPL4_AgAYzGWkoow,513
41
+ prediction_market_agent_tooling/markets/market_fees.py,sha256=Q64T9uaJx0Vllt0BkrPmpMEz53ra-hMVY8Czi7CEP7s,1227
41
42
  prediction_market_agent_tooling/markets/markets.py,sha256=_3nV9QTT48G2oJ2egkuWA1UzrTOGY6x3mXqIRgDaVIo,3245
42
43
  prediction_market_agent_tooling/markets/metaculus/api.py,sha256=4TRPGytQQbSdf42DCg2M_JWYPAuNjqZ3eBqaQBLkNks,2736
43
44
  prediction_market_agent_tooling/markets/metaculus/data_models.py,sha256=2wDZ0BmK9O5Lud-q-FCzgW0tsK9GxMU0rUMlcPxSS04,3184
44
- prediction_market_agent_tooling/markets/metaculus/metaculus.py,sha256=ctRcGm1G8qmUB5RMPoQ_C_GN3Ct24BWDB1gJyOhH_vE,3604
45
+ prediction_market_agent_tooling/markets/metaculus/metaculus.py,sha256=d5tHhekLfPGO6CfmWWJQWpJu5HyoAWBM2aGSR874Cms,3695
45
46
  prediction_market_agent_tooling/markets/omen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
47
  prediction_market_agent_tooling/markets/omen/data_models.py,sha256=nCjsc-ylIzQOCK_1BW-5NoYrS-NIXz2Hg9N1-IqhhC8,27516
47
- prediction_market_agent_tooling/markets/omen/omen.py,sha256=6tBhn7qxtsdrk0xgDSqWy44f_m1qmhfXjvQUWXtW3TI,47974
48
- prediction_market_agent_tooling/markets/omen/omen_contracts.py,sha256=w_ClGd8U4w2pKH3HLZqy2bAFkqZMSAhVgGFGlUqET6Y,28266
48
+ prediction_market_agent_tooling/markets/omen/omen.py,sha256=3BF3oH78K_puwGktLkkOIxsa3G61Jb2zx6LZ_kjr3Hk,48638
49
+ prediction_market_agent_tooling/markets/omen/omen_contracts.py,sha256=Zq7SncCq-hvpgXKsVruGBGCn1OhKZTe7r1qLdCTrT2w,28297
49
50
  prediction_market_agent_tooling/markets/omen/omen_resolving.py,sha256=iDWdjICGkt968exwCjY-6nsnQyrrNAg3YjnDdP430GQ,9415
50
- prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py,sha256=jUucS9RjVi3MDQjnHDXeTgVCcux838Ods1DAsz7txAs,36767
51
+ prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py,sha256=zQH3iu0SVH1RmE-W3NMEpcKVMILXJYxMhL6w1wh5RUo,37348
51
52
  prediction_market_agent_tooling/markets/polymarket/api.py,sha256=UZ4_TG8ceb9Y-qgsOKs8Qiv8zDt957QkT8IX2c83yqo,4800
52
53
  prediction_market_agent_tooling/markets/polymarket/data_models.py,sha256=Fd5PI5y3mJM8VHExBhWFWEnuuIKxQmIAXgBuoPDvNjw,4341
53
54
  prediction_market_agent_tooling/markets/polymarket/data_models_web.py,sha256=VZhVccTApygSKMmy6Au2G02JCJOKJnR_oVeKlaesuSg,12548
54
- prediction_market_agent_tooling/markets/polymarket/polymarket.py,sha256=CE5h74VVwYb9FiLugfLozZZAolWAE-zB5jk9k7-xpqw,2814
55
+ prediction_market_agent_tooling/markets/polymarket/polymarket.py,sha256=NRoZK71PtH8kkangMqme7twcAXhRJSSabbmOir-UnAI,3418
55
56
  prediction_market_agent_tooling/markets/polymarket/utils.py,sha256=m4JG6WULh5epCJt4XBMHg0ae5NoVhqlOvAl0A7DR9iM,2023
56
57
  prediction_market_agent_tooling/monitor/markets/manifold.py,sha256=TS4ERwTfQnot8dhekNyVNhJYf5ysYsjF-9v5_kM3aVI,3334
57
58
  prediction_market_agent_tooling/monitor/markets/metaculus.py,sha256=LOnyWWBFdg10-cTWdb76nOsNjDloO8OfMT85GBzRCFI,1455
@@ -62,8 +63,8 @@ prediction_market_agent_tooling/monitor/monitor_app.py,sha256=zNHSwH_KEiv8aOwvfo
62
63
  prediction_market_agent_tooling/monitor/monitor_settings.py,sha256=Xiozs3AsufuJ04JOe1vjUri-IAMWHjjmc2ugGGiHNH4,947
63
64
  prediction_market_agent_tooling/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
65
  prediction_market_agent_tooling/tools/balances.py,sha256=nR8_dSfbm3yTOOmMAwhGlurftEiNo1w1WIVzbskjdmM,837
65
- prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py,sha256=a_0VmjfQIVU2rrQjAcnWRl_WSYTqeq-7Wj35zUgpokY,4464
66
- prediction_market_agent_tooling/tools/betting_strategies/market_moving.py,sha256=pCS0ISf6SgdhNx_t-h8_aHsLffnQ7kaLXVPPM7rGKJY,5163
66
+ prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py,sha256=TKVF8qZhxgz-4TTEHr7iVLfpurIhuji38qLc8CYaiXA,4662
67
+ prediction_market_agent_tooling/tools/betting_strategies/market_moving.py,sha256=J63kFdDlTHLjWwHE5pDp1fArWpuU6hNNFVpGLE1aRYw,5269
67
68
  prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py,sha256=-FUSuQQgjcWSSnoFxnlAyTeilY6raJABJVM2QKkFqAY,438
68
69
  prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py,sha256=THMXwFlskvzbjnX_OiYtDSzI8XVFyULWfP2525_9UGc,429
69
70
  prediction_market_agent_tooling/tools/betting_strategies/utils.py,sha256=kpIb-ci67Vc1Yqqaa-_S4OUkbhWSIYog4_Iwp69HU_k,97
@@ -81,18 +82,19 @@ prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py,sha256=CTTMfTvs_8PH4k
81
82
  prediction_market_agent_tooling/tools/is_invalid.py,sha256=Lc5fWB4fmx7tFvRakmUOzo0Oq5EizorddZ2xjesEopY,4984
82
83
  prediction_market_agent_tooling/tools/is_predictable.py,sha256=NIoR2bTNMmADcyNY2aKNMWkiDw7Z_9kZMcFXEdyewy4,6771
83
84
  prediction_market_agent_tooling/tools/langfuse_.py,sha256=jI_4ROxqo41CCnWGS1vN_AeDVhRzLMaQLxH3kxDu3L8,1153
84
- prediction_market_agent_tooling/tools/langfuse_client_utils.py,sha256=7H9EzTA_q5TmuqoIeMpdVU2efF_RyttQEoTPLyS-ld4,5579
85
+ prediction_market_agent_tooling/tools/langfuse_client_utils.py,sha256=B0PhAQyviFnVbtOCYMxYmcCn66cu9nbqAOIAZcdgiRI,5771
85
86
  prediction_market_agent_tooling/tools/omen/reality_accuracy.py,sha256=M1SF7iSW1gVlQSTskdVFTn09uPLST23YeipVIWj54io,2236
86
87
  prediction_market_agent_tooling/tools/parallelism.py,sha256=6Gou0hbjtMZrYvxjTDFUDZuxmE2nqZVbb6hkg1hF82A,1022
87
88
  prediction_market_agent_tooling/tools/safe.py,sha256=h0xOO0eNtitClf0fPkn-0oTc6A_bflDTee98V_aiV-A,5195
88
89
  prediction_market_agent_tooling/tools/singleton.py,sha256=CiIELUiI-OeS7U7eeHEt0rnVhtQGzwoUdAgn_7u_GBM,729
89
90
  prediction_market_agent_tooling/tools/streamlit_user_login.py,sha256=NXEqfjT9Lc9QtliwSGRASIz1opjQ7Btme43H4qJbzgE,3010
90
- prediction_market_agent_tooling/tools/tavily_storage/tavily_models.py,sha256=99S7w8BvnJRMOnUArGN0g4GVRoG8M0C-XyIFU8HnLn0,6374
91
- prediction_market_agent_tooling/tools/tavily_storage/tavily_storage.py,sha256=xrtQH9v5pXycBRyc5j45pWqkSffkoc9efNIU1_G633Q,3706
92
- prediction_market_agent_tooling/tools/utils.py,sha256=PGmh-9aeEJe_YcHVIiHMLybx31ppng7tVBlMaIfnWy8,7135
91
+ prediction_market_agent_tooling/tools/tavily/tavily_models.py,sha256=Rz4tZzwCRzPaq49SFT33SCRQrqHXtqWdD9ajb2tGCWc,2723
92
+ prediction_market_agent_tooling/tools/tavily/tavily_search.py,sha256=MK_ozeQbJ014HGiKFPDScjFYq0OGcjY1KPgc9A6qO0M,4511
93
+ prediction_market_agent_tooling/tools/tavily/tavily_storage.py,sha256=t-tZzbCzBBdFedRZDuVBn3A3mIDX8Z5wza6SxWswu_E,4093
94
+ prediction_market_agent_tooling/tools/utils.py,sha256=W-9SqeCKd51BYMRhDjYPQ7lfNO_zE9EvYpmu2r5WXGA,7163
93
95
  prediction_market_agent_tooling/tools/web3_utils.py,sha256=dkcjG-LtuaWRh7WEMzRGmZ5B5rsxZTlliFOI6fj-EJ8,11842
94
- prediction_market_agent_tooling-0.52.1.dist-info/LICENSE,sha256=6or154nLLU6bELzjh0mCreFjt0m2v72zLi3yHE0QbeE,7650
95
- prediction_market_agent_tooling-0.52.1.dist-info/METADATA,sha256=fpI3KeGxWxrgDgZF056WOtj6kmMxnwbrkN_ZDu3bi7I,8056
96
- prediction_market_agent_tooling-0.52.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
97
- prediction_market_agent_tooling-0.52.1.dist-info/entry_points.txt,sha256=m8PukHbeH5g0IAAmOf_1Ahm-sGAMdhSSRQmwtpmi2s8,81
98
- prediction_market_agent_tooling-0.52.1.dist-info/RECORD,,
96
+ prediction_market_agent_tooling-0.53.0.dist-info/LICENSE,sha256=6or154nLLU6bELzjh0mCreFjt0m2v72zLi3yHE0QbeE,7650
97
+ prediction_market_agent_tooling-0.53.0.dist-info/METADATA,sha256=RrGcyPVn2Gs6Xx9ezoDYzqUMAQfDZVlT63_Uq22GjSc,8056
98
+ prediction_market_agent_tooling-0.53.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
99
+ prediction_market_agent_tooling-0.53.0.dist-info/entry_points.txt,sha256=m8PukHbeH5g0IAAmOf_1Ahm-sGAMdhSSRQmwtpmi2s8,81
100
+ prediction_market_agent_tooling-0.53.0.dist-info/RECORD,,