prediction-market-agent-tooling 0.64.12.dev659__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/chains.py +4 -0
- prediction_market_agent_tooling/config.py +4 -3
- 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.dev659.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/METADATA +2 -2
- {prediction_market_agent_tooling-0.64.12.dev659.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/RECORD +43 -52
- 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.dev659.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.64.12.dev659.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/WHEEL +0 -0
- {prediction_market_agent_tooling-0.64.12.dev659.dist-info → prediction_market_agent_tooling-0.65.0.dist-info}/entry_points.txt +0 -0
@@ -1,14 +1,25 @@
|
|
1
1
|
from abc import ABC, abstractmethod
|
2
|
+
from typing import Sequence
|
2
3
|
|
3
4
|
from scipy.optimize import minimize_scalar
|
4
5
|
|
5
|
-
from prediction_market_agent_tooling.
|
6
|
+
from prediction_market_agent_tooling.benchmark.utils import get_most_probable_outcome
|
7
|
+
from prediction_market_agent_tooling.deploy.constants import (
|
8
|
+
INVALID_OUTCOME_LOWERCASE_IDENTIFIER,
|
9
|
+
)
|
10
|
+
from prediction_market_agent_tooling.gtypes import (
|
11
|
+
USD,
|
12
|
+
CollateralToken,
|
13
|
+
OutcomeStr,
|
14
|
+
OutcomeWei,
|
15
|
+
Probability,
|
16
|
+
)
|
6
17
|
from prediction_market_agent_tooling.loggers import logger
|
7
18
|
from prediction_market_agent_tooling.markets.agent_market import AgentMarket, MarketFees
|
8
19
|
from prediction_market_agent_tooling.markets.data_models import (
|
20
|
+
CategoricalProbabilisticAnswer,
|
9
21
|
ExistingPosition,
|
10
22
|
Position,
|
11
|
-
ProbabilisticAnswer,
|
12
23
|
Trade,
|
13
24
|
TradeType,
|
14
25
|
)
|
@@ -17,6 +28,7 @@ from prediction_market_agent_tooling.markets.omen.omen import (
|
|
17
28
|
)
|
18
29
|
from prediction_market_agent_tooling.tools.betting_strategies.kelly_criterion import (
|
19
30
|
get_kelly_bet_full,
|
31
|
+
get_kelly_bet_simplified,
|
20
32
|
)
|
21
33
|
from prediction_market_agent_tooling.tools.betting_strategies.utils import SimpleBet
|
22
34
|
from prediction_market_agent_tooling.tools.utils import check_not_none
|
@@ -31,7 +43,7 @@ class BettingStrategy(ABC):
|
|
31
43
|
def calculate_trades(
|
32
44
|
self,
|
33
45
|
existing_position: ExistingPosition | None,
|
34
|
-
answer:
|
46
|
+
answer: CategoricalProbabilisticAnswer,
|
35
47
|
market: AgentMarket,
|
36
48
|
) -> list[Trade]:
|
37
49
|
raise NotImplementedError("Subclass should implement this.")
|
@@ -41,7 +53,8 @@ class BettingStrategy(ABC):
|
|
41
53
|
def maximum_possible_bet_amount(self) -> USD:
|
42
54
|
raise NotImplementedError("Subclass should implement this.")
|
43
55
|
|
44
|
-
|
56
|
+
@staticmethod
|
57
|
+
def build_zero_usd_amount() -> USD:
|
45
58
|
return USD(0)
|
46
59
|
|
47
60
|
@staticmethod
|
@@ -95,27 +108,43 @@ class BettingStrategy(ABC):
|
|
95
108
|
Trade(outcome=0, amount=10, trade_type=TradeType.BUY),
|
96
109
|
Trade(outcome=1, amount=5, trade_type=TradeType.SELL)
|
97
110
|
]
|
98
|
-
Note that we order the trades to first buy then sell, in order to minimally tilt the odds so that
|
99
|
-
sell price is higher.
|
111
|
+
Note that we order the trades to first buy then sell, in order to minimally tilt the odds so that sell price is higher.
|
100
112
|
"""
|
113
|
+
|
114
|
+
existing_amounts = (
|
115
|
+
{
|
116
|
+
outcome.lower(): amount
|
117
|
+
for outcome, amount in existing_position.amounts_current.items()
|
118
|
+
}
|
119
|
+
if existing_position
|
120
|
+
else {}
|
121
|
+
)
|
122
|
+
target_amounts = (
|
123
|
+
{
|
124
|
+
outcome.lower(): amount
|
125
|
+
for outcome, amount in target_position.amounts_current.items()
|
126
|
+
}
|
127
|
+
if target_position
|
128
|
+
else {}
|
129
|
+
)
|
130
|
+
|
101
131
|
trades = []
|
102
|
-
for
|
103
|
-
|
104
|
-
|
105
|
-
existing_position.amounts_current[outcome]
|
106
|
-
if existing_position and outcome in existing_position.amounts_current
|
107
|
-
else self.build_zero_usd_amount()
|
132
|
+
for outcome in market.outcomes:
|
133
|
+
existing_amount = existing_amounts.get(
|
134
|
+
outcome.lower(), self.build_zero_usd_amount()
|
108
135
|
)
|
109
|
-
|
110
|
-
outcome, self.build_zero_usd_amount()
|
136
|
+
target_amount = target_amounts.get(
|
137
|
+
outcome.lower(), self.build_zero_usd_amount()
|
111
138
|
)
|
112
|
-
|
139
|
+
|
140
|
+
diff_amount = target_amount - existing_amount
|
113
141
|
if diff_amount == 0:
|
114
142
|
continue
|
143
|
+
|
115
144
|
trade_type = TradeType.SELL if diff_amount < 0 else TradeType.BUY
|
116
145
|
trade = Trade(
|
117
146
|
amount=abs(diff_amount),
|
118
|
-
outcome=
|
147
|
+
outcome=outcome,
|
119
148
|
trade_type=trade_type,
|
120
149
|
)
|
121
150
|
|
@@ -130,7 +159,7 @@ class BettingStrategy(ABC):
|
|
130
159
|
return trades
|
131
160
|
|
132
161
|
|
133
|
-
class
|
162
|
+
class MultiCategoricalMaxAccuracyBettingStrategy(BettingStrategy):
|
134
163
|
def __init__(self, bet_amount: USD):
|
135
164
|
self.bet_amount = bet_amount
|
136
165
|
|
@@ -138,38 +167,89 @@ class MaxAccuracyBettingStrategy(BettingStrategy):
|
|
138
167
|
def maximum_possible_bet_amount(self) -> USD:
|
139
168
|
return self.bet_amount
|
140
169
|
|
170
|
+
@staticmethod
|
171
|
+
def calculate_direction(
|
172
|
+
market: AgentMarket, answer: CategoricalProbabilisticAnswer
|
173
|
+
) -> OutcomeStr:
|
174
|
+
# We place a bet on the most likely outcome
|
175
|
+
most_likely_outcome = max(
|
176
|
+
answer.probabilities.items(),
|
177
|
+
key=lambda item: item[1],
|
178
|
+
)[0]
|
179
|
+
|
180
|
+
return market.market_outcome_for_probability_key(most_likely_outcome)
|
181
|
+
|
182
|
+
@staticmethod
|
183
|
+
def get_other_direction(
|
184
|
+
outcomes: Sequence[OutcomeStr], direction: OutcomeStr
|
185
|
+
) -> OutcomeStr:
|
186
|
+
# We get the first direction which is != direction.
|
187
|
+
other_direction = [i for i in outcomes if i.lower() != direction.lower()][0]
|
188
|
+
if INVALID_OUTCOME_LOWERCASE_IDENTIFIER in other_direction.lower():
|
189
|
+
raise ValueError("Invalid outcome found as opposite direction. Exitting.")
|
190
|
+
return other_direction
|
191
|
+
|
141
192
|
def calculate_trades(
|
142
193
|
self,
|
143
194
|
existing_position: ExistingPosition | None,
|
144
|
-
answer:
|
195
|
+
answer: CategoricalProbabilisticAnswer,
|
145
196
|
market: AgentMarket,
|
146
197
|
) -> list[Trade]:
|
147
|
-
|
198
|
+
"""We place bet on only one outcome."""
|
148
199
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
200
|
+
outcome_to_bet_on = self.calculate_direction(market, answer)
|
201
|
+
|
202
|
+
target_position = Position(
|
203
|
+
market_id=market.id, amounts_current={outcome_to_bet_on: self.bet_amount}
|
204
|
+
)
|
153
205
|
trades = self._build_rebalance_trades_from_positions(
|
154
|
-
existing_position,
|
206
|
+
existing_position=existing_position,
|
207
|
+
target_position=target_position,
|
208
|
+
market=market,
|
155
209
|
)
|
156
210
|
return trades
|
157
211
|
|
212
|
+
|
213
|
+
class MaxExpectedValueBettingStrategy(MultiCategoricalMaxAccuracyBettingStrategy):
|
158
214
|
@staticmethod
|
159
|
-
def calculate_direction(
|
160
|
-
|
215
|
+
def calculate_direction(
|
216
|
+
market: AgentMarket, answer: CategoricalProbabilisticAnswer
|
217
|
+
) -> OutcomeStr:
|
218
|
+
"""
|
219
|
+
Returns the index of the outcome with the highest expected value.
|
220
|
+
"""
|
161
221
|
|
162
|
-
|
163
|
-
|
222
|
+
missing_outcomes = set([i.lower() for i in market.outcomes]) - set(
|
223
|
+
[i.lower() for i in market.probabilities.keys()]
|
224
|
+
)
|
164
225
|
|
226
|
+
if missing_outcomes:
|
227
|
+
raise ValueError(
|
228
|
+
f"Outcomes {missing_outcomes} not found in answer probabilities {answer.probabilities}"
|
229
|
+
)
|
165
230
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
231
|
+
best_outcome = None
|
232
|
+
best_ev = float("-inf")
|
233
|
+
for market_outcome in market.outcomes:
|
234
|
+
if market.probability_for_market_outcome(market_outcome) == Probability(
|
235
|
+
0.0
|
236
|
+
):
|
237
|
+
# avoid division by 0
|
238
|
+
continue
|
239
|
+
|
240
|
+
ev = answer.probability_for_market_outcome(
|
241
|
+
market_outcome
|
242
|
+
) / market.probability_for_market_outcome(market_outcome)
|
243
|
+
if ev > best_ev:
|
244
|
+
best_ev = ev
|
245
|
+
best_outcome = market_outcome
|
246
|
+
|
247
|
+
if best_outcome is None:
|
248
|
+
raise ValueError(
|
249
|
+
"Cannot determine best outcome - all market probabilities are zero"
|
250
|
+
)
|
251
|
+
|
252
|
+
return best_outcome
|
173
253
|
|
174
254
|
|
175
255
|
class KellyBettingStrategy(BettingStrategy):
|
@@ -181,40 +261,85 @@ class KellyBettingStrategy(BettingStrategy):
|
|
181
261
|
def maximum_possible_bet_amount(self) -> USD:
|
182
262
|
return self.max_bet_amount
|
183
263
|
|
264
|
+
@staticmethod
|
265
|
+
def get_kelly_bet(
|
266
|
+
market: AgentMarket,
|
267
|
+
max_bet_amount: USD,
|
268
|
+
direction: OutcomeStr,
|
269
|
+
other_direction: OutcomeStr,
|
270
|
+
answer: CategoricalProbabilisticAnswer,
|
271
|
+
override_p_yes: float | None = None,
|
272
|
+
) -> SimpleBet:
|
273
|
+
estimated_p_yes = (
|
274
|
+
answer.probability_for_market_outcome(direction)
|
275
|
+
if not override_p_yes
|
276
|
+
else override_p_yes
|
277
|
+
)
|
278
|
+
|
279
|
+
if not market.is_binary:
|
280
|
+
# use Kelly simple, since Kelly full only supports 2 outcomes
|
281
|
+
|
282
|
+
kelly_bet = get_kelly_bet_simplified(
|
283
|
+
max_bet=market.get_usd_in_token(max_bet_amount),
|
284
|
+
market_p_yes=market.probability_for_market_outcome(direction),
|
285
|
+
estimated_p_yes=estimated_p_yes,
|
286
|
+
confidence=answer.confidence,
|
287
|
+
)
|
288
|
+
else:
|
289
|
+
# We consider only binary markets, since the Kelly strategy is not yet implemented
|
290
|
+
# for markets with more than 2 outcomes (https://github.com/gnosis/prediction-market-agent-tooling/issues/671).
|
291
|
+
direction_to_bet_pool_size = market.get_outcome_token_pool_by_outcome(
|
292
|
+
direction
|
293
|
+
)
|
294
|
+
other_direction_pool_size = market.get_outcome_token_pool_by_outcome(
|
295
|
+
other_direction
|
296
|
+
)
|
297
|
+
kelly_bet = get_kelly_bet_full(
|
298
|
+
yes_outcome_pool_size=direction_to_bet_pool_size,
|
299
|
+
no_outcome_pool_size=other_direction_pool_size,
|
300
|
+
estimated_p_yes=estimated_p_yes,
|
301
|
+
max_bet=market.get_usd_in_token(max_bet_amount),
|
302
|
+
confidence=answer.confidence,
|
303
|
+
fees=market.fees,
|
304
|
+
)
|
305
|
+
return kelly_bet
|
306
|
+
|
184
307
|
def calculate_trades(
|
185
308
|
self,
|
186
309
|
existing_position: ExistingPosition | None,
|
187
|
-
answer:
|
310
|
+
answer: CategoricalProbabilisticAnswer,
|
188
311
|
market: AgentMarket,
|
189
312
|
) -> list[Trade]:
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
313
|
+
# We consider the p_yes as the direction with highest probability.
|
314
|
+
direction = MultiCategoricalMaxAccuracyBettingStrategy.calculate_direction(
|
315
|
+
market, answer
|
316
|
+
)
|
317
|
+
# We get the first direction which is != direction.
|
318
|
+
other_direction = [i for i in market.outcomes if i != direction][0]
|
319
|
+
if INVALID_OUTCOME_LOWERCASE_IDENTIFIER in other_direction.lower():
|
320
|
+
raise ValueError("Invalid outcome found as opposite direction. Exitting.")
|
321
|
+
|
322
|
+
kelly_bet = self.get_kelly_bet(
|
323
|
+
market=market,
|
324
|
+
max_bet_amount=self.max_bet_amount,
|
325
|
+
direction=direction,
|
326
|
+
other_direction=other_direction,
|
327
|
+
answer=answer,
|
202
328
|
)
|
203
329
|
|
204
330
|
kelly_bet_size = kelly_bet.size
|
205
331
|
if self.max_price_impact:
|
206
332
|
# Adjust amount
|
207
333
|
max_price_impact_bet_amount = self.calculate_bet_amount_for_price_impact(
|
208
|
-
market, kelly_bet
|
334
|
+
market, kelly_bet, direction=direction
|
209
335
|
)
|
210
336
|
|
211
337
|
# We just don't want Kelly size to extrapolate price_impact - hence we take the min.
|
212
338
|
kelly_bet_size = min(kelly_bet.size, max_price_impact_bet_amount)
|
213
339
|
|
340
|
+
bet_outcome = direction if kelly_bet.direction else other_direction
|
214
341
|
amounts = {
|
215
|
-
market.
|
216
|
-
kelly_bet.direction
|
217
|
-
): market.get_token_in_usd(kelly_bet_size),
|
342
|
+
bet_outcome: market.get_token_in_usd(kelly_bet_size),
|
218
343
|
}
|
219
344
|
target_position = Position(market_id=market.id, amounts_current=amounts)
|
220
345
|
trades = self._build_rebalance_trades_from_positions(
|
@@ -224,19 +349,16 @@ class KellyBettingStrategy(BettingStrategy):
|
|
224
349
|
|
225
350
|
def calculate_price_impact_for_bet_amount(
|
226
351
|
self,
|
227
|
-
|
352
|
+
outcome_idx: int,
|
228
353
|
bet_amount: CollateralToken,
|
229
|
-
|
230
|
-
no: OutcomeToken,
|
354
|
+
pool_balances: list[OutcomeWei],
|
231
355
|
fees: MarketFees,
|
232
356
|
) -> float:
|
233
|
-
|
234
|
-
expected_price =
|
235
|
-
no / total_outcome_tokens if buy_direction else yes / total_outcome_tokens
|
236
|
-
)
|
357
|
+
prices = AgentMarket.compute_fpmm_probabilities(pool_balances)
|
358
|
+
expected_price = prices[outcome_idx]
|
237
359
|
|
238
360
|
tokens_to_buy = get_buy_outcome_token_amount(
|
239
|
-
bet_amount,
|
361
|
+
bet_amount, outcome_idx, [i.as_outcome_token for i in pool_balances], fees
|
240
362
|
)
|
241
363
|
|
242
364
|
actual_price = bet_amount.value / tokens_to_buy.value
|
@@ -245,19 +367,17 @@ class KellyBettingStrategy(BettingStrategy):
|
|
245
367
|
return price_impact
|
246
368
|
|
247
369
|
def calculate_bet_amount_for_price_impact(
|
248
|
-
self,
|
249
|
-
market: AgentMarket,
|
250
|
-
kelly_bet: SimpleBet,
|
370
|
+
self, market: AgentMarket, kelly_bet: SimpleBet, direction: OutcomeStr
|
251
371
|
) -> CollateralToken:
|
252
372
|
def calculate_price_impact_deviation_from_target_price_impact(
|
253
373
|
bet_amount_usd: float, # Needs to be float because it's used in minimize_scalar internally.
|
254
374
|
) -> float:
|
375
|
+
outcome_idx = market.get_outcome_index(direction)
|
255
376
|
price_impact = self.calculate_price_impact_for_bet_amount(
|
256
|
-
|
257
|
-
market.get_usd_in_token(USD(bet_amount_usd)),
|
258
|
-
|
259
|
-
|
260
|
-
market.fees,
|
377
|
+
outcome_idx=outcome_idx,
|
378
|
+
bet_amount=market.get_usd_in_token(USD(bet_amount_usd)),
|
379
|
+
pool_balances=pool_balances,
|
380
|
+
fees=market.fees,
|
261
381
|
)
|
262
382
|
# We return abs for the algorithm to converge to 0 instead of the min (and possibly negative) value.
|
263
383
|
|
@@ -270,17 +390,14 @@ class KellyBettingStrategy(BettingStrategy):
|
|
270
390
|
)
|
271
391
|
return kelly_bet.size
|
272
392
|
|
273
|
-
|
274
|
-
|
275
|
-
]
|
276
|
-
no_outcome_pool_size = market.outcome_token_pool[
|
277
|
-
market.get_outcome_str_from_bool(False)
|
278
|
-
]
|
393
|
+
pool_balances = [i.as_outcome_wei for i in market.outcome_token_pool.values()]
|
394
|
+
# stay float for compatibility with `minimize_scalar`
|
395
|
+
total_pool_balance = sum([i.value for i in market.outcome_token_pool.values()])
|
279
396
|
|
280
397
|
# The bounds below have been found to work heuristically.
|
281
398
|
optimized_bet_amount = minimize_scalar(
|
282
399
|
calculate_price_impact_deviation_from_target_price_impact,
|
283
|
-
bounds=(0, 1000 *
|
400
|
+
bounds=(0, 1000 * total_pool_balance),
|
284
401
|
method="bounded",
|
285
402
|
tol=1e-11,
|
286
403
|
options={"maxiter": 10000},
|
@@ -310,37 +427,46 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
310
427
|
def calculate_trades(
|
311
428
|
self,
|
312
429
|
existing_position: ExistingPosition | None,
|
313
|
-
answer:
|
430
|
+
answer: CategoricalProbabilisticAnswer,
|
314
431
|
market: AgentMarket,
|
315
432
|
) -> list[Trade]:
|
316
433
|
adjusted_bet_amount_usd = self.adjust_bet_amount(existing_position, market)
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
market.
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
434
|
+
|
435
|
+
outcome = get_most_probable_outcome(answer.probabilities)
|
436
|
+
|
437
|
+
direction = MultiCategoricalMaxAccuracyBettingStrategy.calculate_direction(
|
438
|
+
market, answer
|
439
|
+
)
|
440
|
+
# We get the first direction which is != direction.
|
441
|
+
other_direction = (
|
442
|
+
MultiCategoricalMaxAccuracyBettingStrategy.get_other_direction(
|
443
|
+
outcomes=market.outcomes, direction=direction
|
444
|
+
)
|
445
|
+
)
|
446
|
+
|
447
|
+
# We ignore the direction nudge given by Kelly, hence we assume we have a perfect prediction.
|
448
|
+
estimated_p_yes = 1.0
|
449
|
+
|
450
|
+
kelly_bet = KellyBettingStrategy.get_kelly_bet(
|
451
|
+
market=market,
|
452
|
+
max_bet_amount=adjusted_bet_amount_usd,
|
453
|
+
direction=direction,
|
454
|
+
other_direction=other_direction,
|
455
|
+
answer=answer,
|
456
|
+
override_p_yes=estimated_p_yes,
|
335
457
|
)
|
458
|
+
|
336
459
|
kelly_bet_size_usd = market.get_token_in_usd(kelly_bet.size)
|
337
460
|
|
338
461
|
amounts = {
|
339
|
-
|
462
|
+
outcome: kelly_bet_size_usd,
|
340
463
|
}
|
341
464
|
target_position = Position(market_id=market.id, amounts_current=amounts)
|
465
|
+
|
342
466
|
trades = self._build_rebalance_trades_from_positions(
|
343
|
-
existing_position,
|
467
|
+
existing_position=existing_position,
|
468
|
+
target_position=target_position,
|
469
|
+
market=market,
|
344
470
|
)
|
345
471
|
return trades
|
346
472
|
|
@@ -3,12 +3,18 @@ from abc import ABC, abstractmethod
|
|
3
3
|
|
4
4
|
from pydantic import BaseModel
|
5
5
|
|
6
|
-
from prediction_market_agent_tooling.deploy.betting_strategy import
|
6
|
+
from prediction_market_agent_tooling.deploy.betting_strategy import (
|
7
|
+
CategoricalProbabilisticAnswer,
|
8
|
+
)
|
7
9
|
from prediction_market_agent_tooling.gtypes import USD, Probability
|
8
10
|
from prediction_market_agent_tooling.markets.agent_market import (
|
9
11
|
AgentMarket,
|
10
12
|
ProcessedTradedMarket,
|
11
13
|
)
|
14
|
+
from prediction_market_agent_tooling.markets.omen.data_models import (
|
15
|
+
OMEN_FALSE_OUTCOME,
|
16
|
+
OMEN_TRUE_OUTCOME,
|
17
|
+
)
|
12
18
|
from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
|
13
19
|
FilterBy,
|
14
20
|
SortBy,
|
@@ -69,8 +75,13 @@ class JobAgentMarket(AgentMarket, ABC):
|
|
69
75
|
deadline=self.deadline,
|
70
76
|
)
|
71
77
|
|
72
|
-
def get_job_answer(self, result: str) ->
|
78
|
+
def get_job_answer(self, result: str) -> CategoricalProbabilisticAnswer:
|
73
79
|
# Just return 100% yes with 100% confidence, because we assume the job is completed correctly.
|
74
|
-
return
|
75
|
-
|
80
|
+
return CategoricalProbabilisticAnswer(
|
81
|
+
probabilities={
|
82
|
+
OMEN_TRUE_OUTCOME: Probability(1.0),
|
83
|
+
OMEN_FALSE_OUTCOME: Probability(0.0),
|
84
|
+
},
|
85
|
+
confidence=1.0,
|
86
|
+
reasoning=result,
|
76
87
|
)
|
@@ -42,7 +42,7 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
42
42
|
self.get_token_in_usd(
|
43
43
|
self.get_buy_token_amount(
|
44
44
|
bet_amount=trade.amount,
|
45
|
-
|
45
|
+
outcome=trade.outcome,
|
46
46
|
).as_token
|
47
47
|
)
|
48
48
|
- trade.amount
|
@@ -56,7 +56,7 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
56
56
|
filter_by: FilterBy = FilterBy.OPEN,
|
57
57
|
sort_by: SortBy = SortBy.CLOSING_SOONEST,
|
58
58
|
) -> t.Sequence["OmenJobAgentMarket"]:
|
59
|
-
markets = OmenSubgraphHandler().
|
59
|
+
markets = OmenSubgraphHandler().get_omen_markets_simple(
|
60
60
|
limit=limit,
|
61
61
|
filter_by=filter_by,
|
62
62
|
sort_by=sort_by,
|
@@ -124,7 +124,7 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
124
124
|
resolution=market.resolution,
|
125
125
|
created_time=market.created_time,
|
126
126
|
close_time=market.close_time,
|
127
|
-
|
127
|
+
probabilities=market.probabilities,
|
128
128
|
url=market.url,
|
129
129
|
volume=market.volume,
|
130
130
|
creator=market.creator,
|