prediction-market-agent-tooling 0.14.1__py3-none-any.whl → 0.15.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 (28) hide show
  1. prediction_market_agent_tooling/abis/erc20.abi.json +315 -0
  2. prediction_market_agent_tooling/benchmark/agents.py +7 -1
  3. prediction_market_agent_tooling/benchmark/benchmark.py +22 -24
  4. prediction_market_agent_tooling/config.py +27 -4
  5. prediction_market_agent_tooling/deploy/agent.py +3 -3
  6. prediction_market_agent_tooling/markets/agent_market.py +20 -9
  7. prediction_market_agent_tooling/markets/manifold/manifold.py +9 -1
  8. prediction_market_agent_tooling/markets/omen/data_models.py +42 -11
  9. prediction_market_agent_tooling/markets/omen/omen.py +135 -52
  10. prediction_market_agent_tooling/markets/omen/omen_contracts.py +36 -34
  11. prediction_market_agent_tooling/markets/omen/omen_replicate.py +11 -16
  12. prediction_market_agent_tooling/markets/omen/omen_resolve_replicated.py +32 -25
  13. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +46 -13
  14. prediction_market_agent_tooling/markets/polymarket/polymarket.py +1 -1
  15. prediction_market_agent_tooling/monitor/markets/omen.py +5 -3
  16. prediction_market_agent_tooling/monitor/markets/polymarket.py +3 -2
  17. prediction_market_agent_tooling/monitor/monitor.py +26 -20
  18. prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +1 -1
  19. prediction_market_agent_tooling/tools/contract.py +32 -17
  20. prediction_market_agent_tooling/tools/costs.py +31 -0
  21. prediction_market_agent_tooling/tools/parallelism.py +16 -1
  22. prediction_market_agent_tooling/tools/safe.py +130 -0
  23. prediction_market_agent_tooling/tools/web3_utils.py +100 -15
  24. {prediction_market_agent_tooling-0.14.1.dist-info → prediction_market_agent_tooling-0.15.0.dist-info}/METADATA +13 -1
  25. {prediction_market_agent_tooling-0.14.1.dist-info → prediction_market_agent_tooling-0.15.0.dist-info}/RECORD +28 -25
  26. {prediction_market_agent_tooling-0.14.1.dist-info → prediction_market_agent_tooling-0.15.0.dist-info}/LICENSE +0 -0
  27. {prediction_market_agent_tooling-0.14.1.dist-info → prediction_market_agent_tooling-0.15.0.dist-info}/WHEEL +0 -0
  28. {prediction_market_agent_tooling-0.14.1.dist-info → prediction_market_agent_tooling-0.15.0.dist-info}/entry_points.txt +0 -0
@@ -21,7 +21,10 @@ from prediction_market_agent_tooling.markets.data_models import (
21
21
  Resolution,
22
22
  ResolvedBet,
23
23
  )
24
- from prediction_market_agent_tooling.tools.utils import check_not_none
24
+ from prediction_market_agent_tooling.tools.utils import (
25
+ check_not_none,
26
+ should_not_happen,
27
+ )
25
28
  from prediction_market_agent_tooling.tools.web3_utils import wei_to_xdai
26
29
 
27
30
  OMEN_TRUE_OUTCOME = "Yes"
@@ -154,6 +157,8 @@ class OmenMarket(BaseModel):
154
157
  creationTimestamp: int
155
158
  condition: Condition
156
159
  question: Question
160
+ lastActiveDay: int
161
+ lastActiveHour: int
157
162
 
158
163
  @property
159
164
  def openingTimestamp(self) -> int:
@@ -241,11 +246,19 @@ class OmenMarket(BaseModel):
241
246
  )
242
247
 
243
248
  @property
244
- def p_no(self) -> Probability:
245
- return Probability(1 - self.p_yes)
249
+ def yes_index(self) -> int:
250
+ return self.outcomes.index(OMEN_TRUE_OUTCOME)
251
+
252
+ @property
253
+ def no_index(self) -> int:
254
+ return self.outcomes.index(OMEN_FALSE_OUTCOME)
246
255
 
247
256
  @property
248
- def p_yes(self) -> Probability:
257
+ def current_p_no(self) -> Probability:
258
+ return Probability(1 - self.current_p_yes)
259
+
260
+ @property
261
+ def current_p_yes(self) -> Probability:
249
262
  """
250
263
  Calculate the probability of the outcomes from the relative token amounts.
251
264
 
@@ -257,21 +270,29 @@ class OmenMarket(BaseModel):
257
270
  the the lower the price of that token, and therefore the lower the
258
271
  probability of that outcome.
259
272
  """
260
- if self.outcomeTokenAmounts is None:
261
- raise ValueError(
262
- f"Market with title {self.title} has no outcomeTokenAmounts."
263
- )
264
273
  if len(self.outcomeTokenAmounts) != 2:
265
274
  raise ValueError(
266
275
  f"Market with title {self.title} has {len(self.outcomeTokenAmounts)} outcomes."
267
276
  )
268
- true_index = self.outcomes.index(OMEN_TRUE_OUTCOME)
269
277
 
270
278
  if sum(self.outcomeTokenAmounts) == 0:
271
- return Probability(0.5)
279
+ # If there are no outcome tokens, it should mean that market is closed and without liquidity, so we need to infer the probabilities based on the answer.
280
+ return (
281
+ Probability(1.0)
282
+ if self.yes_index == self.answer_index
283
+ else (
284
+ Probability(0.0)
285
+ if self.no_index == self.answer_index
286
+ else (
287
+ Probability(0.5)
288
+ if not self.has_valid_answer # Invalid market or closed market without resolution.
289
+ else should_not_happen("Unknown condition.")
290
+ )
291
+ )
292
+ )
272
293
 
273
294
  return Probability(
274
- 1 - self.outcomeTokenAmounts[true_index] / sum(self.outcomeTokenAmounts)
295
+ 1 - self.outcomeTokenAmounts[self.yes_index] / sum(self.outcomeTokenAmounts)
275
296
  )
276
297
 
277
298
  def __repr__(self) -> str:
@@ -335,6 +356,16 @@ class OmenBet(BaseModel):
335
356
  def boolean_outcome(self) -> bool:
336
357
  return get_boolean_outcome(self.fpmm.outcomes[self.outcomeIndex])
337
358
 
359
+ @property
360
+ def old_probability(self) -> Probability:
361
+ # Old marginal price is the probability of the outcome before placing this bet.
362
+ return Probability(float(self.oldOutcomeTokenMarginalPrice))
363
+
364
+ @property
365
+ def probability(self) -> Probability:
366
+ # Marginal price is the probability of the outcome after placing this bet.
367
+ return Probability(float(self.outcomeTokenMarginalPrice))
368
+
338
369
  def get_profit(self) -> ProfitAmount:
339
370
  bet_amount_xdai = wei_to_xdai(self.collateralAmount)
340
371
  profit = (
@@ -6,13 +6,13 @@ from loguru import logger
6
6
  from web3 import Web3
7
7
  from web3.constants import HASH_ZERO
8
8
 
9
- from prediction_market_agent_tooling.config import APIKeys
9
+ from prediction_market_agent_tooling.config import APIKeys, PrivateCredentials
10
10
  from prediction_market_agent_tooling.gtypes import (
11
11
  ChecksumAddress,
12
12
  HexAddress,
13
13
  HexStr,
14
14
  OutcomeStr,
15
- PrivateKey,
15
+ Probability,
16
16
  Wei,
17
17
  wei_type,
18
18
  xDai,
@@ -56,7 +56,6 @@ from prediction_market_agent_tooling.tools.hexbytes_custom import HexBytes
56
56
  from prediction_market_agent_tooling.tools.utils import check_not_none
57
57
  from prediction_market_agent_tooling.tools.web3_utils import (
58
58
  add_fraction,
59
- private_key_to_public_key,
60
59
  remove_fraction,
61
60
  wei_to_xdai,
62
61
  xdai_to_wei,
@@ -85,6 +84,38 @@ class OmenAgentMarket(AgentMarket):
85
84
  "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
86
85
  )
87
86
 
87
+ _binary_market_p_yes_history: list[Probability] | None = None
88
+
89
+ @property
90
+ def yes_index(self) -> int:
91
+ return self.outcomes.index(OMEN_TRUE_OUTCOME)
92
+
93
+ @property
94
+ def no_index(self) -> int:
95
+ return self.outcomes.index(OMEN_FALSE_OUTCOME)
96
+
97
+ def get_p_yes_history_cached(self) -> list[Probability]:
98
+ if self._binary_market_p_yes_history is None:
99
+ self._binary_market_p_yes_history = get_binary_market_p_yes_history(self)
100
+ return self._binary_market_p_yes_history
101
+
102
+ def get_last_trade_p_yes(self) -> Probability | None:
103
+ """On Omen, probablities converge after the resolution, so we need to get market's predicted probability from the trade history."""
104
+ return (
105
+ self.get_p_yes_history_cached()[-1]
106
+ if self.get_p_yes_history_cached()
107
+ else None
108
+ )
109
+
110
+ def get_last_trade_p_no(self) -> Probability | None:
111
+ """On Omen, probablities converge after the resolution, so we need to get market's predicted probability from the trade history."""
112
+ last_trade_p_yes = self.get_last_trade_p_yes()
113
+ return (
114
+ Probability(1.0 - last_trade_p_yes)
115
+ if last_trade_p_yes is not None
116
+ else None
117
+ )
118
+
88
119
  def get_liquidity(self) -> Wei:
89
120
  return self.get_contract().totalSupply()
90
121
 
@@ -95,27 +126,34 @@ class OmenAgentMarket(AgentMarket):
95
126
  return BetAmount(amount=0.00001, currency=self.currency)
96
127
 
97
128
  def place_bet(
98
- self, outcome: bool, amount: BetAmount, omen_auto_deposit: bool = True
129
+ self,
130
+ outcome: bool,
131
+ amount: BetAmount,
132
+ omen_auto_deposit: bool = True,
133
+ web3: Web3 | None = None,
99
134
  ) -> None:
100
135
  if amount.currency != self.currency:
101
136
  raise ValueError(f"Omen bets are made in xDai. Got {amount.currency}.")
102
137
  amount_xdai = xDai(amount.amount)
103
138
  keys = APIKeys()
139
+ private_credentials = PrivateCredentials.from_api_keys(keys)
104
140
  binary_omen_buy_outcome_tx(
141
+ private_credentials=private_credentials,
105
142
  amount=amount_xdai,
106
- from_private_key=keys.bet_from_private_key,
107
143
  market=self,
108
144
  binary_outcome=outcome,
109
145
  auto_deposit=omen_auto_deposit,
146
+ web3=web3,
110
147
  )
111
148
 
112
149
  def sell_tokens(
113
150
  self, outcome: bool, amount: TokenAmount, auto_withdraw: bool = True
114
151
  ) -> None:
115
152
  keys = APIKeys()
153
+ private_credentials = PrivateCredentials.from_api_keys(keys)
116
154
  binary_omen_sell_outcome_tx(
155
+ private_credentials=private_credentials,
117
156
  amount=xDai(amount.amount),
118
- from_private_key=keys.bet_from_private_key,
119
157
  market=self,
120
158
  binary_outcome=outcome,
121
159
  auto_withdraw=auto_withdraw,
@@ -165,8 +203,11 @@ class OmenAgentMarket(AgentMarket):
165
203
  )
166
204
  return len(user_positions) > 0
167
205
 
168
- def redeem_positions(self, for_private_key: PrivateKey) -> None:
169
- for_public_key = private_key_to_public_key(for_private_key)
206
+ def redeem_positions(
207
+ self,
208
+ private_credentials: PrivateCredentials,
209
+ ) -> None:
210
+ for_public_key = private_credentials.public_key
170
211
  market_is_redeemable = self.market_redeemable_by(user=for_public_key)
171
212
  if not market_is_redeemable:
172
213
  logger.debug(
@@ -174,7 +215,9 @@ class OmenAgentMarket(AgentMarket):
174
215
  )
175
216
  return None
176
217
 
177
- omen_redeem_full_position_tx(market=self, from_private_key=for_private_key)
218
+ omen_redeem_full_position_tx(
219
+ private_credentials=private_credentials, market=self
220
+ )
178
221
 
179
222
  @staticmethod
180
223
  def from_data_model(model: OmenMarket) -> "OmenAgentMarket":
@@ -188,7 +231,7 @@ class OmenAgentMarket(AgentMarket):
188
231
  resolution=model.get_resolution_enum(),
189
232
  created_time=model.creation_datetime,
190
233
  finalized_time=model.finalized_datetime,
191
- p_yes=model.p_yes,
234
+ current_p_yes=model.current_p_yes,
192
235
  condition=model.condition,
193
236
  url=model.url,
194
237
  volume=wei_to_xdai(model.collateralVolume),
@@ -222,9 +265,11 @@ class OmenAgentMarket(AgentMarket):
222
265
  )
223
266
  )
224
267
 
225
- def get_contract(self) -> OmenFixedProductMarketMakerContract:
268
+ def get_contract(
269
+ self,
270
+ ) -> OmenFixedProductMarketMakerContract:
226
271
  return OmenFixedProductMarketMakerContract(
227
- address=self.market_maker_contract_address_checksummed
272
+ address=self.market_maker_contract_address_checksummed,
228
273
  )
229
274
 
230
275
  def get_index_set(self, outcome: str) -> int:
@@ -238,10 +283,12 @@ class OmenAgentMarket(AgentMarket):
238
283
  cls.get_outcome_str(cls.index_set_to_outcome_index(index_set))
239
284
  )
240
285
 
241
- def get_token_balance(self, user_id: str, outcome: str) -> TokenAmount:
286
+ def get_token_balance(
287
+ self, user_id: str, outcome: str, web3: Web3 | None = None
288
+ ) -> TokenAmount:
242
289
  index_set = self.get_index_set(outcome)
243
290
  balances = get_conditional_tokens_balance_for_market(
244
- self, Web3.to_checksum_address(user_id)
291
+ self, Web3.to_checksum_address(user_id), web3=web3
245
292
  )
246
293
  return TokenAmount(
247
294
  amount=wei_to_xdai(balances[index_set]),
@@ -309,72 +356,79 @@ def pick_binary_market(
309
356
 
310
357
 
311
358
  def omen_buy_outcome_tx(
359
+ private_credentials: PrivateCredentials,
312
360
  amount: xDai,
313
- from_private_key: PrivateKey,
314
361
  market: OmenAgentMarket,
315
362
  outcome: str,
316
363
  auto_deposit: bool,
364
+ web3: Web3 | None = None,
317
365
  ) -> None:
318
366
  """
319
367
  Bets the given amount of xDai for the given outcome in the given market.
320
368
  """
321
369
  amount_wei = xdai_to_wei(amount)
322
- from_address_checksummed = private_key_to_public_key(from_private_key)
370
+ from_address_checksummed = private_credentials.public_key
323
371
 
324
372
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
373
+
325
374
  collateral_token_contract = OmenCollateralTokenContract()
326
375
 
327
376
  # Get the index of the outcome we want to buy.
328
377
  outcome_index: int = market.get_outcome_index(outcome)
329
378
 
330
379
  # Calculate the amount of shares we will get for the given investment amount.
331
- expected_shares = market_contract.calcBuyAmount(amount_wei, outcome_index)
380
+ expected_shares = market_contract.calcBuyAmount(
381
+ amount_wei, outcome_index, web3=web3
382
+ )
332
383
  # Allow 1% slippage.
333
384
  expected_shares = remove_fraction(expected_shares, 0.01)
334
385
  # Approve the market maker to withdraw our collateral token.
335
386
  collateral_token_contract.approve(
387
+ private_credentials=private_credentials,
336
388
  for_address=market_contract.address,
337
389
  amount_wei=amount_wei,
338
- from_private_key=from_private_key,
390
+ web3=web3,
339
391
  )
340
392
  # Deposit xDai to the collateral token,
341
393
  # this can be skipped, if we know we already have enough collateral tokens.
342
394
  collateral_token_balance = collateral_token_contract.balanceOf(
343
- for_address=from_address_checksummed,
395
+ for_address=from_address_checksummed, web3=web3
344
396
  )
345
397
  if auto_deposit and collateral_token_balance < amount_wei:
346
398
  collateral_token_contract.deposit(
347
- amount_wei=amount_wei,
348
- from_private_key=from_private_key,
399
+ private_credentials=private_credentials, amount_wei=amount_wei, web3=web3
349
400
  )
350
401
  # Buy shares using the deposited xDai in the collateral token.
351
402
  market_contract.buy(
403
+ private_credentials=private_credentials,
352
404
  amount_wei=amount_wei,
353
405
  outcome_index=outcome_index,
354
406
  min_outcome_tokens_to_buy=expected_shares,
355
- from_private_key=from_private_key,
407
+ web3=web3,
356
408
  )
357
409
 
358
410
 
359
411
  def binary_omen_buy_outcome_tx(
412
+ private_credentials: PrivateCredentials,
360
413
  amount: xDai,
361
- from_private_key: PrivateKey,
362
414
  market: OmenAgentMarket,
363
415
  binary_outcome: bool,
364
416
  auto_deposit: bool,
417
+ web3: Web3 | None = None,
365
418
  ) -> None:
366
419
  omen_buy_outcome_tx(
420
+ private_credentials=private_credentials,
367
421
  amount=amount,
368
- from_private_key=from_private_key,
369
422
  market=market,
370
423
  outcome=OMEN_TRUE_OUTCOME if binary_outcome else OMEN_FALSE_OUTCOME,
371
424
  auto_deposit=auto_deposit,
425
+ web3=web3,
372
426
  )
373
427
 
374
428
 
375
429
  def omen_sell_outcome_tx(
430
+ private_credentials: PrivateCredentials,
376
431
  amount: xDai, # The xDai value of shares to sell.
377
- from_private_key: PrivateKey,
378
432
  market: OmenAgentMarket,
379
433
  outcome: str,
380
434
  auto_withdraw: bool,
@@ -410,35 +464,35 @@ def omen_sell_outcome_tx(
410
464
 
411
465
  # Approve the market maker to move our (all) conditional tokens.
412
466
  conditional_token_contract.setApprovalForAll(
467
+ private_credentials=private_credentials,
413
468
  for_address=market_contract.address,
414
469
  approve=True,
415
- from_private_key=from_private_key,
416
470
  )
417
471
  # Sell the shares.
418
472
  market_contract.sell(
473
+ private_credentials,
419
474
  amount_wei,
420
475
  outcome_index,
421
476
  max_outcome_tokens_to_sell,
422
- from_private_key,
423
477
  )
424
478
  if auto_withdraw:
425
479
  # Optionally, withdraw from the collateral token back to the `from_address` wallet.
426
480
  collateral_token.withdraw(
481
+ private_credentials=private_credentials,
427
482
  amount_wei=amount_wei,
428
- from_private_key=from_private_key,
429
483
  )
430
484
 
431
485
 
432
486
  def binary_omen_sell_outcome_tx(
487
+ private_credentials: PrivateCredentials,
433
488
  amount: xDai,
434
- from_private_key: PrivateKey,
435
489
  market: OmenAgentMarket,
436
490
  binary_outcome: bool,
437
491
  auto_withdraw: bool,
438
492
  ) -> None:
439
493
  omen_sell_outcome_tx(
494
+ private_credentials=private_credentials,
440
495
  amount=amount,
441
- from_private_key=from_private_key,
442
496
  market=market,
443
497
  outcome=OMEN_TRUE_OUTCOME if binary_outcome else OMEN_FALSE_OUTCOME,
444
498
  auto_withdraw=auto_withdraw,
@@ -446,12 +500,12 @@ def binary_omen_sell_outcome_tx(
446
500
 
447
501
 
448
502
  def omen_create_market_tx(
503
+ private_credentials: PrivateCredentials,
449
504
  initial_funds: xDai,
450
505
  question: str,
451
506
  closing_time: datetime,
452
507
  category: str,
453
508
  language: str,
454
- from_private_key: PrivateKey,
455
509
  outcomes: list[str],
456
510
  auto_deposit: bool,
457
511
  fee: float = OMEN_DEFAULT_MARKET_FEE,
@@ -459,7 +513,7 @@ def omen_create_market_tx(
459
513
  """
460
514
  Based on omen-exchange TypeScript code: https://github.com/protofire/omen-exchange/blob/b0b9a3e71b415d6becf21fe428e1c4fc0dad2e80/app/src/services/cpk/cpk.ts#L308
461
515
  """
462
- from_address = private_key_to_public_key(from_private_key)
516
+ from_address = private_credentials.public_key
463
517
  initial_funds_wei = xdai_to_wei(initial_funds)
464
518
 
465
519
  realitio_contract = OmenRealitioContract()
@@ -482,9 +536,9 @@ def omen_create_market_tx(
482
536
 
483
537
  # Approve the market maker to withdraw our collateral token.
484
538
  collateral_token_contract.approve(
539
+ private_credentials=private_credentials,
485
540
  for_address=factory_contract.address,
486
541
  amount_wei=initial_funds_wei,
487
- from_private_key=from_private_key,
488
542
  )
489
543
 
490
544
  # Deposit xDai to the collateral token,
@@ -497,17 +551,17 @@ def omen_create_market_tx(
497
551
  and initial_funds_wei > 0
498
552
  and collateral_token_balance < initial_funds_wei
499
553
  ):
500
- collateral_token_contract.deposit(initial_funds_wei, from_private_key)
554
+ collateral_token_contract.deposit(private_credentials, initial_funds_wei)
501
555
 
502
556
  # Create the question on Realitio.
503
557
  question_id = realitio_contract.askQuestion(
558
+ private_credentials=private_credentials,
504
559
  question=question,
505
560
  category=category,
506
561
  outcomes=outcomes,
507
562
  language=language,
508
563
  arbitrator=Arbitrator.KLEROS,
509
564
  opening=closing_time, # The question is opened at the closing time of the market.
510
- from_private_key=from_private_key,
511
565
  )
512
566
 
513
567
  # Construct the condition id.
@@ -518,15 +572,15 @@ def omen_create_market_tx(
518
572
  )
519
573
  if not conditional_token_contract.does_condition_exists(condition_id):
520
574
  conditional_token_contract.prepareCondition(
575
+ private_credentials=private_credentials,
521
576
  question_id=question_id,
522
577
  oracle_address=oracle_contract.address,
523
578
  outcomes_slot_count=len(outcomes),
524
- from_private_key=from_private_key,
525
579
  )
526
580
 
527
581
  # Create the market.
528
582
  create_market_receipt_tx = factory_contract.create2FixedProductMarketMaker(
529
- from_private_key=from_private_key,
583
+ private_credentials=private_credentials,
530
584
  condition_id=condition_id,
531
585
  fee=fee,
532
586
  initial_funds_wei=initial_funds_wei,
@@ -544,12 +598,12 @@ def omen_create_market_tx(
544
598
 
545
599
 
546
600
  def omen_fund_market_tx(
601
+ private_credentials: PrivateCredentials,
547
602
  market: OmenAgentMarket,
548
603
  funds: Wei,
549
- from_private_key: PrivateKey,
550
604
  auto_deposit: bool,
551
605
  ) -> None:
552
- from_address = private_key_to_public_key(from_private_key)
606
+ from_address = private_credentials.public_key
553
607
  market_contract = market.get_contract()
554
608
  collateral_token_contract = OmenCollateralTokenContract()
555
609
 
@@ -562,15 +616,15 @@ def omen_fund_market_tx(
562
616
  )
563
617
  < funds
564
618
  ):
565
- collateral_token_contract.deposit(funds, from_private_key)
619
+ collateral_token_contract.deposit(private_credentials, funds)
566
620
 
567
621
  collateral_token_contract.approve(
622
+ private_credentials=private_credentials,
568
623
  for_address=market_contract.address,
569
624
  amount_wei=funds,
570
- from_private_key=from_private_key,
571
625
  )
572
626
 
573
- market_contract.addFunding(funds, from_private_key)
627
+ market_contract.addFunding(private_credentials, funds)
574
628
 
575
629
 
576
630
  def build_parent_collection_id() -> HexStr:
@@ -578,8 +632,8 @@ def build_parent_collection_id() -> HexStr:
578
632
 
579
633
 
580
634
  def omen_redeem_full_position_tx(
635
+ private_credentials: PrivateCredentials,
581
636
  market: OmenAgentMarket,
582
- from_private_key: PrivateKey,
583
637
  web3: Web3 | None = None,
584
638
  ) -> None:
585
639
  """
@@ -587,7 +641,7 @@ def omen_redeem_full_position_tx(
587
641
  to be redeemed before sending the transaction.
588
642
  """
589
643
 
590
- from_address = private_key_to_public_key(from_private_key)
644
+ from_address = private_credentials.public_key
591
645
 
592
646
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
593
647
  conditional_token_contract = OmenConditionalTokenContract()
@@ -617,7 +671,7 @@ def omen_redeem_full_position_tx(
617
671
  return
618
672
 
619
673
  conditional_token_contract.redeemPositions(
620
- from_private_key=from_private_key,
674
+ private_credentials=private_credentials,
621
675
  collateral_token_address=market.collateral_token_contract_address_checksummed,
622
676
  condition_id=market.condition.id,
623
677
  parent_collection_id=parent_collection_id,
@@ -658,9 +712,9 @@ def get_conditional_tokens_balance_for_market(
658
712
 
659
713
 
660
714
  def omen_remove_fund_market_tx(
715
+ private_credentials: PrivateCredentials,
661
716
  market: OmenAgentMarket,
662
717
  shares: Wei | None,
663
- from_private_key: PrivateKey,
664
718
  web3: Web3 | None = None,
665
719
  ) -> None:
666
720
  """
@@ -671,7 +725,7 @@ def omen_remove_fund_market_tx(
671
725
  After we remove funding, using the `mergePositions` we get `min(shares per index)` of wxDai back, but the remaining shares can be converted back only after the market is resolved.
672
726
  That can be done using the `redeem_from_all_user_positions` function below.
673
727
  """
674
- from_address = private_key_to_public_key(from_private_key)
728
+ from_address = private_credentials.public_key
675
729
  market_contract = market.get_contract()
676
730
  original_balances = get_balances(from_address)
677
731
 
@@ -687,7 +741,7 @@ def omen_remove_fund_market_tx(
687
741
  shares = total_shares
688
742
 
689
743
  market_contract.removeFunding(
690
- remove_funding=shares, from_private_key=from_private_key, web3=web3
744
+ private_credentials=private_credentials, remove_funding=shares, web3=web3
691
745
  )
692
746
 
693
747
  conditional_tokens = OmenConditionalTokenContract()
@@ -701,7 +755,7 @@ def omen_remove_fund_market_tx(
701
755
  amount_to_merge = min(amount_per_index_set.values())
702
756
 
703
757
  result = conditional_tokens.mergePositions(
704
- from_private_key=from_private_key,
758
+ private_credentials=private_credentials,
705
759
  collateral_token_address=market.collateral_token_contract_address_checksummed,
706
760
  parent_collection_id=parent_collection_id,
707
761
  conditionId=market.condition.id,
@@ -718,13 +772,13 @@ def omen_remove_fund_market_tx(
718
772
 
719
773
 
720
774
  def redeem_from_all_user_positions(
721
- from_private_key: PrivateKey,
775
+ private_credentials: PrivateCredentials,
722
776
  web3: Web3 | None = None,
723
777
  ) -> None:
724
778
  """
725
779
  Redeems from all user positions where the user didn't redeem yet.
726
780
  """
727
- public_key = private_key_to_public_key(from_private_key)
781
+ public_key = private_credentials.public_key
728
782
 
729
783
  conditional_token_contract = OmenConditionalTokenContract()
730
784
  user_positions = OmenSubgraphHandler().get_user_positions(
@@ -748,7 +802,7 @@ def redeem_from_all_user_positions(
748
802
 
749
803
  original_balances = get_balances(public_key)
750
804
  conditional_token_contract.redeemPositions(
751
- from_private_key=from_private_key,
805
+ private_credentials=private_credentials,
752
806
  collateral_token_address=user_position.position.collateral_token_contract_address_checksummed,
753
807
  condition_id=condition_id,
754
808
  parent_collection_id=build_parent_collection_id(),
@@ -760,3 +814,32 @@ def redeem_from_all_user_positions(
760
814
  logger.info(
761
815
  f"Redeemed {new_balances.wxdai - original_balances.wxdai} wxDai from position {user_position.id=}."
762
816
  )
817
+
818
+
819
+ def get_binary_market_p_yes_history(market: OmenAgentMarket) -> list[Probability]:
820
+ history: list[Probability] = []
821
+ trades = sorted(
822
+ OmenSubgraphHandler().get_trades( # We need to look at price both after buying or selling, so get trades, not bets.
823
+ market_id=market.market_maker_contract_address_checksummed,
824
+ end_time=market.close_time, # Even after market is closed, there can be many `Sell` trades which will converge the probability to the true one.
825
+ ),
826
+ key=lambda x: x.creation_datetime,
827
+ )
828
+
829
+ for index, trade in enumerate(trades):
830
+ # We need to append the old probability to have also the initial state of the market (before any bet placement).
831
+ history.append(
832
+ trade.old_probability
833
+ if trade.outcomeIndex == market.yes_index
834
+ else Probability(1 - trade.old_probability)
835
+ )
836
+
837
+ # At the last trade, we also need to append the new probability, to have the market latest state.
838
+ if index == len(trades) - 1:
839
+ history.append(
840
+ trade.probability
841
+ if trade.outcomeIndex == market.yes_index
842
+ else Probability(1 - trade.probability)
843
+ )
844
+
845
+ return history