prediction-market-agent-tooling 0.64.12.dev660__py3-none-any.whl → 0.65.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prediction_market_agent_tooling/benchmark/agents.py +19 -16
- prediction_market_agent_tooling/benchmark/benchmark.py +94 -84
- prediction_market_agent_tooling/benchmark/utils.py +8 -9
- prediction_market_agent_tooling/deploy/agent.py +85 -125
- prediction_market_agent_tooling/deploy/agent_example.py +20 -10
- prediction_market_agent_tooling/deploy/betting_strategy.py +222 -96
- prediction_market_agent_tooling/deploy/constants.py +4 -0
- prediction_market_agent_tooling/jobs/jobs_models.py +15 -4
- prediction_market_agent_tooling/jobs/omen/omen_jobs.py +3 -3
- prediction_market_agent_tooling/markets/agent_market.py +145 -50
- prediction_market_agent_tooling/markets/blockchain_utils.py +10 -1
- prediction_market_agent_tooling/markets/data_models.py +83 -17
- prediction_market_agent_tooling/markets/manifold/api.py +18 -7
- prediction_market_agent_tooling/markets/manifold/data_models.py +23 -16
- prediction_market_agent_tooling/markets/manifold/manifold.py +18 -18
- prediction_market_agent_tooling/markets/manifold/utils.py +7 -12
- prediction_market_agent_tooling/markets/markets.py +2 -1
- prediction_market_agent_tooling/markets/metaculus/metaculus.py +29 -4
- prediction_market_agent_tooling/markets/omen/data_models.py +17 -32
- prediction_market_agent_tooling/markets/omen/omen.py +65 -108
- prediction_market_agent_tooling/markets/omen/omen_contracts.py +2 -5
- prediction_market_agent_tooling/markets/omen/omen_resolving.py +13 -13
- prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +18 -12
- prediction_market_agent_tooling/markets/polymarket/data_models.py +7 -3
- prediction_market_agent_tooling/markets/polymarket/data_models_web.py +7 -3
- prediction_market_agent_tooling/markets/polymarket/polymarket.py +5 -4
- prediction_market_agent_tooling/markets/seer/data_models.py +0 -83
- prediction_market_agent_tooling/markets/seer/price_manager.py +44 -30
- prediction_market_agent_tooling/markets/seer/seer.py +105 -105
- prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +34 -41
- prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +1 -1
- prediction_market_agent_tooling/tools/cow/cow_order.py +10 -3
- prediction_market_agent_tooling/tools/is_predictable.py +2 -3
- prediction_market_agent_tooling/tools/langfuse_client_utils.py +4 -4
- prediction_market_agent_tooling/tools/omen/sell_positions.py +3 -2
- prediction_market_agent_tooling/tools/utils.py +26 -13
- {prediction_market_agent_tooling-0.64.12.dev660.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/METADATA +2 -2
- {prediction_market_agent_tooling-0.64.12.dev660.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/RECORD +41 -51
- prediction_market_agent_tooling/monitor/financial_metrics/financial_metrics.py +0 -68
- prediction_market_agent_tooling/monitor/markets/manifold.py +0 -90
- prediction_market_agent_tooling/monitor/markets/metaculus.py +0 -43
- prediction_market_agent_tooling/monitor/markets/omen.py +0 -88
- prediction_market_agent_tooling/monitor/markets/polymarket.py +0 -49
- prediction_market_agent_tooling/monitor/monitor.py +0 -406
- prediction_market_agent_tooling/monitor/monitor_app.py +0 -149
- prediction_market_agent_tooling/monitor/monitor_settings.py +0 -27
- prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -146
- prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -12
- {prediction_market_agent_tooling-0.64.12.dev660.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.64.12.dev660.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/WHEEL +0 -0
- {prediction_market_agent_tooling-0.64.12.dev660.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/entry_points.txt +0 -0
@@ -1,149 +0,0 @@
|
|
1
|
-
import typing as t
|
2
|
-
from datetime import datetime, timedelta
|
3
|
-
|
4
|
-
import streamlit as st
|
5
|
-
|
6
|
-
from prediction_market_agent_tooling.markets.agent_market import (
|
7
|
-
AgentMarket,
|
8
|
-
FilterBy,
|
9
|
-
SortBy,
|
10
|
-
)
|
11
|
-
from prediction_market_agent_tooling.markets.markets import MarketType
|
12
|
-
from prediction_market_agent_tooling.monitor.markets.manifold import (
|
13
|
-
DeployedManifoldAgent,
|
14
|
-
)
|
15
|
-
from prediction_market_agent_tooling.monitor.markets.metaculus import (
|
16
|
-
DeployedMetaculusAgent,
|
17
|
-
)
|
18
|
-
from prediction_market_agent_tooling.monitor.markets.omen import DeployedOmenAgent
|
19
|
-
from prediction_market_agent_tooling.monitor.markets.polymarket import (
|
20
|
-
DeployedPolymarketAgent,
|
21
|
-
)
|
22
|
-
from prediction_market_agent_tooling.monitor.monitor import (
|
23
|
-
DeployedAgent,
|
24
|
-
monitor_agent,
|
25
|
-
monitor_market,
|
26
|
-
)
|
27
|
-
from prediction_market_agent_tooling.monitor.monitor_settings import MonitorSettings
|
28
|
-
from prediction_market_agent_tooling.tools.utils import (
|
29
|
-
DatetimeUTC,
|
30
|
-
check_not_none,
|
31
|
-
utc_datetime,
|
32
|
-
utcnow,
|
33
|
-
)
|
34
|
-
|
35
|
-
MAX_MONITOR_MARKETS = 1000
|
36
|
-
|
37
|
-
MARKET_TYPE_TO_DEPLOYED_AGENT: dict[MarketType, type[DeployedAgent]] = {
|
38
|
-
MarketType.MANIFOLD: DeployedManifoldAgent,
|
39
|
-
MarketType.OMEN: DeployedOmenAgent,
|
40
|
-
MarketType.POLYMARKET: DeployedPolymarketAgent,
|
41
|
-
MarketType.METACULUS: DeployedMetaculusAgent,
|
42
|
-
}
|
43
|
-
|
44
|
-
|
45
|
-
def get_deployed_agents(
|
46
|
-
market_type: MarketType,
|
47
|
-
settings: MonitorSettings,
|
48
|
-
start_time: DatetimeUTC | None,
|
49
|
-
) -> list[DeployedAgent]:
|
50
|
-
cls = MARKET_TYPE_TO_DEPLOYED_AGENT.get(market_type)
|
51
|
-
if cls is None:
|
52
|
-
raise ValueError(f"Unknown market type: {market_type}")
|
53
|
-
|
54
|
-
agents: list[DeployedAgent] = []
|
55
|
-
|
56
|
-
if settings.LOAD_FROM_GCF:
|
57
|
-
agents.extend(cls.from_all_gcp_functions())
|
58
|
-
|
59
|
-
if settings.LOAD_FROM_GCK:
|
60
|
-
agents.extend(
|
61
|
-
cls.from_all_gcp_cronjobs(namespace=settings.LOAD_FROM_GCK_NAMESPACE)
|
62
|
-
)
|
63
|
-
|
64
|
-
match market_type:
|
65
|
-
case MarketType.MANIFOLD:
|
66
|
-
agents += settings.MANIFOLD_AGENTS
|
67
|
-
case MarketType.OMEN:
|
68
|
-
agents += settings.OMEN_AGENTS
|
69
|
-
case MarketType.POLYMARKET:
|
70
|
-
agents += settings.POLYMARKET_AGENTS
|
71
|
-
case _:
|
72
|
-
raise ValueError(f"Unknown market type: {market_type}")
|
73
|
-
|
74
|
-
return agents
|
75
|
-
|
76
|
-
|
77
|
-
def get_open_and_resolved_markets(
|
78
|
-
start_time: DatetimeUTC,
|
79
|
-
market_type: MarketType,
|
80
|
-
) -> tuple[t.Sequence[AgentMarket], t.Sequence[AgentMarket]]:
|
81
|
-
cls = market_type.market_class
|
82
|
-
open_markets = cls.get_binary_markets(
|
83
|
-
limit=MAX_MONITOR_MARKETS,
|
84
|
-
sort_by=SortBy.NEWEST,
|
85
|
-
created_after=start_time,
|
86
|
-
filter_by=FilterBy.OPEN,
|
87
|
-
)
|
88
|
-
resolved_markets = cls.get_binary_markets(
|
89
|
-
limit=MAX_MONITOR_MARKETS,
|
90
|
-
sort_by=SortBy.NEWEST,
|
91
|
-
created_after=start_time,
|
92
|
-
filter_by=FilterBy.RESOLVED,
|
93
|
-
)
|
94
|
-
resolved_markets = [m for m in resolved_markets if m.has_successful_resolution()]
|
95
|
-
return open_markets, resolved_markets
|
96
|
-
|
97
|
-
|
98
|
-
def monitor_app(
|
99
|
-
enabled_market_types: list[MarketType],
|
100
|
-
) -> None:
|
101
|
-
settings = MonitorSettings()
|
102
|
-
market_type: MarketType = check_not_none(
|
103
|
-
st.selectbox(label="Market type", options=enabled_market_types, index=0)
|
104
|
-
)
|
105
|
-
start_time: DatetimeUTC | None = (
|
106
|
-
DatetimeUTC.from_datetime(
|
107
|
-
datetime.combine(
|
108
|
-
st.date_input(
|
109
|
-
"Start time",
|
110
|
-
value=utcnow() - timedelta(weeks=settings.PAST_N_WEEKS),
|
111
|
-
),
|
112
|
-
datetime.min.time(),
|
113
|
-
)
|
114
|
-
)
|
115
|
-
if settings.has_manual_agents
|
116
|
-
else None
|
117
|
-
)
|
118
|
-
|
119
|
-
with st.spinner("Loading agents"):
|
120
|
-
agents: list[DeployedAgent] = get_deployed_agents(
|
121
|
-
market_type=market_type,
|
122
|
-
settings=settings,
|
123
|
-
start_time=start_time,
|
124
|
-
)
|
125
|
-
|
126
|
-
oldest_start_time = (
|
127
|
-
min(agent.start_time for agent in agents)
|
128
|
-
if agents
|
129
|
-
else utc_datetime(2020, 1, 1)
|
130
|
-
)
|
131
|
-
|
132
|
-
st.header("Market Info")
|
133
|
-
if st.checkbox("Show Market Info"):
|
134
|
-
with st.spinner("Loading markets"):
|
135
|
-
open_markets, resolved_markets = get_open_and_resolved_markets(
|
136
|
-
start_time=oldest_start_time, market_type=market_type
|
137
|
-
)
|
138
|
-
(
|
139
|
-
monitor_market(open_markets=open_markets, resolved_markets=resolved_markets)
|
140
|
-
if open_markets and resolved_markets
|
141
|
-
else st.warning("No market data found.")
|
142
|
-
)
|
143
|
-
|
144
|
-
st.header("Agent Info")
|
145
|
-
if st.button("Export agents"):
|
146
|
-
st.text("[" + ",".join(a.model_dump_json() for a in agents) + "]")
|
147
|
-
for agent in agents:
|
148
|
-
with st.expander(f"Agent: '{agent.name}'"):
|
149
|
-
monitor_agent(agent)
|
@@ -1,27 +0,0 @@
|
|
1
|
-
from pydantic_settings import BaseSettings, SettingsConfigDict
|
2
|
-
|
3
|
-
from prediction_market_agent_tooling.monitor.markets.manifold import (
|
4
|
-
DeployedManifoldAgent,
|
5
|
-
)
|
6
|
-
from prediction_market_agent_tooling.monitor.markets.omen import DeployedOmenAgent
|
7
|
-
from prediction_market_agent_tooling.monitor.markets.polymarket import (
|
8
|
-
DeployedPolymarketAgent,
|
9
|
-
)
|
10
|
-
|
11
|
-
|
12
|
-
class MonitorSettings(BaseSettings):
|
13
|
-
model_config = SettingsConfigDict(
|
14
|
-
env_file=".env.monitor", env_file_encoding="utf-8", extra="ignore"
|
15
|
-
)
|
16
|
-
|
17
|
-
LOAD_FROM_GCF: bool = False
|
18
|
-
LOAD_FROM_GCK: bool = False
|
19
|
-
LOAD_FROM_GCK_NAMESPACE: str = "agents"
|
20
|
-
MANIFOLD_AGENTS: list[DeployedManifoldAgent] = []
|
21
|
-
OMEN_AGENTS: list[DeployedOmenAgent] = []
|
22
|
-
POLYMARKET_AGENTS: list[DeployedPolymarketAgent] = []
|
23
|
-
PAST_N_WEEKS: int = 1
|
24
|
-
|
25
|
-
@property
|
26
|
-
def has_manual_agents(self) -> bool:
|
27
|
-
return bool(self.MANIFOLD_AGENTS or self.OMEN_AGENTS or self.POLYMARKET_AGENTS)
|
@@ -1,146 +0,0 @@
|
|
1
|
-
from functools import reduce
|
2
|
-
|
3
|
-
import numpy as np
|
4
|
-
|
5
|
-
from prediction_market_agent_tooling.gtypes import (
|
6
|
-
CollateralToken,
|
7
|
-
OutcomeToken,
|
8
|
-
Probability,
|
9
|
-
)
|
10
|
-
from prediction_market_agent_tooling.markets.omen.omen import (
|
11
|
-
MarketFees,
|
12
|
-
OmenAgentMarket,
|
13
|
-
)
|
14
|
-
from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet
|
15
|
-
from prediction_market_agent_tooling.tools.utils import check_not_none
|
16
|
-
|
17
|
-
|
18
|
-
def get_market_moving_bet(
|
19
|
-
yes_outcome_pool_size: OutcomeToken,
|
20
|
-
no_outcome_pool_size: OutcomeToken,
|
21
|
-
market_p_yes: float,
|
22
|
-
target_p_yes: float,
|
23
|
-
fees: MarketFees,
|
24
|
-
max_iters: int = 100,
|
25
|
-
) -> SimpleBet:
|
26
|
-
"""
|
27
|
-
Implements a binary search to determine the bet that will move the market's
|
28
|
-
`p_yes` to that of the target.
|
29
|
-
|
30
|
-
Consider a binary fixed-product market containing `x` and `y` tokens.
|
31
|
-
A trader wishes to acquire `x` tokens by betting an amount `d0`.
|
32
|
-
|
33
|
-
The calculation to determine the number of `x` tokens he acquires, denoted
|
34
|
-
by `dx`, is:
|
35
|
-
|
36
|
-
a_x * a_y = fixed_product
|
37
|
-
na_x = a_x + d0
|
38
|
-
na_y = a_y + d0
|
39
|
-
na_x * na_y = new_product
|
40
|
-
(na_x - dx) * na_y = fixed_product
|
41
|
-
(na_x * na_y) - (dx * na_y) = fixed_product
|
42
|
-
new_product - fixed_product = dx * na_y
|
43
|
-
dx = (new_product - fixed_product) / na_y
|
44
|
-
"""
|
45
|
-
fixed_product = yes_outcome_pool_size * no_outcome_pool_size
|
46
|
-
bet_direction: bool = target_p_yes > market_p_yes
|
47
|
-
|
48
|
-
min_bet_amount = CollateralToken(0.0)
|
49
|
-
max_bet_amount = (
|
50
|
-
yes_outcome_pool_size + no_outcome_pool_size
|
51
|
-
).as_token * 100 # TODO set a better upper bound
|
52
|
-
|
53
|
-
# Binary search for the optimal bet amount
|
54
|
-
for _ in range(max_iters):
|
55
|
-
bet_amount = (min_bet_amount + max_bet_amount) / 2
|
56
|
-
amounts_diff = fees.get_after_fees(bet_amount)
|
57
|
-
amounts_diff_as_ot = OutcomeToken.from_token(amounts_diff)
|
58
|
-
|
59
|
-
# Initial new amounts are old amounts + equal new amounts for each outcome
|
60
|
-
yes_outcome_new_pool_size = yes_outcome_pool_size + amounts_diff_as_ot
|
61
|
-
no_outcome_new_pool_size = no_outcome_pool_size + amounts_diff_as_ot
|
62
|
-
new_amounts: dict[bool, OutcomeToken] = {
|
63
|
-
True: yes_outcome_new_pool_size,
|
64
|
-
False: no_outcome_new_pool_size,
|
65
|
-
}
|
66
|
-
|
67
|
-
# Now give away tokens at `bet_outcome_index` to restore invariant
|
68
|
-
new_product = yes_outcome_new_pool_size * no_outcome_new_pool_size
|
69
|
-
dx = (new_product - fixed_product) / new_amounts[not bet_direction]
|
70
|
-
new_amounts[bet_direction] -= OutcomeToken(dx)
|
71
|
-
|
72
|
-
# Check that the invariant is restored
|
73
|
-
assert np.isclose(
|
74
|
-
reduce(lambda x, y: x * y.value, list(new_amounts.values()), 1.0),
|
75
|
-
float(fixed_product),
|
76
|
-
)
|
77
|
-
|
78
|
-
new_p_yes = Probability(
|
79
|
-
(
|
80
|
-
new_amounts[False]
|
81
|
-
/ sum(list(new_amounts.values()), start=OutcomeToken(0))
|
82
|
-
)
|
83
|
-
)
|
84
|
-
if abs(target_p_yes - new_p_yes) < 1e-6:
|
85
|
-
break
|
86
|
-
elif new_p_yes > target_p_yes:
|
87
|
-
if bet_direction:
|
88
|
-
max_bet_amount = bet_amount
|
89
|
-
else:
|
90
|
-
min_bet_amount = bet_amount
|
91
|
-
else:
|
92
|
-
if bet_direction:
|
93
|
-
min_bet_amount = bet_amount
|
94
|
-
else:
|
95
|
-
max_bet_amount = bet_amount
|
96
|
-
|
97
|
-
return SimpleBet(direction=bet_direction, size=bet_amount)
|
98
|
-
|
99
|
-
|
100
|
-
def _sanity_check_omen_market_moving_bet(
|
101
|
-
bet_to_check: SimpleBet, market: OmenAgentMarket, target_p_yes: float
|
102
|
-
) -> None:
|
103
|
-
"""
|
104
|
-
A util function for checking that a bet moves the market to the target_p_yes
|
105
|
-
by calling the market's calcBuyAmount method from the smart contract, and
|
106
|
-
using the adjusted outcome pool sizes to calculate the new p_yes.
|
107
|
-
"""
|
108
|
-
buy_amount_ = market.get_contract().calcBuyAmount(
|
109
|
-
investment_amount=bet_to_check.size.as_wei,
|
110
|
-
outcome_index=market.get_outcome_index(
|
111
|
-
market.get_outcome_str_from_bool(bet_to_check.direction)
|
112
|
-
),
|
113
|
-
)
|
114
|
-
buy_amount = buy_amount_.as_outcome_token
|
115
|
-
|
116
|
-
outcome_token_pool = check_not_none(market.outcome_token_pool)
|
117
|
-
yes_outcome_pool_size = outcome_token_pool[market.get_outcome_str_from_bool(True)]
|
118
|
-
no_outcome_pool_size = outcome_token_pool[market.get_outcome_str_from_bool(False)]
|
119
|
-
market_const = yes_outcome_pool_size.value * no_outcome_pool_size.value
|
120
|
-
|
121
|
-
bet_to_check_size_after_fees = market.fees.get_after_fees(bet_to_check.size).value
|
122
|
-
|
123
|
-
# When you buy 'yes' tokens, you add your bet size to the both pools, then
|
124
|
-
# subtract `buy_amount` from the 'yes' pool. And vice versa for 'no' tokens.
|
125
|
-
new_yes_outcome_pool_size = (
|
126
|
-
yes_outcome_pool_size.value
|
127
|
-
+ bet_to_check_size_after_fees
|
128
|
-
- float(bet_to_check.direction) * buy_amount.value
|
129
|
-
)
|
130
|
-
new_no_outcome_pool_size = (
|
131
|
-
no_outcome_pool_size.value
|
132
|
-
+ bet_to_check_size_after_fees
|
133
|
-
- float(not bet_to_check.direction) * buy_amount.value
|
134
|
-
)
|
135
|
-
new_market_const = new_yes_outcome_pool_size * new_no_outcome_pool_size
|
136
|
-
# Check the invariant is restored
|
137
|
-
assert np.isclose(new_market_const, market_const)
|
138
|
-
|
139
|
-
# Now check that the market's new p_yes is equal to the target_p_yes
|
140
|
-
new_p_yes = new_no_outcome_pool_size / (
|
141
|
-
new_yes_outcome_pool_size + new_no_outcome_pool_size
|
142
|
-
)
|
143
|
-
if not np.isclose(new_p_yes, target_p_yes, atol=0.01):
|
144
|
-
raise ValueError(
|
145
|
-
f"Bet does not move market to target_p_yes {target_p_yes=}. Got {new_p_yes=}"
|
146
|
-
)
|
@@ -1,12 +0,0 @@
|
|
1
|
-
from prediction_market_agent_tooling.markets.agent_market import AgentMarket
|
2
|
-
|
3
|
-
|
4
|
-
def minimum_bet_to_win(
|
5
|
-
answer: bool, amount_to_win: float, market: AgentMarket
|
6
|
-
) -> float:
|
7
|
-
"""
|
8
|
-
Estimates the minimum bet amount to win the given amount based on the current market price.
|
9
|
-
"""
|
10
|
-
share_price = market.current_p_yes if answer else market.current_p_no
|
11
|
-
bet_amount = amount_to_win / (1 / share_price - 1)
|
12
|
-
return bet_amount
|
File without changes
|
File without changes
|