prediction-market-agent-tooling 0.68.1__tar.gz → 0.69.1__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.68.1 → prediction_market_agent_tooling-0.69.1}/PKG-INFO +1 -1
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/deploy/agent.py +13 -2
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/deploy/betting_strategy.py +132 -29
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/jobs/omen/omen_jobs.py +14 -17
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/agent_market.py +11 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/markets.py +16 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/seer/data_models.py +40 -5
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/seer/seer.py +44 -8
- prediction_market_agent_tooling-0.69.1/prediction_market_agent_tooling/markets/seer/seer_api.py +28 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +68 -21
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/seer/subgraph_data_models.py +41 -4
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +17 -22
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/datetime_utc.py +14 -2
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/langfuse_client_utils.py +17 -5
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/tokens/auto_deposit.py +1 -1
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/pyproject.toml +1 -1
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/README.md +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/agentresultmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/debuggingcontract.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/erc1155.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/erc4626.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/erc721.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/gvp2_settlement.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/ownable.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/ownable_erc721.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/proxy.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/seer_gnosis_router.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/seer_market_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/abis/swapr_router.abi.json +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/chains.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/config.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/data_download/langfuse_data_downloader.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/deploy/constants.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/deploy/trade_interval.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/gtypes.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/jobs/__init__.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/jobs/jobs_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/loggers.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/logprobs_parser.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/base_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/blockchain_utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/categorize.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/data_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/market_fees.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/metaculus/api.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/metaculus/data_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/metaculus/metaculus.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/omen/cow_contracts.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/omen/data_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/omen/omen.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/omen/omen_constants.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/polymarket/clob_manager.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/polymarket/constants.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/polymarket/polymarket_contracts.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/polymarket/polymarket_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/seer/exceptions.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/seer/price_manager.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/seer/seer_contracts.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/markets/seer/swap_pool_handler.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/py.typed +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/_generic_value.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/balances.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/betting_strategies/utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/caches/db_cache.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/caches/inmemory_cache.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/caches/serializers.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/contract.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/costs.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/cow/cow_order.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/cow/models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/cow/semaphore.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/custom_exceptions.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/db/db_manager.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/google_utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/httpx_cached_client.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/image_gen/image_gen.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/is_invalid.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/langfuse_.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/omen/reality_accuracy.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/omen/sell_positions.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/perplexity/perplexity_client.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/perplexity/perplexity_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/perplexity/perplexity_search.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/relevant_news_analysis/data_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_analysis.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_cache.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/rephrase.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/safe.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/singleton.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/streamlit_user_login.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/tavily/tavily_models.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/tavily/tavily_search.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/tokens/main_token.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/tokens/slippage.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/tokens/token_utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/tokens/usd.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/transaction_cache.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/utils.py +0 -0
- {prediction_market_agent_tooling-0.68.1 → prediction_market_agent_tooling-0.69.1}/prediction_market_agent_tooling/tools/web3_utils.py +0 -0
@@ -630,7 +630,7 @@ class DeployableTraderAgent(DeployablePredictionAgent):
|
|
630
630
|
api_keys = APIKeys()
|
631
631
|
|
632
632
|
# Get the strategy to know how much it will bet.
|
633
|
-
strategy = self.
|
633
|
+
strategy = self.get_betting_strategy_supported(market)
|
634
634
|
# Have a little bandwidth after the bet.
|
635
635
|
min_required_balance_to_trade = strategy.maximum_possible_bet_amount * 1.01
|
636
636
|
|
@@ -658,13 +658,24 @@ class DeployableTraderAgent(DeployablePredictionAgent):
|
|
658
658
|
total_amount = self.get_total_amount_to_bet(market)
|
659
659
|
return CategoricalMaxAccuracyBettingStrategy(max_position_amount=total_amount)
|
660
660
|
|
661
|
+
def get_betting_strategy_supported(self, market: AgentMarket) -> BettingStrategy:
|
662
|
+
"""
|
663
|
+
Use this class internally to assert that the configured betting strategy works with the given market.
|
664
|
+
"""
|
665
|
+
strategy = self.get_betting_strategy(market=market)
|
666
|
+
if not strategy.is_market_supported(market):
|
667
|
+
raise ValueError(
|
668
|
+
f"Market {market.url} is not supported by the strategy {strategy}."
|
669
|
+
)
|
670
|
+
return strategy
|
671
|
+
|
661
672
|
def build_trades(
|
662
673
|
self,
|
663
674
|
market: AgentMarket,
|
664
675
|
answer: CategoricalProbabilisticAnswer,
|
665
676
|
existing_position: ExistingPosition | None,
|
666
677
|
) -> list[Trade]:
|
667
|
-
strategy = self.
|
678
|
+
strategy = self.get_betting_strategy_supported(market=market)
|
668
679
|
trades = strategy.calculate_trades(existing_position, answer, market)
|
669
680
|
return trades
|
670
681
|
|
@@ -16,7 +16,11 @@ from prediction_market_agent_tooling.gtypes import (
|
|
16
16
|
Probability,
|
17
17
|
)
|
18
18
|
from prediction_market_agent_tooling.loggers import logger
|
19
|
-
from prediction_market_agent_tooling.markets.agent_market import
|
19
|
+
from prediction_market_agent_tooling.markets.agent_market import (
|
20
|
+
AgentMarket,
|
21
|
+
MarketFees,
|
22
|
+
QuestionType,
|
23
|
+
)
|
20
24
|
from prediction_market_agent_tooling.markets.data_models import (
|
21
25
|
CategoricalProbabilisticAnswer,
|
22
26
|
ExistingPosition,
|
@@ -24,10 +28,12 @@ from prediction_market_agent_tooling.markets.data_models import (
|
|
24
28
|
Trade,
|
25
29
|
TradeType,
|
26
30
|
)
|
31
|
+
from prediction_market_agent_tooling.markets.markets import MarketType
|
27
32
|
from prediction_market_agent_tooling.markets.omen.omen import (
|
28
33
|
get_buy_outcome_token_amount,
|
29
34
|
)
|
30
35
|
from prediction_market_agent_tooling.tools.betting_strategies.kelly_criterion import (
|
36
|
+
KellyType,
|
31
37
|
get_kelly_bet_full,
|
32
38
|
get_kelly_bet_simplified,
|
33
39
|
get_kelly_bets_categorical_full,
|
@@ -45,9 +51,21 @@ class GuaranteedLossError(RuntimeError):
|
|
45
51
|
|
46
52
|
|
47
53
|
class BettingStrategy(ABC):
|
54
|
+
supported_question_types: set[QuestionType]
|
55
|
+
supported_market_types: set[MarketType]
|
56
|
+
|
48
57
|
def __init__(self, take_profit: bool = True) -> None:
|
49
58
|
self.take_profit = take_profit
|
50
59
|
|
60
|
+
def is_market_supported(self, market: AgentMarket) -> bool:
|
61
|
+
if market.question_type not in self.supported_question_types:
|
62
|
+
return False
|
63
|
+
|
64
|
+
if MarketType.from_market(market) not in self.supported_market_types:
|
65
|
+
return False
|
66
|
+
|
67
|
+
return True
|
68
|
+
|
51
69
|
@abstractmethod
|
52
70
|
def calculate_trades(
|
53
71
|
self,
|
@@ -251,6 +269,13 @@ class BettingStrategy(ABC):
|
|
251
269
|
|
252
270
|
|
253
271
|
class CategoricalMaxAccuracyBettingStrategy(BettingStrategy):
|
272
|
+
supported_question_types = {
|
273
|
+
QuestionType.BINARY,
|
274
|
+
QuestionType.CATEGORICAL,
|
275
|
+
QuestionType.SCALAR,
|
276
|
+
}
|
277
|
+
supported_market_types = {x for x in MarketType if x.is_trading_market}
|
278
|
+
|
254
279
|
def __init__(self, max_position_amount: USD, take_profit: bool = True):
|
255
280
|
super().__init__(take_profit=take_profit)
|
256
281
|
self.max_position_amount = max_position_amount
|
@@ -362,18 +387,20 @@ class MaxExpectedValueBettingStrategy(CategoricalMaxAccuracyBettingStrategy):
|
|
362
387
|
return f"MaxExpectedValueBettingStrategy(max_position_amount={self.max_position_amount}, take_profit={self.take_profit})"
|
363
388
|
|
364
389
|
|
365
|
-
class
|
390
|
+
class _BinaryKellyBettingStrategy(BettingStrategy):
|
391
|
+
supported_question_types = {QuestionType.BINARY}
|
392
|
+
|
366
393
|
def __init__(
|
367
394
|
self,
|
395
|
+
kelly_type: KellyType,
|
368
396
|
max_position_amount: USD,
|
369
397
|
max_price_impact: float | None = None,
|
370
398
|
take_profit: bool = True,
|
371
|
-
force_simplified_calculation: bool = False,
|
372
399
|
):
|
373
400
|
super().__init__(take_profit=take_profit)
|
401
|
+
self.kelly_type = kelly_type
|
374
402
|
self.max_position_amount = max_position_amount
|
375
403
|
self.max_price_impact = max_price_impact
|
376
|
-
self.force_simplified_calculation = force_simplified_calculation
|
377
404
|
|
378
405
|
@property
|
379
406
|
def maximum_possible_bet_amount(self) -> USD:
|
@@ -396,7 +423,7 @@ class BinaryKellyBettingStrategy(BettingStrategy):
|
|
396
423
|
else override_p_yes
|
397
424
|
)
|
398
425
|
|
399
|
-
if
|
426
|
+
if self.kelly_type == KellyType.SIMPLE:
|
400
427
|
kelly_bet = get_kelly_bet_simplified(
|
401
428
|
max_bet=market.get_usd_in_token(self.max_position_amount),
|
402
429
|
market_p_yes=market.probability_for_market_outcome(direction),
|
@@ -447,7 +474,6 @@ class BinaryKellyBettingStrategy(BettingStrategy):
|
|
447
474
|
# Adjust amount
|
448
475
|
max_price_impact_bet_amount = self.calculate_bet_amount_for_price_impact(
|
449
476
|
market,
|
450
|
-
kelly_bet.size,
|
451
477
|
direction=direction,
|
452
478
|
max_price_impact=self.max_price_impact,
|
453
479
|
)
|
@@ -492,7 +518,6 @@ class BinaryKellyBettingStrategy(BettingStrategy):
|
|
492
518
|
@staticmethod
|
493
519
|
def calculate_bet_amount_for_price_impact(
|
494
520
|
market: AgentMarket,
|
495
|
-
kelly_bet_size: CollateralToken,
|
496
521
|
direction: OutcomeStr,
|
497
522
|
max_price_impact: float,
|
498
523
|
) -> CollateralToken:
|
@@ -501,7 +526,7 @@ class BinaryKellyBettingStrategy(BettingStrategy):
|
|
501
526
|
) -> float:
|
502
527
|
outcome_idx = market.get_outcome_index(direction)
|
503
528
|
price_impact = (
|
504
|
-
|
529
|
+
_BinaryKellyBettingStrategy.calculate_price_impact_for_bet_amount(
|
505
530
|
outcome_idx=outcome_idx,
|
506
531
|
bet_amount=CollateralToken(bet_amount_collateral),
|
507
532
|
pool_balances=pool_balances,
|
@@ -512,20 +537,13 @@ class BinaryKellyBettingStrategy(BettingStrategy):
|
|
512
537
|
return abs(price_impact - max_price_impact)
|
513
538
|
|
514
539
|
if not market.outcome_token_pool:
|
515
|
-
|
540
|
+
raise ValueError(
|
516
541
|
"Market outcome_token_pool is None, cannot calculate bet amount"
|
517
542
|
)
|
518
|
-
return kelly_bet_size
|
519
|
-
|
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
543
|
|
526
|
-
pool_balances = [i.as_outcome_wei for i in
|
544
|
+
pool_balances = [i.as_outcome_wei for i in market.outcome_token_pool.values()]
|
527
545
|
# stay float for compatibility with `minimize_scalar`
|
528
|
-
total_pool_balance = sum([i.value for i in
|
546
|
+
total_pool_balance = sum([i.value for i in market.outcome_token_pool.values()])
|
529
547
|
|
530
548
|
# The bounds below have been found to work heuristically.
|
531
549
|
optimized_bet_amount = minimize_scalar(
|
@@ -538,10 +556,47 @@ class BinaryKellyBettingStrategy(BettingStrategy):
|
|
538
556
|
return CollateralToken(optimized_bet_amount.x)
|
539
557
|
|
540
558
|
def __repr__(self) -> str:
|
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}
|
559
|
+
return f"{self.__class__.__name__}(max_position_amount={self.max_position_amount}, max_price_impact={self.max_price_impact}, take_profit={self.take_profit})"
|
560
|
+
|
561
|
+
|
562
|
+
class SimpleBinaryKellyBettingStrategy(_BinaryKellyBettingStrategy):
|
563
|
+
supported_market_types = {x for x in MarketType if x.is_trading_market}
|
564
|
+
|
565
|
+
def __init__(
|
566
|
+
self,
|
567
|
+
max_position_amount: USD,
|
568
|
+
take_profit: bool = True,
|
569
|
+
):
|
570
|
+
super().__init__(
|
571
|
+
kelly_type=KellyType.SIMPLE,
|
572
|
+
max_position_amount=max_position_amount,
|
573
|
+
max_price_impact=None,
|
574
|
+
take_profit=take_profit,
|
575
|
+
)
|
576
|
+
|
577
|
+
|
578
|
+
class FullBinaryKellyBettingStrategy(_BinaryKellyBettingStrategy):
|
579
|
+
# Supports only OMEN because it uses closed-form formula derived from a binary FPMM.
|
580
|
+
supported_market_types = {MarketType.OMEN}
|
581
|
+
|
582
|
+
def __init__(
|
583
|
+
self,
|
584
|
+
max_position_amount: USD,
|
585
|
+
max_price_impact: float | None = None,
|
586
|
+
take_profit: bool = True,
|
587
|
+
):
|
588
|
+
super().__init__(
|
589
|
+
kelly_type=KellyType.FULL,
|
590
|
+
max_position_amount=max_position_amount,
|
591
|
+
max_price_impact=max_price_impact,
|
592
|
+
take_profit=take_profit,
|
593
|
+
)
|
542
594
|
|
543
595
|
|
544
596
|
class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
597
|
+
supported_question_types = {QuestionType.BINARY}
|
598
|
+
supported_market_types = {MarketType.OMEN}
|
599
|
+
|
545
600
|
def __init__(
|
546
601
|
self,
|
547
602
|
max_position_amount: USD,
|
@@ -573,7 +628,7 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
573
628
|
# We ignore the direction nudge given by Kelly, hence we assume we have a perfect prediction.
|
574
629
|
estimated_p_yes = 1.0
|
575
630
|
|
576
|
-
kelly_bet =
|
631
|
+
kelly_bet = FullBinaryKellyBettingStrategy(
|
577
632
|
max_position_amount=self.max_position_amount
|
578
633
|
).get_kelly_bet(
|
579
634
|
market=market,
|
@@ -601,24 +656,27 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
601
656
|
return f"{self.__class__.__name__}(max_position_amount={self.max_position_amount}, take_profit={self.take_profit})"
|
602
657
|
|
603
658
|
|
604
|
-
class
|
659
|
+
class _CategoricalKellyBettingStrategy(BettingStrategy):
|
660
|
+
supported_question_types = {QuestionType.BINARY, QuestionType.CATEGORICAL}
|
661
|
+
supported_market_types = {x for x in MarketType if x.is_trading_market}
|
662
|
+
|
605
663
|
def __init__(
|
606
664
|
self,
|
665
|
+
kelly_type: KellyType,
|
607
666
|
max_position_amount: USD,
|
608
667
|
max_price_impact: float | None,
|
609
668
|
allow_multiple_bets: bool,
|
610
669
|
allow_shorting: bool,
|
611
670
|
multicategorical: bool,
|
612
671
|
take_profit: bool = True,
|
613
|
-
force_simplified_calculation: bool = False,
|
614
672
|
):
|
615
673
|
super().__init__(take_profit=take_profit)
|
674
|
+
self.kelly_type = kelly_type
|
616
675
|
self.max_position_amount = max_position_amount
|
617
676
|
self.max_price_impact = max_price_impact
|
618
677
|
self.allow_multiple_bets = allow_multiple_bets
|
619
678
|
self.allow_shorting = allow_shorting
|
620
679
|
self.multicategorical = multicategorical
|
621
|
-
self.force_simplified_calculation = force_simplified_calculation
|
622
680
|
|
623
681
|
@property
|
624
682
|
def maximum_possible_bet_amount(self) -> USD:
|
@@ -632,7 +690,7 @@ class CategoricalKellyBettingStrategy(BettingStrategy):
|
|
632
690
|
) -> list[CategoricalKellyBet]:
|
633
691
|
max_bet = market.get_usd_in_token(max_bet_amount)
|
634
692
|
|
635
|
-
if
|
693
|
+
if self.kelly_type == KellyType.SIMPLE:
|
636
694
|
kelly_bets = get_kelly_bets_categorical_simplified(
|
637
695
|
market_probabilities=[market.probabilities[o] for o in market.outcomes],
|
638
696
|
estimated_probabilities=[
|
@@ -647,8 +705,8 @@ class CategoricalKellyBettingStrategy(BettingStrategy):
|
|
647
705
|
|
648
706
|
else:
|
649
707
|
kelly_bets = get_kelly_bets_categorical_full(
|
650
|
-
|
651
|
-
market.
|
708
|
+
market_probabilities=[
|
709
|
+
market.probability_for_market_outcome(o) for o in market.outcomes
|
652
710
|
],
|
653
711
|
estimated_probabilities=[
|
654
712
|
answer.probability_for_market_outcome(o) for o in market.outcomes
|
@@ -659,6 +717,11 @@ class CategoricalKellyBettingStrategy(BettingStrategy):
|
|
659
717
|
allow_multiple_bets=self.allow_multiple_bets,
|
660
718
|
allow_shorting=self.allow_shorting,
|
661
719
|
multicategorical=self.multicategorical,
|
720
|
+
get_buy_token_amount=lambda bet_amount, outcome_index: check_not_none(
|
721
|
+
market.get_buy_token_amount(
|
722
|
+
bet_amount, market.get_outcome_str(outcome_index)
|
723
|
+
)
|
724
|
+
),
|
662
725
|
)
|
663
726
|
|
664
727
|
return kelly_bets
|
@@ -689,9 +752,8 @@ class CategoricalKellyBettingStrategy(BettingStrategy):
|
|
689
752
|
if self.max_price_impact:
|
690
753
|
# Adjust amount
|
691
754
|
max_price_impact_bet_amount = (
|
692
|
-
|
755
|
+
_BinaryKellyBettingStrategy.calculate_bet_amount_for_price_impact(
|
693
756
|
market,
|
694
|
-
best_kelly_bet.size,
|
695
757
|
direction=market.get_outcome_str(best_kelly_bet.index),
|
696
758
|
max_price_impact=self.max_price_impact,
|
697
759
|
)
|
@@ -712,4 +774,45 @@ class CategoricalKellyBettingStrategy(BettingStrategy):
|
|
712
774
|
return trades
|
713
775
|
|
714
776
|
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}
|
777
|
+
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})"
|
778
|
+
|
779
|
+
|
780
|
+
class SimpleCategoricalKellyBettingStrategy(_CategoricalKellyBettingStrategy):
|
781
|
+
def __init__(
|
782
|
+
self,
|
783
|
+
max_position_amount: USD,
|
784
|
+
allow_multiple_bets: bool,
|
785
|
+
allow_shorting: bool,
|
786
|
+
multicategorical: bool,
|
787
|
+
take_profit: bool = True,
|
788
|
+
):
|
789
|
+
super().__init__(
|
790
|
+
kelly_type=KellyType.SIMPLE,
|
791
|
+
max_position_amount=max_position_amount,
|
792
|
+
max_price_impact=None,
|
793
|
+
allow_multiple_bets=allow_multiple_bets,
|
794
|
+
allow_shorting=allow_shorting,
|
795
|
+
multicategorical=multicategorical,
|
796
|
+
take_profit=take_profit,
|
797
|
+
)
|
798
|
+
|
799
|
+
|
800
|
+
class FullCategoricalKellyBettingStrategy(_CategoricalKellyBettingStrategy):
|
801
|
+
def __init__(
|
802
|
+
self,
|
803
|
+
max_position_amount: USD,
|
804
|
+
max_price_impact: float | None,
|
805
|
+
allow_multiple_bets: bool,
|
806
|
+
allow_shorting: bool,
|
807
|
+
multicategorical: bool,
|
808
|
+
take_profit: bool = True,
|
809
|
+
):
|
810
|
+
super().__init__(
|
811
|
+
kelly_type=KellyType.FULL,
|
812
|
+
max_position_amount=max_position_amount,
|
813
|
+
max_price_impact=max_price_impact,
|
814
|
+
allow_multiple_bets=allow_multiple_bets,
|
815
|
+
allow_shorting=allow_shorting,
|
816
|
+
multicategorical=multicategorical,
|
817
|
+
take_profit=take_profit,
|
818
|
+
)
|
@@ -1,10 +1,6 @@
|
|
1
1
|
import typing as t
|
2
2
|
|
3
3
|
from prediction_market_agent_tooling.config import APIKeys
|
4
|
-
from prediction_market_agent_tooling.deploy.betting_strategy import (
|
5
|
-
BinaryKellyBettingStrategy,
|
6
|
-
TradeType,
|
7
|
-
)
|
8
4
|
from prediction_market_agent_tooling.gtypes import USD
|
9
5
|
from prediction_market_agent_tooling.jobs.jobs_models import JobAgentMarket
|
10
6
|
from prediction_market_agent_tooling.markets.agent_market import ProcessedMarket
|
@@ -92,20 +88,21 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
92
88
|
return processed_traded_market
|
93
89
|
|
94
90
|
def get_job_trade(self, max_bond: USD, result: str) -> Trade:
|
91
|
+
raise NotImplementedError("TODO: Refactor to avoid circular imports.")
|
95
92
|
# 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 =
|
97
|
-
required_trades = strategy.calculate_trades(
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
)
|
102
|
-
assert (
|
103
|
-
|
104
|
-
), f"Shouldn't process same job twice: {required_trades}"
|
105
|
-
trade = required_trades[0]
|
106
|
-
assert trade.trade_type == TradeType.BUY, "Should only buy on job markets."
|
107
|
-
assert trade.outcome, "Should buy only YES on job markets."
|
108
|
-
return required_trades[0]
|
93
|
+
# strategy = FullBinaryKellyBettingStrategy(max_position_amount=max_bond)
|
94
|
+
# required_trades = strategy.calculate_trades(
|
95
|
+
# existing_position=None,
|
96
|
+
# answer=self.get_job_answer(result),
|
97
|
+
# market=self,
|
98
|
+
# )
|
99
|
+
# assert (
|
100
|
+
# len(required_trades) == 1
|
101
|
+
# ), f"Shouldn't process same job twice: {required_trades}"
|
102
|
+
# trade = required_trades[0]
|
103
|
+
# assert trade.trade_type == TradeType.BUY, "Should only buy on job markets."
|
104
|
+
# assert trade.outcome, "Should buy only YES on job markets."
|
105
|
+
# return required_trades[0]
|
109
106
|
|
110
107
|
@staticmethod
|
111
108
|
def from_omen_market(market: OmenMarket) -> "OmenJobAgentMarket":
|
@@ -188,6 +188,17 @@ class AgentMarket(BaseModel):
|
|
188
188
|
f"Could not find probability for market outcome {market_outcome}"
|
189
189
|
)
|
190
190
|
|
191
|
+
@property
|
192
|
+
def question_type(self) -> QuestionType:
|
193
|
+
if self.is_binary:
|
194
|
+
return QuestionType.BINARY
|
195
|
+
|
196
|
+
elif self.is_scalar:
|
197
|
+
return QuestionType.SCALAR
|
198
|
+
|
199
|
+
else:
|
200
|
+
return QuestionType.CATEGORICAL
|
201
|
+
|
191
202
|
@property
|
192
203
|
def is_binary(self) -> bool:
|
193
204
|
# 3 outcomes can also be binary if 3rd outcome is invalid (Seer)
|
@@ -31,6 +31,10 @@ class MarketType(str, Enum):
|
|
31
31
|
METACULUS = "metaculus"
|
32
32
|
SEER = "seer"
|
33
33
|
|
34
|
+
@staticmethod
|
35
|
+
def from_market(market: AgentMarket) -> "MarketType":
|
36
|
+
return AGENT_MARKET_TO_MARKET_TYPE[type(market)]
|
37
|
+
|
34
38
|
@property
|
35
39
|
def market_class(self) -> type[AgentMarket]:
|
36
40
|
if self not in MARKET_TYPE_TO_AGENT_MARKET:
|
@@ -43,6 +47,15 @@ class MarketType(str, Enum):
|
|
43
47
|
raise ValueError(f"Unknown market type: {self}")
|
44
48
|
return JOB_MARKET_TYPE_TO_JOB_AGENT_MARKET[self]
|
45
49
|
|
50
|
+
@property
|
51
|
+
def is_trading_market(self) -> bool:
|
52
|
+
return self in [
|
53
|
+
MarketType.OMEN,
|
54
|
+
MarketType.POLYMARKET,
|
55
|
+
MarketType.SEER,
|
56
|
+
MarketType.MANIFOLD,
|
57
|
+
]
|
58
|
+
|
46
59
|
@property
|
47
60
|
def is_blockchain_market(self) -> bool:
|
48
61
|
return self in [MarketType.OMEN, MarketType.POLYMARKET, MarketType.SEER]
|
@@ -56,6 +69,9 @@ MARKET_TYPE_TO_AGENT_MARKET: dict[MarketType, type[AgentMarket]] = {
|
|
56
69
|
MarketType.SEER: SeerAgentMarket,
|
57
70
|
}
|
58
71
|
|
72
|
+
AGENT_MARKET_TO_MARKET_TYPE: dict[type[AgentMarket], MarketType] = {
|
73
|
+
v: k for k, v in MARKET_TYPE_TO_AGENT_MARKET.items()
|
74
|
+
}
|
59
75
|
|
60
76
|
JOB_MARKET_TYPE_TO_JOB_AGENT_MARKET: dict[MarketType, type[JobAgentMarket]] = {
|
61
77
|
MarketType.OMEN: OmenJobAgentMarket,
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import typing as t
|
2
2
|
from datetime import timedelta
|
3
|
+
from enum import Enum
|
3
4
|
from typing import Annotated
|
4
5
|
from urllib.parse import urljoin
|
5
6
|
|
@@ -139,11 +140,6 @@ class SeerMarket(BaseModel):
|
|
139
140
|
for token in self.wrapped_tokens
|
140
141
|
]
|
141
142
|
|
142
|
-
@property
|
143
|
-
def is_binary(self) -> bool:
|
144
|
-
# 3 because Seer has also third, `Invalid` outcome.
|
145
|
-
return len(self.outcomes) == 3
|
146
|
-
|
147
143
|
@property
|
148
144
|
def collateral_token_contract_address_checksummed(self) -> ChecksumAddress:
|
149
145
|
return Web3.to_checksum_address(self.collateral_token)
|
@@ -188,3 +184,42 @@ class ExactInputSingleParams(BaseModel):
|
|
188
184
|
limit_sqrt_price: Wei = Field(
|
189
185
|
alias="limitSqrtPrice", default_factory=lambda: Wei(0)
|
190
186
|
) # 0 for convenience, we also don't expect major price shifts
|
187
|
+
|
188
|
+
|
189
|
+
class SeerTransactionType(str, Enum):
|
190
|
+
SWAP = "swap"
|
191
|
+
SPLIT = "split"
|
192
|
+
|
193
|
+
|
194
|
+
class SeerTransaction(BaseModel):
|
195
|
+
model_config = ConfigDict(populate_by_name=True)
|
196
|
+
|
197
|
+
market_name: str = Field(alias="marketName")
|
198
|
+
market_id: HexBytes = Field(alias="marketId")
|
199
|
+
type: SeerTransactionType
|
200
|
+
block_number: int = Field(alias="blockNumber")
|
201
|
+
transaction_hash: HexBytes = Field(alias="transactionHash")
|
202
|
+
collateral: HexAddress
|
203
|
+
collateral_symbol: str = Field(alias="collateralSymbol")
|
204
|
+
|
205
|
+
token_in: HexAddress = Field(alias="tokenIn")
|
206
|
+
token_out: HexAddress = Field(alias="tokenOut")
|
207
|
+
amount_in: Wei = Field(alias="amountIn")
|
208
|
+
amount_out: Wei = Field(alias="amountOut")
|
209
|
+
token_in_symbol: str = Field(alias="tokenInSymbol")
|
210
|
+
token_out_symbol: str = Field(alias="tokenOutSymbol")
|
211
|
+
timestamp: int | None = None
|
212
|
+
|
213
|
+
amount: Wei | None = None
|
214
|
+
|
215
|
+
@property
|
216
|
+
def timestamp_dt(self) -> DatetimeUTC | None:
|
217
|
+
return DatetimeUTC.to_datetime_utc(self.timestamp) if self.timestamp else None
|
218
|
+
|
219
|
+
@property
|
220
|
+
def token_in_checksum(self) -> ChecksumAddress:
|
221
|
+
return Web3.to_checksum_address(self.token_in)
|
222
|
+
|
223
|
+
@property
|
224
|
+
def token_out_checksum(self) -> ChecksumAddress:
|
225
|
+
return Web3.to_checksum_address(self.token_out)
|
@@ -35,6 +35,7 @@ from prediction_market_agent_tooling.markets.blockchain_utils import store_trade
|
|
35
35
|
from prediction_market_agent_tooling.markets.data_models import (
|
36
36
|
ExistingPosition,
|
37
37
|
Resolution,
|
38
|
+
ResolvedBet,
|
38
39
|
)
|
39
40
|
from prediction_market_agent_tooling.markets.market_fees import MarketFees
|
40
41
|
from prediction_market_agent_tooling.markets.omen.omen import (
|
@@ -56,6 +57,7 @@ from prediction_market_agent_tooling.markets.seer.exceptions import (
|
|
56
57
|
PriceCalculationError,
|
57
58
|
)
|
58
59
|
from prediction_market_agent_tooling.markets.seer.price_manager import PriceManager
|
60
|
+
from prediction_market_agent_tooling.markets.seer.seer_api import get_seer_transactions
|
59
61
|
from prediction_market_agent_tooling.markets.seer.seer_contracts import (
|
60
62
|
GnosisRouter,
|
61
63
|
SeerMarketFactory,
|
@@ -81,7 +83,6 @@ from prediction_market_agent_tooling.tools.cow.cow_order import (
|
|
81
83
|
OrderStatusError,
|
82
84
|
get_orders_by_owner,
|
83
85
|
get_trades_by_order_uid,
|
84
|
-
get_trades_by_owner,
|
85
86
|
swap_tokens_waiting,
|
86
87
|
wait_for_order_completion,
|
87
88
|
)
|
@@ -272,10 +273,12 @@ class SeerAgentMarket(AgentMarket):
|
|
272
273
|
"""
|
273
274
|
We filter the markets using previous trades by the user so that we don't have to process all Seer markets.
|
274
275
|
"""
|
275
|
-
trades_by_user =
|
276
|
+
trades_by_user = get_seer_transactions(
|
277
|
+
api_keys.bet_from_address, RPCConfig().CHAIN_ID
|
278
|
+
)
|
276
279
|
|
277
|
-
traded_tokens = {t.
|
278
|
-
[t.
|
280
|
+
traded_tokens = {t.token_in_checksum for t in trades_by_user}.union(
|
281
|
+
[t.token_out_checksum for t in trades_by_user]
|
279
282
|
)
|
280
283
|
filtered_markets: list[SeerMarket] = []
|
281
284
|
for market in markets:
|
@@ -313,19 +316,43 @@ class SeerAgentMarket(AgentMarket):
|
|
313
316
|
for market in filtered_markets
|
314
317
|
if market.is_redeemable(owner=api_keys.bet_from_address, web3=web3)
|
315
318
|
]
|
319
|
+
logger.info(f"Got {len(markets_to_redeem)} markets to redeem on Seer.")
|
316
320
|
|
317
321
|
gnosis_router = GnosisRouter()
|
318
322
|
for market in markets_to_redeem:
|
319
323
|
try:
|
324
|
+
# GnosisRouter needs approval to use our outcome tokens
|
325
|
+
for i, token in enumerate(market.wrapped_tokens):
|
326
|
+
ContractERC20OnGnosisChain(
|
327
|
+
address=Web3.to_checksum_address(token)
|
328
|
+
).approve(
|
329
|
+
api_keys,
|
330
|
+
for_address=gnosis_router.address,
|
331
|
+
amount_wei=market_balances[market.id][i].as_wei,
|
332
|
+
web3=web3,
|
333
|
+
)
|
334
|
+
|
335
|
+
# We can only ask for redeem of outcome tokens on correct outcomes
|
336
|
+
# TODO: Implement more complex use-cases: https://github.com/gnosis/prediction-market-agent-tooling/issues/850
|
337
|
+
amounts_to_redeem = [
|
338
|
+
(amount if numerator > 0 else OutcomeWei(0))
|
339
|
+
for amount, numerator in zip(
|
340
|
+
market_balances[market.id], market.payout_numerators
|
341
|
+
)
|
342
|
+
]
|
343
|
+
|
344
|
+
# Redeem!
|
320
345
|
params = RedeemParams(
|
321
346
|
market=Web3.to_checksum_address(market.id),
|
322
347
|
outcome_indices=list(range(len(market.payout_numerators))),
|
323
|
-
amounts=
|
348
|
+
amounts=amounts_to_redeem,
|
324
349
|
)
|
325
350
|
gnosis_router.redeem_to_base(api_keys, params=params, web3=web3)
|
326
|
-
logger.info(f"Redeemed market {market.
|
327
|
-
except Exception
|
328
|
-
logger.
|
351
|
+
logger.info(f"Redeemed market {market.url}.")
|
352
|
+
except Exception:
|
353
|
+
logger.exception(
|
354
|
+
f"Failed to redeem market {market.url}, {market.outcomes}, with amounts {market_balances[market.id]} and payout numerators {market.payout_numerators}, and wrapped tokens {market.wrapped_tokens}."
|
355
|
+
)
|
329
356
|
|
330
357
|
# GnosisRouter withdraws sDai into wxDAI/xDai on its own, so no auto-withdraw needed by us.
|
331
358
|
|
@@ -464,6 +491,15 @@ class SeerAgentMarket(AgentMarket):
|
|
464
491
|
|
465
492
|
return market
|
466
493
|
|
494
|
+
@staticmethod
|
495
|
+
def get_resolved_bets_made_since(
|
496
|
+
better_address: ChecksumAddress,
|
497
|
+
start_time: DatetimeUTC,
|
498
|
+
end_time: DatetimeUTC | None,
|
499
|
+
) -> list[ResolvedBet]:
|
500
|
+
# TODO: https://github.com/gnosis/prediction-market-agent-tooling/issues/841
|
501
|
+
raise NotImplementedError()
|
502
|
+
|
467
503
|
@staticmethod
|
468
504
|
def get_markets(
|
469
505
|
limit: int,
|
prediction_market_agent_tooling-0.69.1/prediction_market_agent_tooling/markets/seer/seer_api.py
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
import httpx
|
2
|
+
|
3
|
+
from prediction_market_agent_tooling.gtypes import ChainID, ChecksumAddress
|
4
|
+
from prediction_market_agent_tooling.markets.seer.data_models import SeerTransaction
|
5
|
+
from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC
|
6
|
+
from prediction_market_agent_tooling.tools.utils import to_int_timestamp, utcnow
|
7
|
+
|
8
|
+
|
9
|
+
def get_seer_transactions(
|
10
|
+
account: ChecksumAddress,
|
11
|
+
chain_id: ChainID,
|
12
|
+
start_time: DatetimeUTC | None = None,
|
13
|
+
end_time: DatetimeUTC | None = None,
|
14
|
+
timeout: int = 60, # The endpoint is pretty slow to respond atm.
|
15
|
+
) -> list[SeerTransaction]:
|
16
|
+
url = "https://app.seer.pm/.netlify/functions/get-transactions"
|
17
|
+
params: dict[str, str | int] = {
|
18
|
+
"account": account,
|
19
|
+
"chainId": chain_id,
|
20
|
+
"startTime": to_int_timestamp(start_time) if start_time else 0,
|
21
|
+
"endTime": to_int_timestamp(end_time if end_time else utcnow()),
|
22
|
+
}
|
23
|
+
response = httpx.get(url, params=params, timeout=timeout)
|
24
|
+
response.raise_for_status()
|
25
|
+
response_json = response.json()
|
26
|
+
|
27
|
+
transactions = [SeerTransaction.model_validate(tx) for tx in response_json]
|
28
|
+
return transactions
|