prediction-market-agent-tooling 0.61.1.dev489__py3-none-any.whl → 0.62.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.
- prediction_market_agent_tooling/deploy/agent.py +4 -5
- prediction_market_agent_tooling/deploy/betting_strategy.py +53 -69
- prediction_market_agent_tooling/gtypes.py +105 -27
- prediction_market_agent_tooling/jobs/jobs_models.py +5 -7
- prediction_market_agent_tooling/jobs/omen/omen_jobs.py +13 -17
- prediction_market_agent_tooling/markets/agent_market.py +96 -55
- prediction_market_agent_tooling/markets/blockchain_utils.py +2 -32
- prediction_market_agent_tooling/markets/data_models.py +40 -44
- prediction_market_agent_tooling/markets/manifold/api.py +2 -6
- prediction_market_agent_tooling/markets/manifold/data_models.py +33 -25
- prediction_market_agent_tooling/markets/manifold/manifold.py +13 -11
- prediction_market_agent_tooling/markets/market_fees.py +6 -2
- prediction_market_agent_tooling/markets/omen/data_models.py +66 -57
- prediction_market_agent_tooling/markets/omen/omen.py +222 -250
- prediction_market_agent_tooling/markets/omen/omen_contracts.py +32 -33
- prediction_market_agent_tooling/markets/omen/omen_resolving.py +7 -14
- prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +20 -14
- prediction_market_agent_tooling/markets/polymarket/data_models.py +3 -3
- prediction_market_agent_tooling/markets/polymarket/data_models_web.py +4 -4
- prediction_market_agent_tooling/markets/polymarket/polymarket.py +3 -5
- prediction_market_agent_tooling/markets/seer/data_models.py +92 -5
- prediction_market_agent_tooling/markets/seer/seer.py +93 -115
- prediction_market_agent_tooling/markets/seer/seer_contracts.py +11 -6
- prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +18 -26
- prediction_market_agent_tooling/monitor/monitor.py +2 -2
- prediction_market_agent_tooling/tools/_generic_value.py +261 -0
- prediction_market_agent_tooling/tools/balances.py +14 -11
- prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +12 -10
- prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +31 -24
- prediction_market_agent_tooling/tools/betting_strategies/utils.py +3 -1
- prediction_market_agent_tooling/tools/contract.py +14 -10
- prediction_market_agent_tooling/tools/cow/cow_manager.py +3 -4
- prediction_market_agent_tooling/tools/cow/cow_order.py +51 -7
- prediction_market_agent_tooling/tools/langfuse_client_utils.py +13 -1
- prediction_market_agent_tooling/tools/omen/sell_positions.py +6 -3
- prediction_market_agent_tooling/tools/safe.py +5 -6
- prediction_market_agent_tooling/tools/tokens/auto_deposit.py +36 -27
- prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +4 -25
- prediction_market_agent_tooling/tools/tokens/main_token.py +2 -2
- prediction_market_agent_tooling/tools/tokens/token_utils.py +46 -0
- prediction_market_agent_tooling/tools/tokens/usd.py +79 -0
- prediction_market_agent_tooling/tools/utils.py +14 -8
- prediction_market_agent_tooling/tools/web3_utils.py +24 -41
- {prediction_market_agent_tooling-0.61.1.dev489.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/METADATA +2 -1
- {prediction_market_agent_tooling-0.61.1.dev489.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/RECORD +48 -47
- prediction_market_agent_tooling/markets/seer/price_manager.py +0 -111
- prediction_market_agent_tooling/markets/seer/subgraph_data_models.py +0 -57
- {prediction_market_agent_tooling-0.61.1.dev489.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.61.1.dev489.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/WHEEL +0 -0
- {prediction_market_agent_tooling-0.61.1.dev489.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/entry_points.txt +0 -0
@@ -15,12 +15,12 @@ from prediction_market_agent_tooling.gtypes import (
|
|
15
15
|
HexBytes,
|
16
16
|
HexStr,
|
17
17
|
IPFSCIDVersion0,
|
18
|
-
|
18
|
+
OutcomeWei,
|
19
19
|
TxParams,
|
20
20
|
TxReceipt,
|
21
21
|
Wei,
|
22
22
|
int_to_hexbytes,
|
23
|
-
|
23
|
+
xDaiWei,
|
24
24
|
)
|
25
25
|
from prediction_market_agent_tooling.markets.omen.data_models import (
|
26
26
|
INVALID_ANSWER_HEX_BYTES,
|
@@ -128,8 +128,8 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
|
|
128
128
|
|
129
129
|
def balanceOf(
|
130
130
|
self, from_address: ChecksumAddress, position_id: int, web3: Web3 | None = None
|
131
|
-
) ->
|
132
|
-
balance =
|
131
|
+
) -> OutcomeWei:
|
132
|
+
balance = OutcomeWei(
|
133
133
|
self.call("balanceOf", [from_address, position_id], web3=web3)
|
134
134
|
)
|
135
135
|
return balance
|
@@ -169,7 +169,7 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
|
|
169
169
|
collateral_token_address: ChecksumAddress,
|
170
170
|
conditionId: HexBytes,
|
171
171
|
index_sets: t.List[int],
|
172
|
-
amount:
|
172
|
+
amount: OutcomeWei,
|
173
173
|
parent_collection_id: HexStr = build_parent_collection_id(),
|
174
174
|
web3: Web3 | None = None,
|
175
175
|
) -> TxReceipt:
|
@@ -296,28 +296,28 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
|
|
296
296
|
# Factory contract at https://gnosisscan.io/address/0x9083a2b699c0a4ad06f63580bde2635d26a3eef0.
|
297
297
|
|
298
298
|
def balanceOf(self, for_address: ChecksumAddress, web3: Web3 | None = None) -> Wei:
|
299
|
-
balance
|
299
|
+
balance = Wei(self.call("balanceOf", [for_address], web3=web3))
|
300
300
|
return balance
|
301
301
|
|
302
302
|
def calcBuyAmount(
|
303
303
|
self, investment_amount: Wei, outcome_index: int, web3: Web3 | None = None
|
304
|
-
) ->
|
304
|
+
) -> OutcomeWei:
|
305
305
|
"""
|
306
306
|
Returns amount of shares we will get for the given outcome_index for the given investment amount.
|
307
307
|
"""
|
308
|
-
calculated_shares
|
309
|
-
"calcBuyAmount", [investment_amount, outcome_index], web3=web3
|
308
|
+
calculated_shares = OutcomeWei(
|
309
|
+
self.call("calcBuyAmount", [investment_amount, outcome_index], web3=web3)
|
310
310
|
)
|
311
311
|
return calculated_shares
|
312
312
|
|
313
313
|
def calcSellAmount(
|
314
314
|
self, return_amount: Wei, outcome_index: int, web3: Web3 | None = None
|
315
|
-
) ->
|
315
|
+
) -> OutcomeWei:
|
316
316
|
"""
|
317
317
|
Returns amount of shares we will sell for the requested wei.
|
318
318
|
"""
|
319
|
-
calculated_shares
|
320
|
-
"calcSellAmount", [return_amount, outcome_index], web3=web3
|
319
|
+
calculated_shares = OutcomeWei(
|
320
|
+
self.call("calcSellAmount", [return_amount, outcome_index], web3=web3)
|
321
321
|
)
|
322
322
|
return calculated_shares
|
323
323
|
|
@@ -334,7 +334,7 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
|
|
334
334
|
api_keys: APIKeys,
|
335
335
|
amount_wei: Wei,
|
336
336
|
outcome_index: int,
|
337
|
-
min_outcome_tokens_to_buy:
|
337
|
+
min_outcome_tokens_to_buy: OutcomeWei,
|
338
338
|
tx_params: t.Optional[TxParams] = None,
|
339
339
|
web3: Web3 | None = None,
|
340
340
|
) -> TxReceipt:
|
@@ -355,7 +355,7 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
|
|
355
355
|
api_keys: APIKeys,
|
356
356
|
amount_wei: Wei,
|
357
357
|
outcome_index: int,
|
358
|
-
max_outcome_tokens_to_sell:
|
358
|
+
max_outcome_tokens_to_sell: OutcomeWei,
|
359
359
|
tx_params: t.Optional[TxParams] = None,
|
360
360
|
web3: Web3 | None = None,
|
361
361
|
) -> TxReceipt:
|
@@ -411,7 +411,7 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
|
|
411
411
|
|
412
412
|
def totalSupply(self, web3: Web3 | None = None) -> Wei:
|
413
413
|
# This is the liquidity you seen on the Omen website (but in Wei).
|
414
|
-
total_supply
|
414
|
+
total_supply = Wei(self.call("totalSupply", web3=web3))
|
415
415
|
return total_supply
|
416
416
|
|
417
417
|
def get_collateral_token_contract(
|
@@ -466,7 +466,7 @@ class OmenFixedProductMarketMakerFactoryContract(ContractOnGnosisChain):
|
|
466
466
|
initial_funds_wei: Wei,
|
467
467
|
collateral_token_address: ChecksumAddress,
|
468
468
|
fee: Wei, # This is actually fee in %, 'where 100% == 1 xDai'.
|
469
|
-
distribution_hint: list[
|
469
|
+
distribution_hint: list[OutcomeWei] | None = None,
|
470
470
|
tx_params: t.Optional[TxParams] = None,
|
471
471
|
web3: Web3 | None = None,
|
472
472
|
) -> tuple[
|
@@ -585,7 +585,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
585
585
|
api_keys: APIKeys,
|
586
586
|
question: str,
|
587
587
|
category: str,
|
588
|
-
outcomes:
|
588
|
+
outcomes: t.Sequence[str],
|
589
589
|
language: str,
|
590
590
|
arbitrator: Arbitrator,
|
591
591
|
opening: DatetimeUTC,
|
@@ -640,14 +640,14 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
640
640
|
api_keys: APIKeys,
|
641
641
|
question_id: HexBytes,
|
642
642
|
answer: HexBytes,
|
643
|
-
bond:
|
644
|
-
max_previous:
|
643
|
+
bond: xDaiWei,
|
644
|
+
max_previous: xDaiWei | None = None,
|
645
645
|
web3: Web3 | None = None,
|
646
646
|
) -> TxReceipt:
|
647
647
|
if max_previous is None:
|
648
648
|
# If not provided, defaults to 0, which means no checking,
|
649
649
|
# same as on Omen website: https://github.com/protofire/omen-exchange/blob/763d9c9d05ebf9edacbc1dbaa561aa5d08813c0f/app/src/services/realitio.ts#L363.
|
650
|
-
max_previous =
|
650
|
+
max_previous = xDaiWei(0)
|
651
651
|
|
652
652
|
return self.send_with_value(
|
653
653
|
api_keys=api_keys,
|
@@ -657,7 +657,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
657
657
|
answer=answer,
|
658
658
|
max_previous=max_previous,
|
659
659
|
),
|
660
|
-
amount_wei=bond,
|
660
|
+
amount_wei=bond.as_wei,
|
661
661
|
web3=web3,
|
662
662
|
)
|
663
663
|
|
@@ -666,9 +666,9 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
666
666
|
api_keys: APIKeys,
|
667
667
|
question_id: HexBytes,
|
668
668
|
answer: str,
|
669
|
-
outcomes:
|
670
|
-
bond:
|
671
|
-
max_previous:
|
669
|
+
outcomes: t.Sequence[str],
|
670
|
+
bond: xDaiWei,
|
671
|
+
max_previous: xDaiWei | None = None,
|
672
672
|
web3: Web3 | None = None,
|
673
673
|
) -> TxReceipt:
|
674
674
|
# Normalise the answer to lowercase, to match Enum values as [YES, NO] against outcomes as ["Yes", "No"].
|
@@ -690,8 +690,8 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
690
690
|
self,
|
691
691
|
api_keys: APIKeys,
|
692
692
|
question_id: HexBytes,
|
693
|
-
bond:
|
694
|
-
max_previous:
|
693
|
+
bond: xDaiWei,
|
694
|
+
max_previous: xDaiWei | None = None,
|
695
695
|
web3: Web3 | None = None,
|
696
696
|
) -> TxReceipt:
|
697
697
|
return self.submitAnswer(
|
@@ -709,7 +709,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
709
709
|
question_id: HexBytes,
|
710
710
|
history_hashes: list[HexBytes],
|
711
711
|
addresses: list[ChecksumAddress],
|
712
|
-
bonds: list[
|
712
|
+
bonds: list[xDaiWei],
|
713
713
|
answers: list[HexBytes],
|
714
714
|
tx_params: t.Optional[TxParams] = None,
|
715
715
|
web3: Web3 | None = None,
|
@@ -732,8 +732,8 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
732
732
|
self,
|
733
733
|
from_address: ChecksumAddress,
|
734
734
|
web3: Web3 | None = None,
|
735
|
-
) ->
|
736
|
-
balance =
|
735
|
+
) -> xDaiWei:
|
736
|
+
balance = xDaiWei(self.call("balanceOf", [from_address], web3=web3))
|
737
737
|
return balance
|
738
738
|
|
739
739
|
def withdraw(
|
@@ -826,10 +826,7 @@ class OmenAgentResultMappingContract(ContractOnGnosisChain):
|
|
826
826
|
return self.send(
|
827
827
|
api_keys=api_keys,
|
828
828
|
function_name="addPrediction",
|
829
|
-
function_params=[
|
830
|
-
market_address,
|
831
|
-
prediction.model_dump(by_alias=True, exclude="publisher_checksummed"),
|
832
|
-
],
|
829
|
+
function_params=[market_address, prediction.model_dump(by_alias=True)],
|
833
830
|
web3=web3,
|
834
831
|
)
|
835
832
|
|
@@ -899,9 +896,11 @@ class OmenThumbnailMapping(ContractOnGnosisChain):
|
|
899
896
|
class CollateralTokenChoice(str, Enum):
|
900
897
|
wxdai = "wxdai"
|
901
898
|
sdai = "sdai"
|
899
|
+
gno = "gno"
|
902
900
|
|
903
901
|
|
904
902
|
COLLATERAL_TOKEN_CHOICE_TO_ADDRESS = {
|
905
903
|
CollateralTokenChoice.wxdai: WrappedxDaiContract().address,
|
906
904
|
CollateralTokenChoice.sdai: sDaiContract().address,
|
905
|
+
CollateralTokenChoice.gno: GNOContract().address,
|
907
906
|
}
|
@@ -5,8 +5,8 @@ from prediction_market_agent_tooling.gtypes import (
|
|
5
5
|
ChecksumAddress,
|
6
6
|
HexAddress,
|
7
7
|
HexBytes,
|
8
|
-
Wei,
|
9
8
|
xDai,
|
9
|
+
xDaiWei,
|
10
10
|
)
|
11
11
|
from prediction_market_agent_tooling.loggers import logger
|
12
12
|
from prediction_market_agent_tooling.markets.data_models import Resolution
|
@@ -32,12 +32,7 @@ from prediction_market_agent_tooling.tools.tokens.main_token import (
|
|
32
32
|
MINIMUM_NATIVE_TOKEN_IN_EOA_FOR_FEES,
|
33
33
|
)
|
34
34
|
from prediction_market_agent_tooling.tools.utils import utcnow
|
35
|
-
from prediction_market_agent_tooling.tools.web3_utils import
|
36
|
-
ZERO_BYTES,
|
37
|
-
wei_to_xdai,
|
38
|
-
xdai_to_wei,
|
39
|
-
xdai_type,
|
40
|
-
)
|
35
|
+
from prediction_market_agent_tooling.tools.web3_utils import ZERO_BYTES
|
41
36
|
|
42
37
|
|
43
38
|
def claim_bonds_on_realitio_questions(
|
@@ -93,7 +88,7 @@ def claim_bonds_on_realitio_question(
|
|
93
88
|
|
94
89
|
history_hashes: list[HexBytes] = []
|
95
90
|
addresses: list[ChecksumAddress] = []
|
96
|
-
bonds: list[
|
91
|
+
bonds: list[xDaiWei] = []
|
97
92
|
answers: list[HexBytes] = []
|
98
93
|
|
99
94
|
# Caller must provide the answer history, in reverse order.
|
@@ -128,7 +123,7 @@ def claim_bonds_on_realitio_question(
|
|
128
123
|
# Keeping balance on Realitio is not useful, so it's recommended to just withdraw it.
|
129
124
|
if current_balance > 0 and auto_withdraw:
|
130
125
|
logger.info(
|
131
|
-
f"Withdrawing remaining balance {
|
126
|
+
f"Withdrawing remaining balance {current_balance.as_xdai} xDai from Realitio."
|
132
127
|
)
|
133
128
|
realitio_contract.withdraw(api_keys, web3=web3)
|
134
129
|
|
@@ -150,9 +145,7 @@ def finalize_markets(
|
|
150
145
|
# If we don't have enough of xDai for bond, try to get it from the keeping token.
|
151
146
|
send_keeping_token_to_eoa_xdai(
|
152
147
|
api_keys=api_keys,
|
153
|
-
min_required_balance=
|
154
|
-
realitio_bond + MINIMUM_NATIVE_TOKEN_IN_EOA_FOR_FEES
|
155
|
-
),
|
148
|
+
min_required_balance=realitio_bond + MINIMUM_NATIVE_TOKEN_IN_EOA_FOR_FEES,
|
156
149
|
web3=web3,
|
157
150
|
)
|
158
151
|
|
@@ -235,7 +228,7 @@ def omen_submit_answer_market_tx(
|
|
235
228
|
question_id=market.question.id,
|
236
229
|
answer=resolution.value,
|
237
230
|
outcomes=market.question.outcomes,
|
238
|
-
bond=
|
231
|
+
bond=bond.as_xdai_wei,
|
239
232
|
web3=web3,
|
240
233
|
)
|
241
234
|
|
@@ -254,7 +247,7 @@ def omen_submit_invalid_answer_market_tx(
|
|
254
247
|
realitio_contract.submit_answer_invalid(
|
255
248
|
api_keys=api_keys,
|
256
249
|
question_id=market.question.id,
|
257
|
-
bond=
|
250
|
+
bond=bond.as_xdai_wei,
|
258
251
|
web3=web3,
|
259
252
|
)
|
260
253
|
|
@@ -11,7 +11,6 @@ from prediction_market_agent_tooling.gtypes import (
|
|
11
11
|
HexAddress,
|
12
12
|
HexBytes,
|
13
13
|
Wei,
|
14
|
-
wei_type,
|
15
14
|
)
|
16
15
|
from prediction_market_agent_tooling.markets.agent_market import FilterBy, SortBy
|
17
16
|
from prediction_market_agent_tooling.markets.base_subgraph_handler import (
|
@@ -24,6 +23,8 @@ from prediction_market_agent_tooling.markets.omen.data_models import (
|
|
24
23
|
OmenMarket,
|
25
24
|
OmenPosition,
|
26
25
|
OmenUserPosition,
|
26
|
+
OutcomeStr,
|
27
|
+
OutcomeWei,
|
27
28
|
RealityAnswer,
|
28
29
|
RealityQuestion,
|
29
30
|
RealityResponse,
|
@@ -44,6 +45,7 @@ from prediction_market_agent_tooling.tools.utils import (
|
|
44
45
|
from prediction_market_agent_tooling.tools.web3_utils import (
|
45
46
|
ZERO_BYTES,
|
46
47
|
byte32_to_ipfscidv0,
|
48
|
+
unwrap_generic_value,
|
47
49
|
)
|
48
50
|
|
49
51
|
SAFE_COLLATERAL_TOKENS = (
|
@@ -209,7 +211,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
209
211
|
self,
|
210
212
|
creator: HexAddress | None,
|
211
213
|
creator_in: t.Sequence[HexAddress] | None,
|
212
|
-
outcomes:
|
214
|
+
outcomes: t.Sequence[OutcomeStr],
|
213
215
|
created_after: DatetimeUTC | None,
|
214
216
|
question_opened_before: DatetimeUTC | None,
|
215
217
|
question_opened_after: DatetimeUTC | None,
|
@@ -347,7 +349,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
347
349
|
# because even closed markets don't need to be resolved yet (e.g. if someone forgot to finalize the question on reality).
|
348
350
|
opened_after = utcnow()
|
349
351
|
# Even if the market isn't closed yet, liquidity can be withdrawn to 0, which essentially closes the market.
|
350
|
-
liquidity_bigger_than =
|
352
|
+
liquidity_bigger_than = Wei(0)
|
351
353
|
elif filter_by == FilterBy.NONE:
|
352
354
|
pass
|
353
355
|
else:
|
@@ -391,7 +393,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
391
393
|
id_in: list[str] | None = None,
|
392
394
|
sort_by_field: FieldPath | None = None,
|
393
395
|
sort_direction: str | None = None,
|
394
|
-
outcomes:
|
396
|
+
outcomes: t.Sequence[OutcomeStr] = OMEN_BINARY_MARKET_OUTCOMES,
|
395
397
|
collateral_token_address_in: (
|
396
398
|
tuple[ChecksumAddress, ...] | None
|
397
399
|
) = SAFE_COLLATERAL_TOKENS_ADDRESSES,
|
@@ -434,7 +436,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
434
436
|
first=(
|
435
437
|
limit if limit else sys.maxsize
|
436
438
|
), # if not limit, we fetch all possible markets
|
437
|
-
where=where_stms,
|
439
|
+
where=unwrap_generic_value(where_stms),
|
438
440
|
**optional_params,
|
439
441
|
)
|
440
442
|
|
@@ -489,7 +491,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
489
491
|
where_stms["conditionIds_contains"] = [condition_id.hex()]
|
490
492
|
|
491
493
|
positions = self.conditional_tokens_subgraph.Query.positions(
|
492
|
-
first=sys.maxsize, where=where_stms
|
494
|
+
first=sys.maxsize, where=unwrap_generic_value(where_stms)
|
493
495
|
)
|
494
496
|
fields = self._get_fields_for_positions(positions)
|
495
497
|
result = self.sg.query_json(fields)
|
@@ -500,7 +502,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
500
502
|
self,
|
501
503
|
better_address: ChecksumAddress,
|
502
504
|
position_id_in: list[HexBytes] | None = None,
|
503
|
-
total_balance_bigger_than:
|
505
|
+
total_balance_bigger_than: OutcomeWei | None = None,
|
504
506
|
) -> list[OmenUserPosition]:
|
505
507
|
where_stms: dict[str, t.Any] = {
|
506
508
|
"user": better_address.lower(),
|
@@ -514,7 +516,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
514
516
|
where_stms["position_"]["positionId_in"] = [x.hex() for x in position_id_in]
|
515
517
|
|
516
518
|
positions = self.conditional_tokens_subgraph.Query.userPositions(
|
517
|
-
first=sys.maxsize, where=where_stms
|
519
|
+
first=sys.maxsize, where=unwrap_generic_value(where_stms)
|
518
520
|
)
|
519
521
|
fields = self._get_fields_for_user_positions(positions)
|
520
522
|
result = self.sg.query_json(fields)
|
@@ -568,7 +570,9 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
568
570
|
< to_int_timestamp(market_resolved_before)
|
569
571
|
)
|
570
572
|
if collateral_amount_more_than is not None:
|
571
|
-
where_stms.append(
|
573
|
+
where_stms.append(
|
574
|
+
trade.collateralAmount > collateral_amount_more_than.value
|
575
|
+
)
|
572
576
|
|
573
577
|
# These values can not be set to `None`, but they can be omitted.
|
574
578
|
optional_params = {}
|
@@ -579,7 +583,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
579
583
|
|
580
584
|
trades = self.trades_subgraph.Query.fpmmTrades(
|
581
585
|
first=limit if limit else sys.maxsize,
|
582
|
-
where=where_stms,
|
586
|
+
where=unwrap_generic_value(where_stms),
|
583
587
|
**optional_params,
|
584
588
|
)
|
585
589
|
fields = self._get_fields_for_bets(trades)
|
@@ -818,7 +822,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
818
822
|
first=(
|
819
823
|
limit if limit else sys.maxsize
|
820
824
|
), # if not limit, we fetch all possible
|
821
|
-
where=where_stms,
|
825
|
+
where=unwrap_generic_value(where_stms),
|
822
826
|
)
|
823
827
|
fields = self._get_fields_for_reality_questions(questions)
|
824
828
|
result = self.sg.query_json(fields)
|
@@ -832,7 +836,9 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
832
836
|
answer.question.questionId == question_id.hex(),
|
833
837
|
]
|
834
838
|
|
835
|
-
answers = self.realityeth_subgraph.Query.answers(
|
839
|
+
answers = self.realityeth_subgraph.Query.answers(
|
840
|
+
where=unwrap_generic_value(where_stms)
|
841
|
+
)
|
836
842
|
fields = self._get_fields_for_answers(answers)
|
837
843
|
result = self.sg.query_json(fields)
|
838
844
|
items = self._parse_items_from_json(result)
|
@@ -879,7 +885,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
879
885
|
first=(
|
880
886
|
limit if limit else sys.maxsize
|
881
887
|
), # if not limit, we fetch all possible
|
882
|
-
where=where_stms,
|
888
|
+
where=unwrap_generic_value(where_stms),
|
883
889
|
)
|
884
890
|
fields = self._get_fields_for_responses(responses)
|
885
891
|
result = self.sg.query_json(fields)
|
@@ -938,7 +944,7 @@ class OmenSubgraphHandler(BaseSubgraphHandler):
|
|
938
944
|
|
939
945
|
prediction_added = (
|
940
946
|
self.omen_agent_result_mapping_subgraph.Query.predictionAddeds(
|
941
|
-
where=where_stms,
|
947
|
+
where=unwrap_generic_value(where_stms),
|
942
948
|
orderBy="blockNumber",
|
943
949
|
orderDirection="asc",
|
944
950
|
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from pydantic import BaseModel
|
2
2
|
|
3
|
-
from prediction_market_agent_tooling.gtypes import USDC,
|
3
|
+
from prediction_market_agent_tooling.gtypes import USDC, OutcomeStr, Probability
|
4
4
|
from prediction_market_agent_tooling.markets.data_models import Resolution
|
5
5
|
from prediction_market_agent_tooling.markets.polymarket.data_models_web import (
|
6
6
|
POLYMARKET_FALSE_OUTCOME,
|
@@ -22,7 +22,7 @@ class PolymarketRewards(BaseModel):
|
|
22
22
|
|
23
23
|
class PolymarketToken(BaseModel):
|
24
24
|
token_id: str
|
25
|
-
outcome:
|
25
|
+
outcome: OutcomeStr
|
26
26
|
winner: bool
|
27
27
|
|
28
28
|
|
@@ -111,7 +111,7 @@ class PolymarketPriceResponse(BaseModel):
|
|
111
111
|
|
112
112
|
@property
|
113
113
|
def price_dec(self) -> USDC:
|
114
|
-
return
|
114
|
+
return USDC(self.price)
|
115
115
|
|
116
116
|
|
117
117
|
class Prices(BaseModel):
|
@@ -1,5 +1,5 @@
|
|
1
1
|
"""
|
2
|
-
Autogenerated using `datamodel-codegen` from a single Polymarket response. Then adjusted, fixed.
|
2
|
+
Autogenerated using `datamodel-codegen` from a single Polymarket response. Then adjusted, fixed.
|
3
3
|
Keep in mind that not all fields were used so far, so there might be some bugs.
|
4
4
|
|
5
5
|
These models are based on what Polymarket's website returns in the response, and `prediction_market_agent_tooling/markets/polymarket/data_models.py` are based on what their API returns.
|
@@ -11,7 +11,7 @@ import typing as t
|
|
11
11
|
import requests
|
12
12
|
from pydantic import BaseModel, field_validator
|
13
13
|
|
14
|
-
from prediction_market_agent_tooling.gtypes import USDC, HexAddress
|
14
|
+
from prediction_market_agent_tooling.gtypes import USDC, HexAddress, OutcomeStr
|
15
15
|
from prediction_market_agent_tooling.loggers import logger
|
16
16
|
from prediction_market_agent_tooling.markets.data_models import Resolution
|
17
17
|
from prediction_market_agent_tooling.tools.utils import DatetimeUTC
|
@@ -47,7 +47,7 @@ class Market1(BaseModel):
|
|
47
47
|
question: str
|
48
48
|
image: str
|
49
49
|
volume: USDC | None = None
|
50
|
-
outcomes:
|
50
|
+
outcomes: t.Sequence[OutcomeStr]
|
51
51
|
outcomePrices: list[USDC]
|
52
52
|
active: bool
|
53
53
|
archived: bool
|
@@ -92,7 +92,7 @@ class Market(BaseModel):
|
|
92
92
|
fee: str | None = None
|
93
93
|
lowerBound: t.Any | None = None
|
94
94
|
upperBound: t.Any | None = None
|
95
|
-
outcomes:
|
95
|
+
outcomes: t.Sequence[OutcomeStr]
|
96
96
|
image: str | None = None
|
97
97
|
icon: str | None = None
|
98
98
|
imageOptimized: t.Any | None = None
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import typing as t
|
2
2
|
|
3
|
+
from prediction_market_agent_tooling.gtypes import USD, CollateralToken
|
3
4
|
from prediction_market_agent_tooling.markets.agent_market import (
|
4
5
|
AgentMarket,
|
5
6
|
FilterBy,
|
6
7
|
MarketFees,
|
7
8
|
SortBy,
|
8
9
|
)
|
9
|
-
from prediction_market_agent_tooling.markets.data_models import BetAmount, Currency
|
10
10
|
from prediction_market_agent_tooling.markets.polymarket.api import (
|
11
11
|
get_polymarket_binary_markets,
|
12
12
|
)
|
@@ -24,7 +24,6 @@ class PolymarketAgentMarket(AgentMarket):
|
|
24
24
|
Polymarket's market class that can be used by agents to make predictions.
|
25
25
|
"""
|
26
26
|
|
27
|
-
currency: t.ClassVar[Currency] = Currency.USDC
|
28
27
|
base_url: t.ClassVar[str] = POLYMARKET_BASE_URL
|
29
28
|
|
30
29
|
# Based on https://docs.polymarket.com/#fees, there are currently no fees, except for transactions fees.
|
@@ -49,11 +48,10 @@ class PolymarketAgentMarket(AgentMarket):
|
|
49
48
|
outcome_token_pool=None,
|
50
49
|
)
|
51
50
|
|
52
|
-
|
53
|
-
def get_tiny_bet_amount(cls) -> BetAmount:
|
51
|
+
def get_tiny_bet_amount(self) -> CollateralToken:
|
54
52
|
raise NotImplementedError("TODO: Implement to allow betting on Polymarket.")
|
55
53
|
|
56
|
-
def place_bet(self, outcome: bool, amount:
|
54
|
+
def place_bet(self, outcome: bool, amount: USD) -> str:
|
57
55
|
raise NotImplementedError("TODO: Implement to allow betting on Polymarket.")
|
58
56
|
|
59
57
|
@staticmethod
|
@@ -5,20 +5,47 @@ from urllib.parse import urljoin
|
|
5
5
|
|
6
6
|
from pydantic import BaseModel, ConfigDict, Field
|
7
7
|
from web3 import Web3
|
8
|
+
from web3.constants import ADDRESS_ZERO
|
8
9
|
|
9
10
|
from prediction_market_agent_tooling.config import RPCConfig
|
10
11
|
from prediction_market_agent_tooling.gtypes import (
|
11
12
|
ChecksumAddress,
|
13
|
+
CollateralToken,
|
12
14
|
HexAddress,
|
13
15
|
HexBytes,
|
16
|
+
OutcomeStr,
|
17
|
+
Probability,
|
18
|
+
Web3Wei,
|
14
19
|
)
|
20
|
+
from prediction_market_agent_tooling.loggers import logger
|
15
21
|
from prediction_market_agent_tooling.markets.data_models import Resolution
|
16
|
-
from prediction_market_agent_tooling.
|
17
|
-
SeerParentMarket,
|
18
|
-
)
|
22
|
+
from prediction_market_agent_tooling.tools.cow.cow_manager import CowManager
|
19
23
|
from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC
|
20
24
|
|
21
25
|
|
26
|
+
class CreateCategoricalMarketsParams(BaseModel):
|
27
|
+
model_config = ConfigDict(populate_by_name=True)
|
28
|
+
|
29
|
+
market_name: str = Field(..., alias="marketName")
|
30
|
+
outcomes: t.Sequence[OutcomeStr]
|
31
|
+
# Only relevant for scalar markets
|
32
|
+
question_start: str = Field(alias="questionStart", default="")
|
33
|
+
question_end: str = Field(alias="questionEnd", default="")
|
34
|
+
outcome_type: str = Field(alias="outcomeType", default="")
|
35
|
+
|
36
|
+
# Not needed for non-conditional markets.
|
37
|
+
parent_outcome: int = Field(alias="parentOutcome", default=0)
|
38
|
+
parent_market: HexAddress = Field(alias="parentMarket", default=ADDRESS_ZERO)
|
39
|
+
|
40
|
+
category: str
|
41
|
+
lang: str
|
42
|
+
lower_bound: int = Field(alias="lowerBound", default=0)
|
43
|
+
upper_bound: int = Field(alias="upperBound", default=0)
|
44
|
+
min_bond: Web3Wei = Field(..., alias="minBond")
|
45
|
+
opening_time: int = Field(..., alias="openingTime")
|
46
|
+
token_names: list[str] = Field(..., alias="tokenNames")
|
47
|
+
|
48
|
+
|
22
49
|
class SeerOutcomeEnum(str, Enum):
|
23
50
|
YES = "yes"
|
24
51
|
NO = "no"
|
@@ -57,6 +84,10 @@ class SeerOutcomeEnum(str, Enum):
|
|
57
84
|
raise ValueError(f"Unknown outcome: {self}")
|
58
85
|
|
59
86
|
|
87
|
+
class SeerParentMarket(BaseModel):
|
88
|
+
id: HexBytes
|
89
|
+
|
90
|
+
|
60
91
|
SEER_BASE_URL = "https://app.seer.pm"
|
61
92
|
|
62
93
|
|
@@ -66,7 +97,7 @@ class SeerMarket(BaseModel):
|
|
66
97
|
id: HexBytes
|
67
98
|
creator: HexAddress
|
68
99
|
title: str = Field(alias="marketName")
|
69
|
-
outcomes:
|
100
|
+
outcomes: t.Sequence[OutcomeStr]
|
70
101
|
wrapped_tokens: list[HexAddress] = Field(alias="wrappedTokens")
|
71
102
|
parent_outcome: int = Field(alias="parentOutcome")
|
72
103
|
parent_market: t.Optional[SeerParentMarket] = Field(
|
@@ -79,7 +110,6 @@ class SeerMarket(BaseModel):
|
|
79
110
|
has_answers: bool | None = Field(alias="hasAnswers")
|
80
111
|
payout_reported: bool = Field(alias="payoutReported")
|
81
112
|
payout_numerators: list[int] = Field(alias="payoutNumerators")
|
82
|
-
outcomes_supply: int = Field(alias="outcomesSupply")
|
83
113
|
|
84
114
|
@property
|
85
115
|
def has_valid_answer(self) -> bool:
|
@@ -156,7 +186,64 @@ class SeerMarket(BaseModel):
|
|
156
186
|
def created_time(self) -> DatetimeUTC:
|
157
187
|
return DatetimeUTC.to_datetime_utc(self.block_timestamp)
|
158
188
|
|
189
|
+
@property
|
190
|
+
def current_p_yes(self) -> Probability:
|
191
|
+
price_data = {}
|
192
|
+
for idx in range(len(self.outcomes)):
|
193
|
+
wrapped_token = self.wrapped_tokens[idx]
|
194
|
+
price = self._get_price_for_token(
|
195
|
+
token=Web3.to_checksum_address(wrapped_token)
|
196
|
+
)
|
197
|
+
price_data[idx] = price
|
198
|
+
|
199
|
+
if sum(price_data.values()) == 0:
|
200
|
+
logger.warning(
|
201
|
+
f"Could not get p_yes for market {self.id.hex()}, all price quotes are 0."
|
202
|
+
)
|
203
|
+
return Probability(0)
|
204
|
+
|
205
|
+
yes_idx = self.outcome_as_enums[SeerOutcomeEnum.YES]
|
206
|
+
price_yes = price_data[yes_idx] / sum(price_data.values())
|
207
|
+
return Probability(price_yes)
|
208
|
+
|
209
|
+
def _get_price_for_token(self, token: ChecksumAddress) -> float:
|
210
|
+
collateral_exchange_amount = CollateralToken(1).as_wei
|
211
|
+
try:
|
212
|
+
quote = CowManager().get_quote(
|
213
|
+
collateral_token=self.collateral_token_contract_address_checksummed,
|
214
|
+
buy_token=token,
|
215
|
+
sell_amount=collateral_exchange_amount,
|
216
|
+
)
|
217
|
+
except Exception as e:
|
218
|
+
logger.warning(f"Could not get quote for {token=}, returning price 0. {e=}")
|
219
|
+
return 0
|
220
|
+
|
221
|
+
return collateral_exchange_amount.value / float(quote.quote.buyAmount.root)
|
222
|
+
|
159
223
|
@property
|
160
224
|
def url(self) -> str:
|
161
225
|
chain_id = RPCConfig().chain_id
|
162
226
|
return urljoin(SEER_BASE_URL, f"markets/{chain_id}/{self.id.hex()}")
|
227
|
+
|
228
|
+
|
229
|
+
class SeerToken(BaseModel):
|
230
|
+
id: HexBytes
|
231
|
+
name: str
|
232
|
+
symbol: str
|
233
|
+
|
234
|
+
|
235
|
+
class SeerPool(BaseModel):
|
236
|
+
model_config = ConfigDict(populate_by_name=True)
|
237
|
+
id: HexBytes
|
238
|
+
liquidity: int
|
239
|
+
token0: SeerToken
|
240
|
+
token1: SeerToken
|
241
|
+
|
242
|
+
|
243
|
+
class NewMarketEvent(BaseModel):
|
244
|
+
market: HexAddress
|
245
|
+
marketName: str
|
246
|
+
parentMarket: HexAddress
|
247
|
+
conditionId: HexBytes
|
248
|
+
questionId: HexBytes
|
249
|
+
questionsIds: list[HexBytes]
|