prediction-market-agent-tooling 0.66.0.dev791__tar.gz → 0.66.2__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.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/PKG-INFO +2 -2
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/deploy/agent.py +3 -1
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/deploy/betting_strategy.py +98 -15
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/jobs/omen/omen_jobs.py +1 -1
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/data_models.py +1 -1
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/metaculus/data_models.py +3 -3
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/omen/cow_contracts.py +5 -1
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/omen/data_models.py +4 -2
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/omen/omen.py +2 -2
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/omen/omen_constants.py +5 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/seer/seer.py +20 -16
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/cow/cow_order.py +14 -6
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/cow/models.py +8 -0
- prediction_market_agent_tooling-0.66.2/prediction_market_agent_tooling/tools/cow/semaphore.py +101 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/pyproject.toml +2 -2
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/README.md +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/agentresultmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/debuggingcontract.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/erc4626.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/erc721.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/gvp2_settlement.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/ownable.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/ownable_erc721.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/proxy.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/seer_gnosis_router.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/seer_market_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/abis/swapr_router.abi.json +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/chains.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/config.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/data_download/langfuse_data_downloader.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/deploy/constants.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/deploy/trade_interval.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/gtypes.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/jobs/__init__.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/jobs/jobs_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/loggers.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/logprobs_parser.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/agent_market.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/base_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/blockchain_utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/categorize.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/market_fees.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/markets.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/metaculus/api.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/metaculus/metaculus.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/seer/data_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/seer/exceptions.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/seer/price_manager.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/seer/seer_contracts.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/seer/subgraph_data_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/markets/seer/swap_pool_handler.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/py.typed +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/_generic_value.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/balances.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/betting_strategies/utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/caches/db_cache.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/caches/inmemory_cache.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/caches/serializers.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/contract.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/costs.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/custom_exceptions.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/datetime_utc.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/db/db_manager.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/google_utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/httpx_cached_client.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/image_gen/image_gen.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/is_invalid.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/langfuse_.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/langfuse_client_utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/omen/reality_accuracy.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/omen/sell_positions.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/perplexity/perplexity_client.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/perplexity/perplexity_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/perplexity/perplexity_search.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/relevant_news_analysis/data_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_analysis.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_cache.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/safe.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/singleton.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/streamlit_user_login.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/tavily/tavily_models.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/tavily/tavily_search.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/tokens/auto_deposit.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/tokens/main_token.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/tokens/token_utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/tokens/usd.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/transaction_cache.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/utils.py +0 -0
- {prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/prediction_market_agent_tooling/tools/web3_utils.py +0 -0
{prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/PKG-INFO
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: prediction-market-agent-tooling
|
3
|
-
Version: 0.66.
|
3
|
+
Version: 0.66.2
|
4
4
|
Summary: Tools to benchmark, deploy and monitor prediction market agents.
|
5
5
|
Author: Gnosis
|
6
6
|
Requires-Python: >=3.10,<3.13
|
@@ -14,7 +14,7 @@ Provides-Extra: openai
|
|
14
14
|
Provides-Extra: optuna
|
15
15
|
Requires-Dist: autoflake (>=2.2.1,<3.0.0)
|
16
16
|
Requires-Dist: base58 (>=1.0.2,<2.0)
|
17
|
-
Requires-Dist: cowdao-cowpy
|
17
|
+
Requires-Dist: cowdao-cowpy (==1.0.0rc5)
|
18
18
|
Requires-Dist: cron-validator (>=1.0.8,<2.0.0)
|
19
19
|
Requires-Dist: eth-account (>=0.8.0,<0.12.0)
|
20
20
|
Requires-Dist: eth-keys (>=0.6.1,<0.7.0)
|
@@ -571,7 +571,9 @@ class DeployableTraderAgent(DeployablePredictionAgent):
|
|
571
571
|
Given the market and prediction, agent uses this method to calculate optimal outcome and bet size.
|
572
572
|
"""
|
573
573
|
total_amount = self.get_total_amount_to_bet(market)
|
574
|
-
return MultiCategoricalMaxAccuracyBettingStrategy(
|
574
|
+
return MultiCategoricalMaxAccuracyBettingStrategy(
|
575
|
+
max_position_amount=total_amount
|
576
|
+
)
|
575
577
|
|
576
578
|
def build_trades(
|
577
579
|
self,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from abc import ABC, abstractmethod
|
2
2
|
from typing import Sequence
|
3
3
|
|
4
|
+
import numpy as np
|
4
5
|
from scipy.optimize import minimize_scalar
|
5
6
|
|
6
7
|
from prediction_market_agent_tooling.benchmark.utils import get_most_probable_outcome
|
@@ -94,6 +95,76 @@ class BettingStrategy(ABC):
|
|
94
95
|
)
|
95
96
|
return trades
|
96
97
|
|
98
|
+
@staticmethod
|
99
|
+
def cap_to_profitable_bet_amount(
|
100
|
+
market: AgentMarket,
|
101
|
+
bet_amount: USD,
|
102
|
+
outcome: OutcomeStr,
|
103
|
+
iters: int = 10,
|
104
|
+
) -> USD:
|
105
|
+
"""
|
106
|
+
Use a binary search (tree-based search) to efficiently find the largest profitable bet amount.
|
107
|
+
"""
|
108
|
+
# First, try it with the desired amount right away.
|
109
|
+
if (
|
110
|
+
market.get_in_usd(
|
111
|
+
check_not_none(
|
112
|
+
market.get_buy_token_amount(bet_amount, outcome)
|
113
|
+
).as_token
|
114
|
+
)
|
115
|
+
> bet_amount
|
116
|
+
):
|
117
|
+
return bet_amount
|
118
|
+
|
119
|
+
# If it wasn't profitable, try binary search to find the highest, but profitable, amount.
|
120
|
+
lower = USD(0)
|
121
|
+
# It doesn't make sense to try to bet more than the liquidity itself, so override it as maximal value if it's lower.
|
122
|
+
upper = min(bet_amount, market.get_in_usd(market.get_liquidity()))
|
123
|
+
best_profitable = USD(0)
|
124
|
+
|
125
|
+
for _ in range(iters):
|
126
|
+
mid = (lower + upper) / 2
|
127
|
+
potential_outcome_value = market.get_in_usd(
|
128
|
+
check_not_none(market.get_buy_token_amount(mid, outcome)).as_token
|
129
|
+
)
|
130
|
+
|
131
|
+
if potential_outcome_value > mid:
|
132
|
+
# Profitable, try higher
|
133
|
+
best_profitable = mid
|
134
|
+
lower = mid
|
135
|
+
|
136
|
+
else:
|
137
|
+
# Not profitable, try lower
|
138
|
+
upper = mid
|
139
|
+
|
140
|
+
# If the search interval is very small, break early
|
141
|
+
if float(upper - lower) < 1e-8:
|
142
|
+
break
|
143
|
+
|
144
|
+
if np.isclose(best_profitable.value, 0):
|
145
|
+
best_profitable = USD(0)
|
146
|
+
|
147
|
+
return best_profitable
|
148
|
+
|
149
|
+
@staticmethod
|
150
|
+
def cap_to_profitable_position(
|
151
|
+
market: AgentMarket,
|
152
|
+
existing_position: USD,
|
153
|
+
wanted_position: USD,
|
154
|
+
outcome_to_bet_on: OutcomeStr,
|
155
|
+
) -> USD:
|
156
|
+
# If the wanted position is lower, it means the agent is gonna sell and that's profitable always.
|
157
|
+
if wanted_position > existing_position:
|
158
|
+
difference = wanted_position - existing_position
|
159
|
+
# Cap the difference we would like to buy to a profitable one.
|
160
|
+
capped_difference = BettingStrategy.cap_to_profitable_bet_amount(
|
161
|
+
market, difference, outcome_to_bet_on
|
162
|
+
)
|
163
|
+
# Lowered the actual wanted position such that it remains profitable.
|
164
|
+
wanted_position = existing_position + capped_difference
|
165
|
+
|
166
|
+
return wanted_position
|
167
|
+
|
97
168
|
def _build_rebalance_trades_from_positions(
|
98
169
|
self,
|
99
170
|
existing_position: ExistingPosition | None,
|
@@ -160,12 +231,12 @@ class BettingStrategy(ABC):
|
|
160
231
|
|
161
232
|
|
162
233
|
class MultiCategoricalMaxAccuracyBettingStrategy(BettingStrategy):
|
163
|
-
def __init__(self,
|
164
|
-
self.
|
234
|
+
def __init__(self, max_position_amount: USD):
|
235
|
+
self.max_position_amount = max_position_amount
|
165
236
|
|
166
237
|
@property
|
167
238
|
def maximum_possible_bet_amount(self) -> USD:
|
168
|
-
return self.
|
239
|
+
return self.max_position_amount
|
169
240
|
|
170
241
|
@staticmethod
|
171
242
|
def calculate_direction(
|
@@ -196,11 +267,23 @@ class MultiCategoricalMaxAccuracyBettingStrategy(BettingStrategy):
|
|
196
267
|
market: AgentMarket,
|
197
268
|
) -> list[Trade]:
|
198
269
|
"""We place bet on only one outcome."""
|
199
|
-
|
200
270
|
outcome_to_bet_on = self.calculate_direction(market, answer)
|
201
271
|
|
272
|
+
# Will be lowered if the amount that we would need to buy would be unprofitable.
|
273
|
+
actual_wanted_position = BettingStrategy.cap_to_profitable_position(
|
274
|
+
market,
|
275
|
+
(
|
276
|
+
existing_position.amounts_current.get(outcome_to_bet_on, USD(0))
|
277
|
+
if existing_position
|
278
|
+
else USD(0)
|
279
|
+
),
|
280
|
+
self.max_position_amount,
|
281
|
+
outcome_to_bet_on,
|
282
|
+
)
|
283
|
+
|
202
284
|
target_position = Position(
|
203
|
-
market_id=market.id,
|
285
|
+
market_id=market.id,
|
286
|
+
amounts_current={outcome_to_bet_on: actual_wanted_position},
|
204
287
|
)
|
205
288
|
trades = self._build_rebalance_trades_from_positions(
|
206
289
|
existing_position=existing_position,
|
@@ -253,13 +336,13 @@ class MaxExpectedValueBettingStrategy(MultiCategoricalMaxAccuracyBettingStrategy
|
|
253
336
|
|
254
337
|
|
255
338
|
class KellyBettingStrategy(BettingStrategy):
|
256
|
-
def __init__(self,
|
257
|
-
self.
|
339
|
+
def __init__(self, max_position_amount: USD, max_price_impact: float | None = None):
|
340
|
+
self.max_position_amount = max_position_amount
|
258
341
|
self.max_price_impact = max_price_impact
|
259
342
|
|
260
343
|
@property
|
261
344
|
def maximum_possible_bet_amount(self) -> USD:
|
262
|
-
return self.
|
345
|
+
return self.max_position_amount
|
263
346
|
|
264
347
|
@staticmethod
|
265
348
|
def get_kelly_bet(
|
@@ -321,7 +404,7 @@ class KellyBettingStrategy(BettingStrategy):
|
|
321
404
|
|
322
405
|
kelly_bet = self.get_kelly_bet(
|
323
406
|
market=market,
|
324
|
-
max_bet_amount=self.
|
407
|
+
max_bet_amount=self.max_position_amount,
|
325
408
|
direction=direction,
|
326
409
|
other_direction=other_direction,
|
327
410
|
answer=answer,
|
@@ -405,16 +488,16 @@ class KellyBettingStrategy(BettingStrategy):
|
|
405
488
|
return CollateralToken(optimized_bet_amount.x)
|
406
489
|
|
407
490
|
def __repr__(self) -> str:
|
408
|
-
return f"{self.__class__.__name__}(max_bet_amount={self.
|
491
|
+
return f"{self.__class__.__name__}(max_bet_amount={self.max_position_amount}, max_price_impact={self.max_price_impact})"
|
409
492
|
|
410
493
|
|
411
494
|
class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
412
|
-
def __init__(self,
|
413
|
-
self.
|
495
|
+
def __init__(self, max_position_amount: USD):
|
496
|
+
self.max_position_amount = max_position_amount
|
414
497
|
|
415
498
|
@property
|
416
499
|
def maximum_possible_bet_amount(self) -> USD:
|
417
|
-
return self.
|
500
|
+
return self.max_position_amount
|
418
501
|
|
419
502
|
def adjust_bet_amount(
|
420
503
|
self, existing_position: ExistingPosition | None, market: AgentMarket
|
@@ -422,7 +505,7 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
422
505
|
existing_position_total_amount = (
|
423
506
|
existing_position.total_amount_current if existing_position else USD(0)
|
424
507
|
)
|
425
|
-
return self.
|
508
|
+
return self.max_position_amount + existing_position_total_amount
|
426
509
|
|
427
510
|
def calculate_trades(
|
428
511
|
self,
|
@@ -471,4 +554,4 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
471
554
|
return trades
|
472
555
|
|
473
556
|
def __repr__(self) -> str:
|
474
|
-
return f"{self.__class__.__name__}(max_bet_amount={self.
|
557
|
+
return f"{self.__class__.__name__}(max_bet_amount={self.max_position_amount})"
|
@@ -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 = KellyBettingStrategy(
|
96
|
+
strategy = KellyBettingStrategy(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),
|
@@ -15,7 +15,7 @@ from prediction_market_agent_tooling.gtypes import (
|
|
15
15
|
Probability,
|
16
16
|
)
|
17
17
|
from prediction_market_agent_tooling.logprobs_parser import FieldLogprobs
|
18
|
-
from prediction_market_agent_tooling.markets.omen.
|
18
|
+
from prediction_market_agent_tooling.markets.omen.omen_constants import (
|
19
19
|
OMEN_FALSE_OUTCOME,
|
20
20
|
OMEN_TRUE_OUTCOME,
|
21
21
|
)
|
@@ -14,13 +14,13 @@ class QuestionType(str, Enum):
|
|
14
14
|
class AggregationItem(BaseModel):
|
15
15
|
start_time: DatetimeUTC
|
16
16
|
end_time: DatetimeUTC | None
|
17
|
-
forecast_values: list[float] | None
|
17
|
+
forecast_values: list[float] | None = None
|
18
18
|
forecaster_count: int
|
19
19
|
interval_lower_bounds: list[float] | None
|
20
20
|
centers: list[float] | None
|
21
21
|
interval_upper_bounds: list[float] | None
|
22
|
-
means: list[float] | None
|
23
|
-
histogram: list[list[float]] | None
|
22
|
+
means: list[float] | None = None
|
23
|
+
histogram: list[list[float]] | None = None
|
24
24
|
|
25
25
|
|
26
26
|
class Aggregation(BaseModel):
|
@@ -3,7 +3,7 @@ import os
|
|
3
3
|
from web3 import Web3
|
4
4
|
|
5
5
|
from prediction_market_agent_tooling.config import APIKeys
|
6
|
-
from prediction_market_agent_tooling.gtypes import ABI, HexBytes
|
6
|
+
from prediction_market_agent_tooling.gtypes import ABI, ChecksumAddress, HexBytes
|
7
7
|
from prediction_market_agent_tooling.tools.contract import (
|
8
8
|
ContractOnGnosisChain,
|
9
9
|
abi_field_validator,
|
@@ -19,6 +19,10 @@ class CowGPv2SettlementContract(ContractOnGnosisChain):
|
|
19
19
|
)
|
20
20
|
)
|
21
21
|
|
22
|
+
address: ChecksumAddress = Web3.to_checksum_address(
|
23
|
+
"0x9008D19f58AAbD9eD0D60971565AA8510560ab41"
|
24
|
+
)
|
25
|
+
|
22
26
|
def setPreSignature(
|
23
27
|
self,
|
24
28
|
api_keys: APIKeys,
|
@@ -23,6 +23,10 @@ from prediction_market_agent_tooling.markets.data_models import (
|
|
23
23
|
Resolution,
|
24
24
|
ResolvedBet,
|
25
25
|
)
|
26
|
+
from prediction_market_agent_tooling.markets.omen.omen_constants import (
|
27
|
+
OMEN_FALSE_OUTCOME,
|
28
|
+
OMEN_TRUE_OUTCOME,
|
29
|
+
)
|
26
30
|
from prediction_market_agent_tooling.tools.contract import (
|
27
31
|
ContractERC20OnGnosisChain,
|
28
32
|
init_collateral_token_contract,
|
@@ -37,8 +41,6 @@ from prediction_market_agent_tooling.tools.utils import (
|
|
37
41
|
utcnow,
|
38
42
|
)
|
39
43
|
|
40
|
-
OMEN_TRUE_OUTCOME = OutcomeStr("Yes")
|
41
|
-
OMEN_FALSE_OUTCOME = OutcomeStr("No")
|
42
44
|
OMEN_BINARY_MARKET_OUTCOMES: t.Sequence[OutcomeStr] = [
|
43
45
|
OMEN_TRUE_OUTCOME,
|
44
46
|
OMEN_FALSE_OUTCOME,
|
@@ -104,6 +104,7 @@ class OmenAgentMarket(AgentMarket):
|
|
104
104
|
|
105
105
|
collateral_token_contract_address_checksummed: ChecksumAddress
|
106
106
|
market_maker_contract_address_checksummed: ChecksumAddress
|
107
|
+
outcome_token_pool: dict[OutcomeStr, OutcomeToken]
|
107
108
|
condition: Condition
|
108
109
|
finalized_time: DatetimeUTC | None
|
109
110
|
created_time: DatetimeUTC
|
@@ -620,11 +621,10 @@ class OmenAgentMarket(AgentMarket):
|
|
620
621
|
Note: this is only valid if the market instance's token pool is
|
621
622
|
up-to-date with the smart contract.
|
622
623
|
"""
|
623
|
-
outcome_token_pool = check_not_none(self.outcome_token_pool)
|
624
624
|
amount = get_buy_outcome_token_amount(
|
625
625
|
investment_amount=self.get_in_token(bet_amount),
|
626
626
|
outcome_index=self.get_outcome_index(outcome),
|
627
|
-
pool_balances=[outcome_token_pool[x] for x in self.outcomes],
|
627
|
+
pool_balances=[self.outcome_token_pool[x] for x in self.outcomes],
|
628
628
|
fees=self.fees,
|
629
629
|
)
|
630
630
|
return amount
|
@@ -1,5 +1,10 @@
|
|
1
1
|
from web3 import Web3
|
2
2
|
|
3
|
+
from prediction_market_agent_tooling.gtypes import OutcomeStr
|
4
|
+
|
5
|
+
OMEN_TRUE_OUTCOME = OutcomeStr("Yes")
|
6
|
+
OMEN_FALSE_OUTCOME = OutcomeStr("No")
|
7
|
+
|
3
8
|
WRAPPED_XDAI_CONTRACT_ADDRESS = Web3.to_checksum_address(
|
4
9
|
"0xe91d153e0b41518a2ce8dd3d7944fa863463a97d"
|
5
10
|
)
|
@@ -2,6 +2,7 @@ import asyncio
|
|
2
2
|
import typing as t
|
3
3
|
from datetime import timedelta
|
4
4
|
|
5
|
+
from cowdao_cowpy.common.api.errors import UnexpectedResponseError
|
5
6
|
from eth_typing import ChecksumAddress
|
6
7
|
from web3 import Web3
|
7
8
|
from web3.types import TxReceipt
|
@@ -61,7 +62,6 @@ from prediction_market_agent_tooling.tools.contract import (
|
|
61
62
|
to_gnosis_chain_contract,
|
62
63
|
)
|
63
64
|
from prediction_market_agent_tooling.tools.cow.cow_order import (
|
64
|
-
cancel_order,
|
65
65
|
get_buy_token_amount_else_raise,
|
66
66
|
get_orders_by_owner,
|
67
67
|
get_trades_by_owner,
|
@@ -198,9 +198,7 @@ class SeerAgentMarket(AgentMarket):
|
|
198
198
|
)
|
199
199
|
)
|
200
200
|
|
201
|
-
amounts_ot[
|
202
|
-
OutcomeStr(outcome_str)
|
203
|
-
] = outcome_token_balance_wei.as_outcome_token
|
201
|
+
amounts_ot[outcome_str] = outcome_token_balance_wei.as_outcome_token
|
204
202
|
|
205
203
|
amounts_current = {
|
206
204
|
k: self.get_token_in_usd(self.get_sell_value_of_outcome_token(k, v))
|
@@ -481,26 +479,32 @@ class SeerAgentMarket(AgentMarket):
|
|
481
479
|
Returns:
|
482
480
|
Transaction hash of the successful swap
|
483
481
|
"""
|
484
|
-
_, order = swap_tokens_waiting(
|
485
|
-
amount_wei=amount_wei,
|
486
|
-
sell_token=sell_token,
|
487
|
-
buy_token=buy_token,
|
488
|
-
api_keys=api_keys,
|
489
|
-
web3=web3,
|
490
|
-
wait_order_complete=False,
|
491
|
-
)
|
492
482
|
|
493
483
|
try:
|
484
|
+
_, order = swap_tokens_waiting(
|
485
|
+
amount_wei=amount_wei,
|
486
|
+
sell_token=sell_token,
|
487
|
+
buy_token=buy_token,
|
488
|
+
api_keys=api_keys,
|
489
|
+
web3=web3,
|
490
|
+
wait_order_complete=False,
|
491
|
+
timeout=timedelta(minutes=2),
|
492
|
+
)
|
494
493
|
order_metadata = asyncio.run(wait_for_order_completion(order=order))
|
495
494
|
logger.debug(
|
496
495
|
f"Swapped {sell_token} for {buy_token}. Order details {order_metadata}"
|
497
496
|
)
|
498
497
|
return order_metadata.uid.root
|
499
498
|
|
500
|
-
except TimeoutError:
|
501
|
-
#
|
502
|
-
|
503
|
-
|
499
|
+
except (UnexpectedResponseError, TimeoutError) as e:
|
500
|
+
# We don't retry if not enough balance.
|
501
|
+
if "InsufficientBalance" in str(e):
|
502
|
+
raise e
|
503
|
+
# Note that we don't need to cancel the order because we are setting
|
504
|
+
# timeout and valid_to in the order, thus the order simply expires.
|
505
|
+
logger.info(
|
506
|
+
f"Exception occured when swapping tokens via Cowswap, doing swap via pools. {e}"
|
507
|
+
)
|
504
508
|
|
505
509
|
tx_receipt = SwapPoolHandler(
|
506
510
|
api_keys=api_keys,
|
@@ -55,7 +55,8 @@ from prediction_market_agent_tooling.markets.omen.cow_contracts import (
|
|
55
55
|
)
|
56
56
|
from prediction_market_agent_tooling.tools.contract import ContractERC20OnGnosisChain
|
57
57
|
from prediction_market_agent_tooling.tools.cow.models import MinimalisticToken, Order
|
58
|
-
from prediction_market_agent_tooling.tools.
|
58
|
+
from prediction_market_agent_tooling.tools.cow.semaphore import postgres_rate_limited
|
59
|
+
from prediction_market_agent_tooling.tools.utils import utcnow
|
59
60
|
|
60
61
|
|
61
62
|
class OrderStatusError(Exception):
|
@@ -190,7 +191,11 @@ def handle_allowance(
|
|
190
191
|
)
|
191
192
|
|
192
193
|
|
194
|
+
@postgres_rate_limited(
|
195
|
+
api_keys=APIKeys(), rate_id="swap_tokens_waiting", interval_seconds=60.0
|
196
|
+
)
|
193
197
|
@tenacity.retry(
|
198
|
+
reraise=True,
|
194
199
|
stop=stop_after_attempt(3),
|
195
200
|
wait=wait_fixed(1),
|
196
201
|
retry=tenacity.retry_if_not_exception_type((TimeoutError, OrderStatusError)),
|
@@ -205,6 +210,7 @@ def swap_tokens_waiting(
|
|
205
210
|
env: Envs = "prod",
|
206
211
|
web3: Web3 | None = None,
|
207
212
|
wait_order_complete: bool = True,
|
213
|
+
timeout: timedelta = timedelta(seconds=120),
|
208
214
|
) -> tuple[OrderMetaData | None, CompletedOrder]:
|
209
215
|
# CoW library uses async, so we need to wrap the call in asyncio.run for us to use it.
|
210
216
|
return asyncio.run(
|
@@ -215,6 +221,7 @@ def swap_tokens_waiting(
|
|
215
221
|
api_keys,
|
216
222
|
chain,
|
217
223
|
env,
|
224
|
+
timeout=timeout,
|
218
225
|
web3=web3,
|
219
226
|
wait_order_complete=wait_order_complete,
|
220
227
|
)
|
@@ -229,6 +236,7 @@ async def place_swap_order(
|
|
229
236
|
chain: Chain,
|
230
237
|
env: Envs,
|
231
238
|
slippage_tolerance: float = 0.01,
|
239
|
+
valid_to: int | None = None,
|
232
240
|
) -> CompletedOrder:
|
233
241
|
account = api_keys.get_account()
|
234
242
|
safe_address = api_keys.safe_address_checksum
|
@@ -242,6 +250,7 @@ async def place_swap_order(
|
|
242
250
|
chain=chain,
|
243
251
|
env=env,
|
244
252
|
slippage_tolerance=slippage_tolerance,
|
253
|
+
valid_to=valid_to,
|
245
254
|
)
|
246
255
|
logger.info(f"Order created: {order}")
|
247
256
|
|
@@ -299,6 +308,7 @@ async def swap_tokens_waiting_async(
|
|
299
308
|
handle_allowance(
|
300
309
|
api_keys=api_keys, sell_token=sell_token, amount_wei=amount_wei, web3=web3
|
301
310
|
)
|
311
|
+
valid_to = (utcnow() + timeout).timestamp()
|
302
312
|
order = await place_swap_order(
|
303
313
|
api_keys=api_keys,
|
304
314
|
amount_wei=amount_wei,
|
@@ -307,6 +317,7 @@ async def swap_tokens_waiting_async(
|
|
307
317
|
chain=chain,
|
308
318
|
env=env,
|
309
319
|
slippage_tolerance=slippage_tolerance,
|
320
|
+
valid_to=int(valid_to),
|
310
321
|
)
|
311
322
|
if wait_order_complete:
|
312
323
|
order_metadata = await wait_for_order_completion(order=order, timeout=timeout)
|
@@ -327,11 +338,8 @@ async def sign_safe_cow_swap(
|
|
327
338
|
) -> None:
|
328
339
|
order_book_api = get_order_book_api(env, chain)
|
329
340
|
posted_order = await order_book_api.get_order_by_uid(order.uid)
|
330
|
-
|
331
|
-
|
332
|
-
check_not_none(posted_order.settlementContract).root
|
333
|
-
)
|
334
|
-
).setPreSignature(
|
341
|
+
|
342
|
+
CowGPv2SettlementContract().setPreSignature(
|
335
343
|
api_keys,
|
336
344
|
HexBytes(posted_order.uid.root),
|
337
345
|
True,
|
@@ -1,7 +1,9 @@
|
|
1
1
|
from pydantic import BaseModel
|
2
|
+
from sqlmodel import Field, SQLModel
|
2
3
|
|
3
4
|
from prediction_market_agent_tooling.gtypes import ChecksumAddress
|
4
5
|
from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC
|
6
|
+
from prediction_market_agent_tooling.tools.utils import utcnow
|
5
7
|
|
6
8
|
|
7
9
|
class MinimalisticToken(BaseModel):
|
@@ -14,3 +16,9 @@ class Order(BaseModel):
|
|
14
16
|
sellToken: str
|
15
17
|
buyToken: str
|
16
18
|
creationDate: DatetimeUTC
|
19
|
+
|
20
|
+
|
21
|
+
class RateLimit(SQLModel, table=True):
|
22
|
+
__tablename__ = "rate_limit"
|
23
|
+
id: str = Field(primary_key=True)
|
24
|
+
last_called_at: DatetimeUTC = Field(default_factory=utcnow)
|
@@ -0,0 +1,101 @@
|
|
1
|
+
import time
|
2
|
+
from datetime import timedelta
|
3
|
+
from functools import wraps
|
4
|
+
from typing import Any, Callable, Optional, TypeVar, cast
|
5
|
+
|
6
|
+
from sqlalchemy.exc import OperationalError
|
7
|
+
from sqlmodel import Session, select
|
8
|
+
|
9
|
+
from prediction_market_agent_tooling.config import APIKeys
|
10
|
+
from prediction_market_agent_tooling.tools.cow.models import RateLimit
|
11
|
+
from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC
|
12
|
+
from prediction_market_agent_tooling.tools.db.db_manager import DBManager
|
13
|
+
from prediction_market_agent_tooling.tools.utils import utcnow
|
14
|
+
|
15
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
16
|
+
|
17
|
+
FALLBACK_SQL_ENGINE = "sqlite:///rate_limit.db"
|
18
|
+
|
19
|
+
|
20
|
+
def postgres_rate_limited(
|
21
|
+
api_keys: APIKeys, rate_id: str = "default", interval_seconds: float = 1.0
|
22
|
+
) -> Callable[[F], F]:
|
23
|
+
"""rate_id is used to distinguish between different rate limits for different functions"""
|
24
|
+
limiter = RateLimiter(id=rate_id, interval_seconds=interval_seconds)
|
25
|
+
|
26
|
+
def decorator(func: F) -> F:
|
27
|
+
@wraps(func)
|
28
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
29
|
+
sqlalchemy_db_url = (
|
30
|
+
api_keys.sqlalchemy_db_url.get_secret_value()
|
31
|
+
if api_keys.SQLALCHEMY_DB_URL
|
32
|
+
else FALLBACK_SQL_ENGINE
|
33
|
+
)
|
34
|
+
|
35
|
+
db_manager = DBManager(sqlalchemy_db_url)
|
36
|
+
db_manager.create_tables([RateLimit])
|
37
|
+
|
38
|
+
with db_manager.get_session() as session:
|
39
|
+
limiter.enforce(session)
|
40
|
+
return func(*args, **kwargs)
|
41
|
+
|
42
|
+
return cast(F, wrapper)
|
43
|
+
|
44
|
+
return decorator
|
45
|
+
|
46
|
+
|
47
|
+
class RateLimiter:
|
48
|
+
def __init__(self, id: str, interval_seconds: float = 1.0) -> None:
|
49
|
+
self.id = id
|
50
|
+
self.interval = timedelta(seconds=interval_seconds)
|
51
|
+
|
52
|
+
def enforce(self, session: Session, timeout_seconds: float = 30.0) -> None:
|
53
|
+
"""
|
54
|
+
Enforces the rate limit inside a transaction.
|
55
|
+
Blocks until allowed or timeout is reached.
|
56
|
+
|
57
|
+
Args:
|
58
|
+
session: The database session to use
|
59
|
+
timeout_seconds: Maximum time in seconds to wait before giving up
|
60
|
+
|
61
|
+
Raises:
|
62
|
+
TimeoutError: If the rate limit cannot be acquired within the timeout period
|
63
|
+
"""
|
64
|
+
start_time = time.monotonic()
|
65
|
+
|
66
|
+
while True:
|
67
|
+
try:
|
68
|
+
with session.begin():
|
69
|
+
stmt = (
|
70
|
+
select(RateLimit)
|
71
|
+
.where(RateLimit.id == self.id)
|
72
|
+
.with_for_update()
|
73
|
+
)
|
74
|
+
result: Optional[RateLimit] = session.exec(stmt).first()
|
75
|
+
|
76
|
+
now = utcnow()
|
77
|
+
|
78
|
+
if result is None:
|
79
|
+
# First time this limiter is used
|
80
|
+
session.add(RateLimit(id=self.id))
|
81
|
+
return
|
82
|
+
|
83
|
+
last_called_aware = DatetimeUTC.from_datetime(result.last_called_at)
|
84
|
+
elapsed = now - last_called_aware
|
85
|
+
if elapsed >= self.interval:
|
86
|
+
result.last_called_at = now
|
87
|
+
session.add(result)
|
88
|
+
return
|
89
|
+
|
90
|
+
# Not enough time passed, sleep and retry
|
91
|
+
to_sleep = (self.interval - elapsed).total_seconds()
|
92
|
+
time.sleep(to_sleep)
|
93
|
+
except OperationalError:
|
94
|
+
# Backoff if DB is under contention
|
95
|
+
elapsed_time = time.monotonic() - start_time
|
96
|
+
if elapsed_time > timeout_seconds:
|
97
|
+
raise TimeoutError(
|
98
|
+
f"Could not acquire rate limit '{self.id}' "
|
99
|
+
f"after {elapsed_time:.1f} seconds due to database contention"
|
100
|
+
)
|
101
|
+
time.sleep(0.5)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "prediction-market-agent-tooling"
|
3
|
-
version = "0.66.
|
3
|
+
version = "0.66.2"
|
4
4
|
description = "Tools to benchmark, deploy and monitor prediction market agents."
|
5
5
|
authors = ["Gnosis"]
|
6
6
|
readme = "README.md"
|
@@ -55,7 +55,7 @@ hishel = "^0.0.31"
|
|
55
55
|
pytest-postgresql = "^6.1.1"
|
56
56
|
optuna = { version = "^4.1.0", optional = true}
|
57
57
|
httpx = ">=0.25.2,<1.0.0"
|
58
|
-
cowdao-cowpy
|
58
|
+
cowdao-cowpy = "1.0.0rc5"
|
59
59
|
eth-keys = "^0.6.1"
|
60
60
|
proto-plus = "^1.0.0"
|
61
61
|
protobuf = "^5.0.0"
|
{prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/LICENSE
RENAMED
File without changes
|
{prediction_market_agent_tooling-0.66.0.dev791 → prediction_market_agent_tooling-0.66.2}/README.md
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|