prediction-market-agent-tooling 0.67.4__tar.gz → 0.68.0__tar.gz
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-0.67.4 → prediction_market_agent_tooling-0.68.0}/PKG-INFO +1 -1
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/deploy/agent.py +2 -4
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/deploy/betting_strategy.py +177 -49
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/jobs/omen/omen_jobs.py +2 -2
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/omen/data_models.py +6 -1
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/omen/omen.py +43 -6
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/seer/price_manager.py +68 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/seer/seer.py +11 -7
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +2 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/seer/subgraph_data_models.py +2 -0
- prediction_market_agent_tooling-0.68.0/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +418 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/betting_strategies/utils.py +6 -1
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/langfuse_client_utils.py +0 -3
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/web3_utils.py +2 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/pyproject.toml +1 -1
- prediction_market_agent_tooling-0.67.4/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -150
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/README.md +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/agentresultmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/debuggingcontract.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/erc1155.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/erc4626.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/erc721.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/gvp2_settlement.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/ownable.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/ownable_erc721.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/proxy.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/seer_gnosis_router.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/seer_market_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/abis/swapr_router.abi.json +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/chains.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/config.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/data_download/langfuse_data_downloader.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/deploy/trade_interval.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/gtypes.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/jobs/__init__.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/jobs/jobs_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/loggers.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/logprobs_parser.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/agent_market.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/base_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/blockchain_utils.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/data_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/market_fees.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/markets.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/metaculus/api.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/metaculus/data_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/metaculus/metaculus.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/omen/cow_contracts.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/omen/omen_constants.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/polymarket/polymarket_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/seer/data_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/seer/exceptions.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/seer/seer_contracts.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/markets/seer/swap_pool_handler.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/py.typed +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/_generic_value.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/balances.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/caches/db_cache.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/caches/inmemory_cache.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/caches/serializers.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/contract.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/costs.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/cow/cow_order.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/cow/models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/cow/semaphore.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/custom_exceptions.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/datetime_utc.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/db/db_manager.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/google_utils.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/httpx_cached_client.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/image_gen/image_gen.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/is_invalid.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/langfuse_.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/omen/reality_accuracy.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/omen/sell_positions.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/perplexity/perplexity_client.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/perplexity/perplexity_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/perplexity/perplexity_search.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/relevant_news_analysis/data_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_analysis.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_cache.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/rephrase.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/safe.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/streamlit_user_login.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/tavily/tavily_models.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/tavily/tavily_search.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/tokens/auto_deposit.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/tokens/main_token.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/tokens/slippage.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/tokens/token_utils.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/tokens/usd.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/transaction_cache.py +0 -0
- {prediction_market_agent_tooling-0.67.4 → prediction_market_agent_tooling-0.68.0}/prediction_market_agent_tooling/tools/utils.py +0 -0
@@ -11,7 +11,7 @@ from pydantic_ai.exceptions import UnexpectedModelBehavior
|
|
11
11
|
from prediction_market_agent_tooling.config import APIKeys
|
12
12
|
from prediction_market_agent_tooling.deploy.betting_strategy import (
|
13
13
|
BettingStrategy,
|
14
|
-
|
14
|
+
CategoricalMaxAccuracyBettingStrategy,
|
15
15
|
TradeType,
|
16
16
|
)
|
17
17
|
from prediction_market_agent_tooling.deploy.trade_interval import (
|
@@ -662,9 +662,7 @@ class DeployableTraderAgent(DeployablePredictionAgent):
|
|
662
662
|
Given the market and prediction, agent uses this method to calculate optimal outcome and bet size.
|
663
663
|
"""
|
664
664
|
total_amount = self.get_total_amount_to_bet(market)
|
665
|
-
return
|
666
|
-
max_position_amount=total_amount
|
667
|
-
)
|
665
|
+
return CategoricalMaxAccuracyBettingStrategy(max_position_amount=total_amount)
|
668
666
|
|
669
667
|
def build_trades(
|
670
668
|
self,
|
@@ -30,8 +30,13 @@ from prediction_market_agent_tooling.markets.omen.omen import (
|
|
30
30
|
from prediction_market_agent_tooling.tools.betting_strategies.kelly_criterion import (
|
31
31
|
get_kelly_bet_full,
|
32
32
|
get_kelly_bet_simplified,
|
33
|
+
get_kelly_bets_categorical_full,
|
34
|
+
get_kelly_bets_categorical_simplified,
|
35
|
+
)
|
36
|
+
from prediction_market_agent_tooling.tools.betting_strategies.utils import (
|
37
|
+
BinaryKellyBet,
|
38
|
+
CategoricalKellyBet,
|
33
39
|
)
|
34
|
-
from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet
|
35
40
|
from prediction_market_agent_tooling.tools.utils import check_not_none
|
36
41
|
|
37
42
|
|
@@ -245,7 +250,7 @@ class BettingStrategy(ABC):
|
|
245
250
|
return trades
|
246
251
|
|
247
252
|
|
248
|
-
class
|
253
|
+
class CategoricalMaxAccuracyBettingStrategy(BettingStrategy):
|
249
254
|
def __init__(self, max_position_amount: USD, take_profit: bool = True):
|
250
255
|
super().__init__(take_profit=take_profit)
|
251
256
|
self.max_position_amount = max_position_amount
|
@@ -308,8 +313,11 @@ class MultiCategoricalMaxAccuracyBettingStrategy(BettingStrategy):
|
|
308
313
|
)
|
309
314
|
return trades
|
310
315
|
|
316
|
+
def __repr__(self) -> str:
|
317
|
+
return f"CategoricalMaxAccuracyBettingStrategy(max_position_amount={self.max_position_amount}, take_profit={self.take_profit})"
|
318
|
+
|
311
319
|
|
312
|
-
class MaxExpectedValueBettingStrategy(
|
320
|
+
class MaxExpectedValueBettingStrategy(CategoricalMaxAccuracyBettingStrategy):
|
313
321
|
@staticmethod
|
314
322
|
def calculate_direction(
|
315
323
|
market: AgentMarket, answer: CategoricalProbabilisticAnswer
|
@@ -350,49 +358,52 @@ class MaxExpectedValueBettingStrategy(MultiCategoricalMaxAccuracyBettingStrategy
|
|
350
358
|
|
351
359
|
return best_outcome
|
352
360
|
|
361
|
+
def __repr__(self) -> str:
|
362
|
+
return f"MaxExpectedValueBettingStrategy(max_position_amount={self.max_position_amount}, take_profit={self.take_profit})"
|
363
|
+
|
353
364
|
|
354
|
-
class
|
365
|
+
class BinaryKellyBettingStrategy(BettingStrategy):
|
355
366
|
def __init__(
|
356
367
|
self,
|
357
368
|
max_position_amount: USD,
|
358
369
|
max_price_impact: float | None = None,
|
359
370
|
take_profit: bool = True,
|
371
|
+
force_simplified_calculation: bool = False,
|
360
372
|
):
|
361
373
|
super().__init__(take_profit=take_profit)
|
362
374
|
self.max_position_amount = max_position_amount
|
363
375
|
self.max_price_impact = max_price_impact
|
376
|
+
self.force_simplified_calculation = force_simplified_calculation
|
364
377
|
|
365
378
|
@property
|
366
379
|
def maximum_possible_bet_amount(self) -> USD:
|
367
380
|
return self.max_position_amount
|
368
381
|
|
369
|
-
@staticmethod
|
370
382
|
def get_kelly_bet(
|
383
|
+
self,
|
371
384
|
market: AgentMarket,
|
372
|
-
max_bet_amount: USD,
|
373
385
|
direction: OutcomeStr,
|
374
386
|
other_direction: OutcomeStr,
|
375
387
|
answer: CategoricalProbabilisticAnswer,
|
376
388
|
override_p_yes: float | None = None,
|
377
|
-
) ->
|
389
|
+
) -> BinaryKellyBet:
|
390
|
+
if not market.is_binary:
|
391
|
+
raise ValueError("This strategy is usable only with binary markets.")
|
392
|
+
|
378
393
|
estimated_p_yes = (
|
379
394
|
answer.probability_for_market_outcome(direction)
|
380
395
|
if not override_p_yes
|
381
396
|
else override_p_yes
|
382
397
|
)
|
383
398
|
|
384
|
-
if
|
385
|
-
# use Kelly simple, since Kelly full only supports 2 outcomes
|
386
|
-
|
399
|
+
if market.outcome_token_pool is None or self.force_simplified_calculation:
|
387
400
|
kelly_bet = get_kelly_bet_simplified(
|
388
|
-
max_bet=market.get_usd_in_token(
|
401
|
+
max_bet=market.get_usd_in_token(self.max_position_amount),
|
389
402
|
market_p_yes=market.probability_for_market_outcome(direction),
|
390
403
|
estimated_p_yes=estimated_p_yes,
|
391
404
|
confidence=answer.confidence,
|
392
405
|
)
|
393
406
|
else:
|
394
|
-
# We consider only binary markets, since the Kelly strategy is not yet implemented
|
395
|
-
# for markets with more than 2 outcomes (https://github.com/gnosis/prediction-market-agent-tooling/issues/671).
|
396
407
|
direction_to_bet_pool_size = market.get_outcome_token_pool_by_outcome(
|
397
408
|
direction
|
398
409
|
)
|
@@ -403,7 +414,7 @@ class KellyBettingStrategy(BettingStrategy):
|
|
403
414
|
yes_outcome_pool_size=direction_to_bet_pool_size,
|
404
415
|
no_outcome_pool_size=other_direction_pool_size,
|
405
416
|
estimated_p_yes=estimated_p_yes,
|
406
|
-
max_bet=market.get_usd_in_token(
|
417
|
+
max_bet=market.get_usd_in_token(self.max_position_amount),
|
407
418
|
confidence=answer.confidence,
|
408
419
|
fees=market.fees,
|
409
420
|
)
|
@@ -416,7 +427,7 @@ class KellyBettingStrategy(BettingStrategy):
|
|
416
427
|
market: AgentMarket,
|
417
428
|
) -> list[Trade]:
|
418
429
|
# We consider the p_yes as the direction with highest probability.
|
419
|
-
direction =
|
430
|
+
direction = CategoricalMaxAccuracyBettingStrategy.calculate_direction(
|
420
431
|
market, answer
|
421
432
|
)
|
422
433
|
# We get the first direction which is != direction.
|
@@ -426,7 +437,6 @@ class KellyBettingStrategy(BettingStrategy):
|
|
426
437
|
|
427
438
|
kelly_bet = self.get_kelly_bet(
|
428
439
|
market=market,
|
429
|
-
max_bet_amount=self.max_position_amount,
|
430
440
|
direction=direction,
|
431
441
|
other_direction=other_direction,
|
432
442
|
answer=answer,
|
@@ -436,7 +446,10 @@ class KellyBettingStrategy(BettingStrategy):
|
|
436
446
|
if self.max_price_impact:
|
437
447
|
# Adjust amount
|
438
448
|
max_price_impact_bet_amount = self.calculate_bet_amount_for_price_impact(
|
439
|
-
market,
|
449
|
+
market,
|
450
|
+
kelly_bet.size,
|
451
|
+
direction=direction,
|
452
|
+
max_price_impact=self.max_price_impact,
|
440
453
|
)
|
441
454
|
|
442
455
|
# We just don't want Kelly size to extrapolate price_impact - hence we take the min.
|
@@ -447,7 +460,9 @@ class KellyBettingStrategy(BettingStrategy):
|
|
447
460
|
amounts = {
|
448
461
|
bet_outcome: BettingStrategy.cap_to_profitable_bet_amount(
|
449
462
|
market, market.get_token_in_usd(kelly_bet_size), bet_outcome
|
450
|
-
)
|
463
|
+
)
|
464
|
+
if kelly_bet_size > 0
|
465
|
+
else USD(0),
|
451
466
|
}
|
452
467
|
target_position = Position(market_id=market.id, amounts_current=amounts)
|
453
468
|
trades = self._build_rebalance_trades_from_positions(
|
@@ -455,8 +470,8 @@ class KellyBettingStrategy(BettingStrategy):
|
|
455
470
|
)
|
456
471
|
return trades
|
457
472
|
|
473
|
+
@staticmethod
|
458
474
|
def calculate_price_impact_for_bet_amount(
|
459
|
-
self,
|
460
475
|
outcome_idx: int,
|
461
476
|
bet_amount: CollateralToken,
|
462
477
|
pool_balances: list[OutcomeWei],
|
@@ -474,33 +489,43 @@ class KellyBettingStrategy(BettingStrategy):
|
|
474
489
|
price_impact = (actual_price - expected_price) / expected_price
|
475
490
|
return price_impact
|
476
491
|
|
492
|
+
@staticmethod
|
477
493
|
def calculate_bet_amount_for_price_impact(
|
478
|
-
|
494
|
+
market: AgentMarket,
|
495
|
+
kelly_bet_size: CollateralToken,
|
496
|
+
direction: OutcomeStr,
|
497
|
+
max_price_impact: float,
|
479
498
|
) -> CollateralToken:
|
480
499
|
def calculate_price_impact_deviation_from_target_price_impact(
|
481
500
|
bet_amount_collateral: float, # Needs to be float because it's used in minimize_scalar internally.
|
482
501
|
) -> float:
|
483
502
|
outcome_idx = market.get_outcome_index(direction)
|
484
|
-
price_impact =
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
503
|
+
price_impact = (
|
504
|
+
BinaryKellyBettingStrategy.calculate_price_impact_for_bet_amount(
|
505
|
+
outcome_idx=outcome_idx,
|
506
|
+
bet_amount=CollateralToken(bet_amount_collateral),
|
507
|
+
pool_balances=pool_balances,
|
508
|
+
fees=market.fees,
|
509
|
+
)
|
489
510
|
)
|
490
511
|
# We return abs for the algorithm to converge to 0 instead of the min (and possibly negative) value.
|
491
|
-
|
492
|
-
max_price_impact = check_not_none(self.max_price_impact)
|
493
512
|
return abs(price_impact - max_price_impact)
|
494
513
|
|
495
514
|
if not market.outcome_token_pool:
|
496
515
|
logger.warning(
|
497
516
|
"Market outcome_token_pool is None, cannot calculate bet amount"
|
498
517
|
)
|
499
|
-
return
|
518
|
+
return kelly_bet_size
|
500
519
|
|
501
|
-
|
520
|
+
filtered_pool = {
|
521
|
+
outcome: pool_value
|
522
|
+
for outcome, pool_value in market.outcome_token_pool.items()
|
523
|
+
if INVALID_OUTCOME_LOWERCASE_IDENTIFIER not in outcome.lower()
|
524
|
+
}
|
525
|
+
|
526
|
+
pool_balances = [i.as_outcome_wei for i in filtered_pool.values()]
|
502
527
|
# stay float for compatibility with `minimize_scalar`
|
503
|
-
total_pool_balance = sum([i.value for i in
|
528
|
+
total_pool_balance = sum([i.value for i in filtered_pool.values()])
|
504
529
|
|
505
530
|
# The bounds below have been found to work heuristically.
|
506
531
|
optimized_bet_amount = minimize_scalar(
|
@@ -513,7 +538,7 @@ class KellyBettingStrategy(BettingStrategy):
|
|
513
538
|
return CollateralToken(optimized_bet_amount.x)
|
514
539
|
|
515
540
|
def __repr__(self) -> str:
|
516
|
-
return f"{self.__class__.__name__}(
|
541
|
+
return f"{self.__class__.__name__}(max_position_amount={self.max_position_amount}, max_price_impact={self.max_price_impact}, take_profit={self.take_profit}, force_simplified_calculation={self.force_simplified_calculation})"
|
517
542
|
|
518
543
|
|
519
544
|
class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
@@ -529,40 +554,29 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
529
554
|
def maximum_possible_bet_amount(self) -> USD:
|
530
555
|
return self.max_position_amount
|
531
556
|
|
532
|
-
def adjust_bet_amount(
|
533
|
-
self, existing_position: ExistingPosition | None, market: AgentMarket
|
534
|
-
) -> USD:
|
535
|
-
existing_position_total_amount = (
|
536
|
-
existing_position.total_amount_current if existing_position else USD(0)
|
537
|
-
)
|
538
|
-
return self.max_position_amount + existing_position_total_amount
|
539
|
-
|
540
557
|
def calculate_trades(
|
541
558
|
self,
|
542
559
|
existing_position: ExistingPosition | None,
|
543
560
|
answer: CategoricalProbabilisticAnswer,
|
544
561
|
market: AgentMarket,
|
545
562
|
) -> list[Trade]:
|
546
|
-
adjusted_bet_amount_usd = self.adjust_bet_amount(existing_position, market)
|
547
|
-
|
548
563
|
outcome = get_most_probable_outcome(answer.probabilities)
|
549
564
|
|
550
|
-
direction =
|
565
|
+
direction = CategoricalMaxAccuracyBettingStrategy.calculate_direction(
|
551
566
|
market, answer
|
552
567
|
)
|
553
568
|
# We get the first direction which is != direction.
|
554
|
-
other_direction = (
|
555
|
-
|
556
|
-
outcomes=market.outcomes, direction=direction
|
557
|
-
)
|
569
|
+
other_direction = CategoricalMaxAccuracyBettingStrategy.get_other_direction(
|
570
|
+
outcomes=market.outcomes, direction=direction
|
558
571
|
)
|
559
572
|
|
560
573
|
# We ignore the direction nudge given by Kelly, hence we assume we have a perfect prediction.
|
561
574
|
estimated_p_yes = 1.0
|
562
575
|
|
563
|
-
kelly_bet =
|
576
|
+
kelly_bet = BinaryKellyBettingStrategy(
|
577
|
+
max_position_amount=self.max_position_amount
|
578
|
+
).get_kelly_bet(
|
564
579
|
market=market,
|
565
|
-
max_bet_amount=adjusted_bet_amount_usd,
|
566
580
|
direction=direction,
|
567
581
|
other_direction=other_direction,
|
568
582
|
answer=answer,
|
@@ -584,4 +598,118 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
584
598
|
return trades
|
585
599
|
|
586
600
|
def __repr__(self) -> str:
|
587
|
-
return f"{self.__class__.__name__}(
|
601
|
+
return f"{self.__class__.__name__}(max_position_amount={self.max_position_amount}, take_profit={self.take_profit})"
|
602
|
+
|
603
|
+
|
604
|
+
class CategoricalKellyBettingStrategy(BettingStrategy):
|
605
|
+
def __init__(
|
606
|
+
self,
|
607
|
+
max_position_amount: USD,
|
608
|
+
max_price_impact: float | None,
|
609
|
+
allow_multiple_bets: bool,
|
610
|
+
allow_shorting: bool,
|
611
|
+
multicategorical: bool,
|
612
|
+
take_profit: bool = True,
|
613
|
+
force_simplified_calculation: bool = False,
|
614
|
+
):
|
615
|
+
super().__init__(take_profit=take_profit)
|
616
|
+
self.max_position_amount = max_position_amount
|
617
|
+
self.max_price_impact = max_price_impact
|
618
|
+
self.allow_multiple_bets = allow_multiple_bets
|
619
|
+
self.allow_shorting = allow_shorting
|
620
|
+
self.multicategorical = multicategorical
|
621
|
+
self.force_simplified_calculation = force_simplified_calculation
|
622
|
+
|
623
|
+
@property
|
624
|
+
def maximum_possible_bet_amount(self) -> USD:
|
625
|
+
return self.max_position_amount
|
626
|
+
|
627
|
+
def get_kelly_bets(
|
628
|
+
self,
|
629
|
+
market: AgentMarket,
|
630
|
+
max_bet_amount: USD,
|
631
|
+
answer: CategoricalProbabilisticAnswer,
|
632
|
+
) -> list[CategoricalKellyBet]:
|
633
|
+
max_bet = market.get_usd_in_token(max_bet_amount)
|
634
|
+
|
635
|
+
if market.outcome_token_pool is None or self.force_simplified_calculation:
|
636
|
+
kelly_bets = get_kelly_bets_categorical_simplified(
|
637
|
+
market_probabilities=[market.probabilities[o] for o in market.outcomes],
|
638
|
+
estimated_probabilities=[
|
639
|
+
answer.probability_for_market_outcome(o) for o in market.outcomes
|
640
|
+
],
|
641
|
+
confidence=answer.confidence,
|
642
|
+
max_bet=max_bet,
|
643
|
+
fees=market.fees,
|
644
|
+
allow_multiple_bets=self.allow_multiple_bets,
|
645
|
+
allow_shorting=self.allow_shorting,
|
646
|
+
)
|
647
|
+
|
648
|
+
else:
|
649
|
+
kelly_bets = get_kelly_bets_categorical_full(
|
650
|
+
outcome_pool_sizes=[
|
651
|
+
market.outcome_token_pool[o] for o in market.outcomes
|
652
|
+
],
|
653
|
+
estimated_probabilities=[
|
654
|
+
answer.probability_for_market_outcome(o) for o in market.outcomes
|
655
|
+
],
|
656
|
+
confidence=answer.confidence,
|
657
|
+
max_bet=max_bet,
|
658
|
+
fees=market.fees,
|
659
|
+
allow_multiple_bets=self.allow_multiple_bets,
|
660
|
+
allow_shorting=self.allow_shorting,
|
661
|
+
multicategorical=self.multicategorical,
|
662
|
+
)
|
663
|
+
|
664
|
+
return kelly_bets
|
665
|
+
|
666
|
+
def calculate_trades(
|
667
|
+
self,
|
668
|
+
existing_position: ExistingPosition | None,
|
669
|
+
answer: CategoricalProbabilisticAnswer,
|
670
|
+
market: AgentMarket,
|
671
|
+
) -> list[Trade]:
|
672
|
+
kelly_bets = self.get_kelly_bets(
|
673
|
+
market=market,
|
674
|
+
max_bet_amount=self.max_position_amount,
|
675
|
+
answer=answer,
|
676
|
+
)
|
677
|
+
|
678
|
+
# TODO: Allow shorting in BettingStrategy._build_rebalance_trades_from_positions.
|
679
|
+
# In binary implementation, we simply flip the direction in case of negative bet, for categorical outcome, we need to implement shorting.
|
680
|
+
kelly_bets = [bet for bet in kelly_bets if bet.size > 0]
|
681
|
+
if not kelly_bets:
|
682
|
+
return []
|
683
|
+
|
684
|
+
# TODO: Allow betting on multiple outcomes.
|
685
|
+
# Categorical kelly could suggest to bet on multiple outcomes, but we only consider the first one for now (limitation of BettingStrategy `trades` creation).
|
686
|
+
# Also, this could maybe work for multi-categorical markets as well, but it wasn't benchmarked for it.
|
687
|
+
best_kelly_bet = max(kelly_bets, key=lambda x: abs(x.size))
|
688
|
+
|
689
|
+
if self.max_price_impact:
|
690
|
+
# Adjust amount
|
691
|
+
max_price_impact_bet_amount = (
|
692
|
+
BinaryKellyBettingStrategy.calculate_bet_amount_for_price_impact(
|
693
|
+
market,
|
694
|
+
best_kelly_bet.size,
|
695
|
+
direction=market.get_outcome_str(best_kelly_bet.index),
|
696
|
+
max_price_impact=self.max_price_impact,
|
697
|
+
)
|
698
|
+
)
|
699
|
+
# We just don't want Kelly size to extrapolate price_impact - hence we take the min.
|
700
|
+
best_kelly_bet.size = min(best_kelly_bet.size, max_price_impact_bet_amount)
|
701
|
+
|
702
|
+
amounts = {
|
703
|
+
market.outcomes[best_kelly_bet.index]: market.get_token_in_usd(
|
704
|
+
best_kelly_bet.size
|
705
|
+
),
|
706
|
+
}
|
707
|
+
target_position = Position(market_id=market.id, amounts_current=amounts)
|
708
|
+
trades = self._build_rebalance_trades_from_positions(
|
709
|
+
existing_position, target_position, market=market
|
710
|
+
)
|
711
|
+
|
712
|
+
return trades
|
713
|
+
|
714
|
+
def __repr__(self) -> str:
|
715
|
+
return f"{self.__class__.__name__}(max_position_amount={self.max_position_amount}, max_price_impact={self.max_price_impact}, allow_multiple_bets={self.allow_multiple_bets}, allow_shorting={self.allow_shorting}, take_profit={self.take_profit}, force_simplified_calculation={self.force_simplified_calculation})"
|
@@ -2,7 +2,7 @@ import typing as t
|
|
2
2
|
|
3
3
|
from prediction_market_agent_tooling.config import APIKeys
|
4
4
|
from prediction_market_agent_tooling.deploy.betting_strategy import (
|
5
|
-
|
5
|
+
BinaryKellyBettingStrategy,
|
6
6
|
TradeType,
|
7
7
|
)
|
8
8
|
from prediction_market_agent_tooling.gtypes import USD
|
@@ -93,7 +93,7 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
93
93
|
|
94
94
|
def get_job_trade(self, max_bond: USD, result: str) -> Trade:
|
95
95
|
# Because jobs are powered by prediction markets, potentional reward depends on job's liquidity and our will to bond (bet) our xDai into our job completion.
|
96
|
-
strategy =
|
96
|
+
strategy = BinaryKellyBettingStrategy(max_position_amount=max_bond)
|
97
97
|
required_trades = strategy.calculate_trades(
|
98
98
|
existing_position=None,
|
99
99
|
answer=self.get_job_answer(result),
|
@@ -601,7 +601,12 @@ class OmenBet(BaseModel):
|
|
601
601
|
created_time=self.creation_datetime,
|
602
602
|
market_question=self.title,
|
603
603
|
market_id=self.fpmm.id,
|
604
|
-
market_outcome=self.fpmm.outcomes[
|
604
|
+
market_outcome=self.fpmm.outcomes[
|
605
|
+
check_not_none(
|
606
|
+
self.fpmm.answer_index,
|
607
|
+
"Should not be None if `is_resolved_with_valid_answer`.",
|
608
|
+
)
|
609
|
+
],
|
605
610
|
resolved_time=check_not_none(self.fpmm.finalized_datetime),
|
606
611
|
profit=self.get_profit(),
|
607
612
|
)
|
@@ -3,6 +3,7 @@ from collections import defaultdict
|
|
3
3
|
from datetime import timedelta
|
4
4
|
|
5
5
|
import tenacity
|
6
|
+
from pydantic import BaseModel
|
6
7
|
from tqdm import tqdm
|
7
8
|
from web3 import Web3
|
8
9
|
|
@@ -1323,20 +1324,34 @@ def send_keeping_token_to_eoa_xdai(
|
|
1323
1324
|
)
|
1324
1325
|
|
1325
1326
|
|
1326
|
-
|
1327
|
+
class BuyOutcomeResult(BaseModel):
|
1328
|
+
outcome_tokens_received: OutcomeToken
|
1329
|
+
new_pool_balances: list[OutcomeToken]
|
1330
|
+
|
1331
|
+
|
1332
|
+
def calculate_buy_outcome_token(
|
1327
1333
|
investment_amount: CollateralToken,
|
1328
1334
|
outcome_index: int,
|
1329
1335
|
pool_balances: list[OutcomeToken],
|
1330
1336
|
fees: MarketFees,
|
1331
|
-
) ->
|
1337
|
+
) -> BuyOutcomeResult:
|
1332
1338
|
"""
|
1333
1339
|
Calculates the amount of outcome tokens received for a given investment
|
1340
|
+
and returns the new pool balances after the purchase.
|
1334
1341
|
|
1335
1342
|
Taken from https://github.com/gnosis/conditional-tokens-market-makers/blob/6814c0247c745680bb13298d4f0dd7f5b574d0db/contracts/FixedProductMarketMaker.sol#L264
|
1336
1343
|
"""
|
1337
1344
|
if outcome_index >= len(pool_balances):
|
1338
1345
|
raise ValueError("invalid outcome index")
|
1339
1346
|
|
1347
|
+
new_pool_balances = pool_balances.copy()
|
1348
|
+
|
1349
|
+
if investment_amount == 0:
|
1350
|
+
return BuyOutcomeResult(
|
1351
|
+
outcome_tokens_received=OutcomeToken(0),
|
1352
|
+
new_pool_balances=new_pool_balances,
|
1353
|
+
)
|
1354
|
+
|
1340
1355
|
investment_amount_minus_fees = fees.get_after_fees(investment_amount)
|
1341
1356
|
investment_amount_minus_fees_as_ot = OutcomeToken(
|
1342
1357
|
investment_amount_minus_fees.value
|
@@ -1348,17 +1363,39 @@ def get_buy_outcome_token_amount(
|
|
1348
1363
|
# Calculate the ending balance considering all other outcomes
|
1349
1364
|
for i, pool_balance in enumerate(pool_balances):
|
1350
1365
|
if i != outcome_index:
|
1351
|
-
|
1366
|
+
new_pool_balances[i] = pool_balance + investment_amount_minus_fees_as_ot
|
1352
1367
|
ending_outcome_balance = OutcomeToken(
|
1353
|
-
(ending_outcome_balance * pool_balance /
|
1368
|
+
(ending_outcome_balance * pool_balance / new_pool_balances[i])
|
1354
1369
|
)
|
1355
1370
|
|
1371
|
+
# Update the bought outcome's pool balance
|
1372
|
+
new_pool_balances[outcome_index] = ending_outcome_balance
|
1373
|
+
|
1356
1374
|
if ending_outcome_balance <= 0:
|
1357
1375
|
raise ValueError("must have non-zero balances")
|
1358
1376
|
|
1359
|
-
|
1377
|
+
outcome_tokens_received = (
|
1360
1378
|
buy_token_pool_balance
|
1361
1379
|
+ investment_amount_minus_fees_as_ot
|
1362
1380
|
- ending_outcome_balance
|
1363
1381
|
)
|
1364
|
-
|
1382
|
+
|
1383
|
+
return BuyOutcomeResult(
|
1384
|
+
outcome_tokens_received=outcome_tokens_received,
|
1385
|
+
new_pool_balances=new_pool_balances,
|
1386
|
+
)
|
1387
|
+
|
1388
|
+
|
1389
|
+
def get_buy_outcome_token_amount(
|
1390
|
+
investment_amount: CollateralToken,
|
1391
|
+
outcome_index: int,
|
1392
|
+
pool_balances: list[OutcomeToken],
|
1393
|
+
fees: MarketFees,
|
1394
|
+
) -> OutcomeToken:
|
1395
|
+
result = calculate_buy_outcome_token(
|
1396
|
+
investment_amount=investment_amount,
|
1397
|
+
outcome_index=outcome_index,
|
1398
|
+
pool_balances=pool_balances,
|
1399
|
+
fees=fees,
|
1400
|
+
)
|
1401
|
+
return result.outcome_tokens_received
|
@@ -2,11 +2,15 @@ from cachetools import TTLCache, cached
|
|
2
2
|
from pydantic import BaseModel
|
3
3
|
from web3 import Web3
|
4
4
|
|
5
|
+
from prediction_market_agent_tooling.deploy.constants import (
|
6
|
+
INVALID_OUTCOME_LOWERCASE_IDENTIFIER,
|
7
|
+
)
|
5
8
|
from prediction_market_agent_tooling.gtypes import (
|
6
9
|
ChecksumAddress,
|
7
10
|
CollateralToken,
|
8
11
|
HexAddress,
|
9
12
|
OutcomeStr,
|
13
|
+
OutcomeToken,
|
10
14
|
Probability,
|
11
15
|
)
|
12
16
|
from prediction_market_agent_tooling.loggers import logger
|
@@ -182,3 +186,67 @@ class PriceManager:
|
|
182
186
|
normalized_prices[outcome] = new_price
|
183
187
|
|
184
188
|
return normalized_prices
|
189
|
+
|
190
|
+
def build_initial_probs_from_pool(
|
191
|
+
self, model: SeerMarket, wrapped_tokens: list[ChecksumAddress]
|
192
|
+
) -> tuple[dict[OutcomeStr, Probability], dict[OutcomeStr, OutcomeToken]]:
|
193
|
+
"""
|
194
|
+
Builds a map of outcome to probability and outcome token pool.
|
195
|
+
"""
|
196
|
+
probability_map = {}
|
197
|
+
outcome_token_pool = {}
|
198
|
+
wrapped_tokens_with_supply = [
|
199
|
+
(
|
200
|
+
token,
|
201
|
+
SeerSubgraphHandler().get_pool_by_token(
|
202
|
+
token, model.collateral_token_contract_address_checksummed
|
203
|
+
),
|
204
|
+
)
|
205
|
+
for token in wrapped_tokens
|
206
|
+
]
|
207
|
+
wrapped_tokens_with_supply = [
|
208
|
+
(token, pool)
|
209
|
+
for token, pool in wrapped_tokens_with_supply
|
210
|
+
if pool is not None
|
211
|
+
]
|
212
|
+
|
213
|
+
for token, pool in wrapped_tokens_with_supply:
|
214
|
+
if pool is None or pool.token1.id is None or pool.token0.id is None:
|
215
|
+
continue
|
216
|
+
if HexBytes(token) == HexBytes(pool.token1.id):
|
217
|
+
outcome_token_pool[
|
218
|
+
OutcomeStr(model.outcomes[wrapped_tokens.index(token)])
|
219
|
+
] = (
|
220
|
+
OutcomeToken(pool.totalValueLockedToken0)
|
221
|
+
if pool.totalValueLockedToken0 is not None
|
222
|
+
else OutcomeToken(0)
|
223
|
+
)
|
224
|
+
probability_map[
|
225
|
+
OutcomeStr(model.outcomes[wrapped_tokens.index(token)])
|
226
|
+
] = Probability(pool.token0Price.value)
|
227
|
+
else:
|
228
|
+
outcome_token_pool[
|
229
|
+
OutcomeStr(model.outcomes[wrapped_tokens.index(token)])
|
230
|
+
] = (
|
231
|
+
OutcomeToken(pool.totalValueLockedToken1)
|
232
|
+
if pool.totalValueLockedToken1 is not None
|
233
|
+
else OutcomeToken(0)
|
234
|
+
)
|
235
|
+
probability_map[
|
236
|
+
OutcomeStr(model.outcomes[wrapped_tokens.index(token)])
|
237
|
+
] = Probability(pool.token1Price.value)
|
238
|
+
|
239
|
+
for outcome in model.outcomes:
|
240
|
+
if outcome not in outcome_token_pool:
|
241
|
+
outcome_token_pool[outcome] = OutcomeToken(0)
|
242
|
+
logger.warning(
|
243
|
+
f"Outcome {outcome} not found in outcome_token_pool for market {self.seer_market.url}."
|
244
|
+
)
|
245
|
+
if outcome not in probability_map:
|
246
|
+
if INVALID_OUTCOME_LOWERCASE_IDENTIFIER not in outcome.lower():
|
247
|
+
raise PriceCalculationError(
|
248
|
+
f"Couldn't get probability for {outcome} for market {self.seer_market.url}."
|
249
|
+
)
|
250
|
+
else:
|
251
|
+
probability_map[outcome] = Probability(0)
|
252
|
+
return probability_map, outcome_token_pool
|
@@ -411,10 +411,14 @@ class SeerAgentMarket(AgentMarket):
|
|
411
411
|
must_have_prices: bool,
|
412
412
|
) -> t.Optional["SeerAgentMarket"]:
|
413
413
|
price_manager = PriceManager(seer_market=model, seer_subgraph=seer_subgraph)
|
414
|
-
|
415
|
-
probability_map = {}
|
414
|
+
wrapped_tokens = [Web3.to_checksum_address(i) for i in model.wrapped_tokens]
|
416
415
|
try:
|
417
|
-
|
416
|
+
(
|
417
|
+
probability_map,
|
418
|
+
outcome_token_pool,
|
419
|
+
) = price_manager.build_initial_probs_from_pool(
|
420
|
+
model=model, wrapped_tokens=wrapped_tokens
|
421
|
+
)
|
418
422
|
except PriceCalculationError as e:
|
419
423
|
logger.info(
|
420
424
|
f"Error when calculating probabilities for market {model.id.hex()} - {e}"
|
@@ -437,9 +441,9 @@ class SeerAgentMarket(AgentMarket):
|
|
437
441
|
condition_id=model.condition_id,
|
438
442
|
url=model.url,
|
439
443
|
close_time=model.close_time,
|
440
|
-
wrapped_tokens=
|
444
|
+
wrapped_tokens=wrapped_tokens,
|
441
445
|
fees=MarketFees.get_zero_fees(),
|
442
|
-
outcome_token_pool=
|
446
|
+
outcome_token_pool=outcome_token_pool,
|
443
447
|
outcomes_supply=model.outcomes_supply,
|
444
448
|
resolution=resolution,
|
445
449
|
volume=None,
|
@@ -633,9 +637,9 @@ class SeerAgentMarket(AgentMarket):
|
|
633
637
|
amount_wei=amount_wei,
|
634
638
|
web3=web3,
|
635
639
|
)
|
636
|
-
swap_pool_tx_hash = tx_receipt["transactionHash"]
|
640
|
+
swap_pool_tx_hash = tx_receipt["transactionHash"]
|
637
641
|
logger.info(f"TxHash is {swap_pool_tx_hash=}.")
|
638
|
-
return swap_pool_tx_hash
|
642
|
+
return swap_pool_tx_hash.hex()
|
639
643
|
|
640
644
|
def place_bet(
|
641
645
|
self,
|