prediction-market-agent-tooling 0.61.1.dev462__py3-none-any.whl → 0.61.1.dev477__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/deploy/agent.py +5 -4
- prediction_market_agent_tooling/deploy/betting_strategy.py +69 -53
- prediction_market_agent_tooling/gtypes.py +27 -105
- prediction_market_agent_tooling/jobs/jobs_models.py +7 -5
- prediction_market_agent_tooling/jobs/omen/omen_jobs.py +17 -13
- prediction_market_agent_tooling/markets/agent_market.py +52 -96
- prediction_market_agent_tooling/markets/blockchain_utils.py +27 -1
- prediction_market_agent_tooling/markets/data_models.py +44 -40
- prediction_market_agent_tooling/markets/manifold/api.py +6 -2
- prediction_market_agent_tooling/markets/manifold/data_models.py +25 -33
- prediction_market_agent_tooling/markets/manifold/manifold.py +11 -8
- prediction_market_agent_tooling/markets/market_fees.py +2 -4
- prediction_market_agent_tooling/markets/omen/data_models.py +57 -66
- prediction_market_agent_tooling/markets/omen/omen.py +249 -214
- prediction_market_agent_tooling/markets/omen/omen_contracts.py +29 -31
- prediction_market_agent_tooling/markets/omen/omen_resolving.py +14 -7
- prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +14 -20
- prediction_market_agent_tooling/markets/polymarket/data_models.py +3 -3
- prediction_market_agent_tooling/markets/polymarket/data_models_web.py +4 -4
- prediction_market_agent_tooling/markets/polymarket/polymarket.py +5 -3
- prediction_market_agent_tooling/markets/seer/data_models.py +11 -8
- prediction_market_agent_tooling/markets/seer/seer.py +71 -85
- prediction_market_agent_tooling/markets/seer/seer_contracts.py +5 -10
- prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +7 -7
- prediction_market_agent_tooling/monitor/monitor.py +2 -2
- prediction_market_agent_tooling/tools/balances.py +11 -9
- prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +10 -12
- prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +24 -27
- prediction_market_agent_tooling/tools/betting_strategies/utils.py +1 -3
- prediction_market_agent_tooling/tools/contract.py +10 -14
- prediction_market_agent_tooling/tools/cow/cow_manager.py +4 -3
- prediction_market_agent_tooling/tools/cow/cow_order.py +4 -3
- prediction_market_agent_tooling/tools/langfuse_client_utils.py +1 -13
- prediction_market_agent_tooling/tools/omen/sell_positions.py +3 -6
- prediction_market_agent_tooling/tools/safe.py +6 -5
- prediction_market_agent_tooling/tools/tokens/auto_deposit.py +30 -32
- prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +22 -5
- prediction_market_agent_tooling/tools/tokens/main_token.py +2 -2
- prediction_market_agent_tooling/tools/utils.py +8 -14
- prediction_market_agent_tooling/tools/web3_utils.py +41 -24
- {prediction_market_agent_tooling-0.61.1.dev462.dist-info → prediction_market_agent_tooling-0.61.1.dev477.dist-info}/METADATA +1 -2
- {prediction_market_agent_tooling-0.61.1.dev462.dist-info → prediction_market_agent_tooling-0.61.1.dev477.dist-info}/RECORD +45 -48
- prediction_market_agent_tooling/tools/_generic_value.py +0 -248
- prediction_market_agent_tooling/tools/tokens/token_utils.py +0 -46
- prediction_market_agent_tooling/tools/tokens/usd.py +0 -63
- {prediction_market_agent_tooling-0.61.1.dev462.dist-info → prediction_market_agent_tooling-0.61.1.dev477.dist-info}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.61.1.dev462.dist-info → prediction_market_agent_tooling-0.61.1.dev477.dist-info}/WHEEL +0 -0
- {prediction_market_agent_tooling-0.61.1.dev462.dist-info → prediction_market_agent_tooling-0.61.1.dev477.dist-info}/entry_points.txt +0 -0
@@ -40,8 +40,8 @@ from prediction_market_agent_tooling.markets.agent_market import (
|
|
40
40
|
SortBy,
|
41
41
|
)
|
42
42
|
from prediction_market_agent_tooling.markets.data_models import (
|
43
|
-
ExistingPosition,
|
44
43
|
PlacedTrade,
|
44
|
+
Position,
|
45
45
|
ProbabilisticAnswer,
|
46
46
|
Trade,
|
47
47
|
)
|
@@ -582,9 +582,9 @@ class DeployableTraderAgent(DeployablePredictionAgent):
|
|
582
582
|
"""
|
583
583
|
user_id = market.get_user_id(api_keys=APIKeys())
|
584
584
|
|
585
|
-
total_amount = market.
|
585
|
+
total_amount = market.get_tiny_bet_amount().amount
|
586
586
|
if existing_position := market.get_position(user_id=user_id):
|
587
|
-
total_amount += existing_position.
|
587
|
+
total_amount += existing_position.total_amount.amount
|
588
588
|
|
589
589
|
return MaxAccuracyBettingStrategy(bet_amount=total_amount)
|
590
590
|
|
@@ -592,10 +592,11 @@ class DeployableTraderAgent(DeployablePredictionAgent):
|
|
592
592
|
self,
|
593
593
|
market: AgentMarket,
|
594
594
|
answer: ProbabilisticAnswer,
|
595
|
-
existing_position:
|
595
|
+
existing_position: Position | None,
|
596
596
|
) -> list[Trade]:
|
597
597
|
strategy = self.get_betting_strategy(market=market)
|
598
598
|
trades = strategy.calculate_trades(existing_position, answer, market)
|
599
|
+
BettingStrategy.assert_trades_currency_match_markets(market, trades)
|
599
600
|
return trades
|
600
601
|
|
601
602
|
def before_process_market(
|
@@ -2,13 +2,14 @@ from abc import ABC, abstractmethod
|
|
2
2
|
|
3
3
|
from scipy.optimize import minimize_scalar
|
4
4
|
|
5
|
-
from prediction_market_agent_tooling.gtypes import
|
5
|
+
from prediction_market_agent_tooling.gtypes import xDai
|
6
6
|
from prediction_market_agent_tooling.loggers import logger
|
7
7
|
from prediction_market_agent_tooling.markets.agent_market import AgentMarket, MarketFees
|
8
8
|
from prediction_market_agent_tooling.markets.data_models import (
|
9
|
-
|
9
|
+
Currency,
|
10
10
|
Position,
|
11
11
|
ProbabilisticAnswer,
|
12
|
+
TokenAmount,
|
12
13
|
Trade,
|
13
14
|
TradeType,
|
14
15
|
)
|
@@ -30,7 +31,7 @@ class BettingStrategy(ABC):
|
|
30
31
|
@abstractmethod
|
31
32
|
def calculate_trades(
|
32
33
|
self,
|
33
|
-
existing_position:
|
34
|
+
existing_position: Position | None,
|
34
35
|
answer: ProbabilisticAnswer,
|
35
36
|
market: AgentMarket,
|
36
37
|
) -> list[Trade]:
|
@@ -38,11 +39,21 @@ class BettingStrategy(ABC):
|
|
38
39
|
|
39
40
|
@property
|
40
41
|
@abstractmethod
|
41
|
-
def maximum_possible_bet_amount(self) ->
|
42
|
+
def maximum_possible_bet_amount(self) -> float:
|
42
43
|
raise NotImplementedError("Subclass should implement this.")
|
43
44
|
|
44
|
-
def
|
45
|
-
return
|
45
|
+
def build_zero_token_amount(self, currency: Currency) -> TokenAmount:
|
46
|
+
return TokenAmount(amount=0, currency=currency)
|
47
|
+
|
48
|
+
@staticmethod
|
49
|
+
def assert_trades_currency_match_markets(
|
50
|
+
market: AgentMarket, trades: list[Trade]
|
51
|
+
) -> None:
|
52
|
+
currencies_match = all([t.amount.currency == market.currency for t in trades])
|
53
|
+
if not currencies_match:
|
54
|
+
raise ValueError(
|
55
|
+
"Cannot handle trades with currencies that deviate from market's currency"
|
56
|
+
)
|
46
57
|
|
47
58
|
@staticmethod
|
48
59
|
def assert_buy_trade_wont_be_guaranteed_loss(
|
@@ -53,21 +64,20 @@ class BettingStrategy(ABC):
|
|
53
64
|
outcome_tokens_to_get = market.get_buy_token_amount(
|
54
65
|
trade.amount, trade.outcome
|
55
66
|
)
|
56
|
-
|
57
|
-
|
58
|
-
)
|
59
|
-
if outcome_tokens_to_get_in_usd <= trade.amount:
|
67
|
+
|
68
|
+
if outcome_tokens_to_get.amount < trade.amount.amount:
|
60
69
|
raise GuaranteedLossError(
|
61
70
|
f"Trade {trade=} would result in guaranteed loss by getting only {outcome_tokens_to_get=}."
|
62
71
|
)
|
63
72
|
|
64
73
|
@staticmethod
|
65
74
|
def check_trades(market: AgentMarket, trades: list[Trade]) -> None:
|
75
|
+
BettingStrategy.assert_trades_currency_match_markets(market, trades)
|
66
76
|
BettingStrategy.assert_buy_trade_wont_be_guaranteed_loss(market, trades)
|
67
77
|
|
68
78
|
def _build_rebalance_trades_from_positions(
|
69
79
|
self,
|
70
|
-
existing_position:
|
80
|
+
existing_position: Position | None,
|
71
81
|
target_position: Position,
|
72
82
|
market: AgentMarket,
|
73
83
|
) -> list[Trade]:
|
@@ -85,20 +95,23 @@ class BettingStrategy(ABC):
|
|
85
95
|
trades = []
|
86
96
|
for outcome_bool in [True, False]:
|
87
97
|
outcome = market.get_outcome_str_from_bool(outcome_bool)
|
88
|
-
prev_amount = (
|
89
|
-
existing_position.
|
90
|
-
if existing_position and outcome in existing_position.
|
91
|
-
else self.
|
98
|
+
prev_amount: TokenAmount = (
|
99
|
+
existing_position.amounts[outcome]
|
100
|
+
if existing_position and outcome in existing_position.amounts
|
101
|
+
else self.build_zero_token_amount(currency=market.currency)
|
92
102
|
)
|
93
|
-
new_amount = target_position.
|
94
|
-
outcome, self.
|
103
|
+
new_amount: TokenAmount = target_position.amounts.get(
|
104
|
+
outcome, self.build_zero_token_amount(currency=market.currency)
|
95
105
|
)
|
96
|
-
|
106
|
+
|
107
|
+
if prev_amount.currency != new_amount.currency:
|
108
|
+
raise ValueError("Cannot handle positions with different currencies")
|
109
|
+
diff_amount = new_amount.amount - prev_amount.amount
|
97
110
|
if diff_amount == 0:
|
98
111
|
continue
|
99
112
|
trade_type = TradeType.SELL if diff_amount < 0 else TradeType.BUY
|
100
113
|
trade = Trade(
|
101
|
-
amount=abs(diff_amount),
|
114
|
+
amount=TokenAmount(amount=abs(diff_amount), currency=market.currency),
|
102
115
|
outcome=outcome_bool,
|
103
116
|
trade_type=trade_type,
|
104
117
|
)
|
@@ -115,25 +128,28 @@ class BettingStrategy(ABC):
|
|
115
128
|
|
116
129
|
|
117
130
|
class MaxAccuracyBettingStrategy(BettingStrategy):
|
118
|
-
def __init__(self, bet_amount:
|
131
|
+
def __init__(self, bet_amount: float):
|
119
132
|
self.bet_amount = bet_amount
|
120
133
|
|
121
134
|
@property
|
122
|
-
def maximum_possible_bet_amount(self) ->
|
135
|
+
def maximum_possible_bet_amount(self) -> float:
|
123
136
|
return self.bet_amount
|
124
137
|
|
125
138
|
def calculate_trades(
|
126
139
|
self,
|
127
|
-
existing_position:
|
140
|
+
existing_position: Position | None,
|
128
141
|
answer: ProbabilisticAnswer,
|
129
142
|
market: AgentMarket,
|
130
143
|
) -> list[Trade]:
|
131
144
|
direction = self.calculate_direction(market.current_p_yes, answer.p_yes)
|
132
145
|
|
133
146
|
amounts = {
|
134
|
-
market.get_outcome_str_from_bool(direction):
|
147
|
+
market.get_outcome_str_from_bool(direction): TokenAmount(
|
148
|
+
amount=self.bet_amount,
|
149
|
+
currency=market.currency,
|
150
|
+
),
|
135
151
|
}
|
136
|
-
target_position = Position(market_id=market.id,
|
152
|
+
target_position = Position(market_id=market.id, amounts=amounts)
|
137
153
|
trades = self._build_rebalance_trades_from_positions(
|
138
154
|
existing_position, target_position, market=market
|
139
155
|
)
|
@@ -157,17 +173,17 @@ class MaxExpectedValueBettingStrategy(MaxAccuracyBettingStrategy):
|
|
157
173
|
|
158
174
|
|
159
175
|
class KellyBettingStrategy(BettingStrategy):
|
160
|
-
def __init__(self, max_bet_amount:
|
176
|
+
def __init__(self, max_bet_amount: float, max_price_impact: float | None = None):
|
161
177
|
self.max_bet_amount = max_bet_amount
|
162
178
|
self.max_price_impact = max_price_impact
|
163
179
|
|
164
180
|
@property
|
165
|
-
def maximum_possible_bet_amount(self) ->
|
181
|
+
def maximum_possible_bet_amount(self) -> float:
|
166
182
|
return self.max_bet_amount
|
167
183
|
|
168
184
|
def calculate_trades(
|
169
185
|
self,
|
170
|
-
existing_position:
|
186
|
+
existing_position: Position | None,
|
171
187
|
answer: ProbabilisticAnswer,
|
172
188
|
market: AgentMarket,
|
173
189
|
) -> list[Trade]:
|
@@ -180,7 +196,7 @@ class KellyBettingStrategy(BettingStrategy):
|
|
180
196
|
market.get_outcome_str_from_bool(False)
|
181
197
|
],
|
182
198
|
estimated_p_yes=answer.p_yes,
|
183
|
-
max_bet=
|
199
|
+
max_bet=self.max_bet_amount,
|
184
200
|
confidence=answer.confidence,
|
185
201
|
fees=market.fees,
|
186
202
|
)
|
@@ -196,11 +212,11 @@ class KellyBettingStrategy(BettingStrategy):
|
|
196
212
|
kelly_bet_size = min(kelly_bet.size, max_price_impact_bet_amount)
|
197
213
|
|
198
214
|
amounts = {
|
199
|
-
market.get_outcome_str_from_bool(
|
200
|
-
|
201
|
-
)
|
215
|
+
market.get_outcome_str_from_bool(kelly_bet.direction): TokenAmount(
|
216
|
+
amount=kelly_bet_size, currency=market.currency
|
217
|
+
),
|
202
218
|
}
|
203
|
-
target_position = Position(market_id=market.id,
|
219
|
+
target_position = Position(market_id=market.id, amounts=amounts)
|
204
220
|
trades = self._build_rebalance_trades_from_positions(
|
205
221
|
existing_position, target_position, market=market
|
206
222
|
)
|
@@ -209,9 +225,9 @@ class KellyBettingStrategy(BettingStrategy):
|
|
209
225
|
def calculate_price_impact_for_bet_amount(
|
210
226
|
self,
|
211
227
|
buy_direction: bool,
|
212
|
-
bet_amount:
|
213
|
-
yes:
|
214
|
-
no:
|
228
|
+
bet_amount: float,
|
229
|
+
yes: float,
|
230
|
+
no: float,
|
215
231
|
fees: MarketFees,
|
216
232
|
) -> float:
|
217
233
|
total_outcome_tokens = yes + no
|
@@ -223,7 +239,7 @@ class KellyBettingStrategy(BettingStrategy):
|
|
223
239
|
bet_amount, buy_direction, yes, no, fees
|
224
240
|
)
|
225
241
|
|
226
|
-
actual_price = bet_amount
|
242
|
+
actual_price = bet_amount / tokens_to_buy
|
227
243
|
# price_impact should always be > 0
|
228
244
|
price_impact = (actual_price - expected_price) / expected_price
|
229
245
|
return price_impact
|
@@ -232,13 +248,13 @@ class KellyBettingStrategy(BettingStrategy):
|
|
232
248
|
self,
|
233
249
|
market: AgentMarket,
|
234
250
|
kelly_bet: SimpleBet,
|
235
|
-
) ->
|
251
|
+
) -> float:
|
236
252
|
def calculate_price_impact_deviation_from_target_price_impact(
|
237
|
-
|
253
|
+
bet_amount: xDai,
|
238
254
|
) -> float:
|
239
255
|
price_impact = self.calculate_price_impact_for_bet_amount(
|
240
256
|
kelly_bet.direction,
|
241
|
-
|
257
|
+
bet_amount,
|
242
258
|
yes_outcome_pool_size,
|
243
259
|
no_outcome_pool_size,
|
244
260
|
market.fees,
|
@@ -264,41 +280,40 @@ class KellyBettingStrategy(BettingStrategy):
|
|
264
280
|
# The bounds below have been found to work heuristically.
|
265
281
|
optimized_bet_amount = minimize_scalar(
|
266
282
|
calculate_price_impact_deviation_from_target_price_impact,
|
267
|
-
bounds=(0, 1000 * (yes_outcome_pool_size + no_outcome_pool_size)
|
283
|
+
bounds=(0, 1000 * (yes_outcome_pool_size + no_outcome_pool_size)),
|
268
284
|
method="bounded",
|
269
285
|
tol=1e-11,
|
270
286
|
options={"maxiter": 10000},
|
271
287
|
)
|
272
|
-
return
|
288
|
+
return float(optimized_bet_amount.x)
|
273
289
|
|
274
290
|
def __repr__(self) -> str:
|
275
291
|
return f"{self.__class__.__name__}(max_bet_amount={self.max_bet_amount}, max_price_impact={self.max_price_impact})"
|
276
292
|
|
277
293
|
|
278
294
|
class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
279
|
-
def __init__(self, max_bet_amount:
|
295
|
+
def __init__(self, max_bet_amount: float = 10):
|
280
296
|
self.max_bet_amount = max_bet_amount
|
281
297
|
|
282
298
|
@property
|
283
|
-
def maximum_possible_bet_amount(self) ->
|
299
|
+
def maximum_possible_bet_amount(self) -> float:
|
284
300
|
return self.max_bet_amount
|
285
301
|
|
286
302
|
def adjust_bet_amount(
|
287
|
-
self, existing_position:
|
288
|
-
) ->
|
303
|
+
self, existing_position: Position | None, market: AgentMarket
|
304
|
+
) -> float:
|
289
305
|
existing_position_total_amount = (
|
290
|
-
existing_position.
|
306
|
+
existing_position.total_amount.amount if existing_position else 0
|
291
307
|
)
|
292
308
|
return self.max_bet_amount + existing_position_total_amount
|
293
309
|
|
294
310
|
def calculate_trades(
|
295
311
|
self,
|
296
|
-
existing_position:
|
312
|
+
existing_position: Position | None,
|
297
313
|
answer: ProbabilisticAnswer,
|
298
314
|
market: AgentMarket,
|
299
315
|
) -> list[Trade]:
|
300
|
-
|
301
|
-
adjusted_bet_amount_token = market.get_usd_in_token(adjusted_bet_amount_usd)
|
316
|
+
adjusted_bet_amount = self.adjust_bet_amount(existing_position, market)
|
302
317
|
outcome_token_pool = check_not_none(market.outcome_token_pool)
|
303
318
|
|
304
319
|
# Fixed direction of bet, only use Kelly to adjust the bet size based on market's outcome pool size.
|
@@ -313,16 +328,17 @@ class MaxAccuracyWithKellyScaledBetsStrategy(BettingStrategy):
|
|
313
328
|
market.get_outcome_str_from_bool(False)
|
314
329
|
],
|
315
330
|
estimated_p_yes=estimated_p_yes,
|
316
|
-
max_bet=
|
331
|
+
max_bet=adjusted_bet_amount,
|
317
332
|
confidence=confidence,
|
318
333
|
fees=market.fees,
|
319
334
|
)
|
320
|
-
kelly_bet_size_usd = market.get_token_in_usd(kelly_bet.size)
|
321
335
|
|
322
336
|
amounts = {
|
323
|
-
market.get_outcome_str_from_bool(kelly_bet.direction):
|
337
|
+
market.get_outcome_str_from_bool(kelly_bet.direction): TokenAmount(
|
338
|
+
amount=kelly_bet.size, currency=market.currency
|
339
|
+
),
|
324
340
|
}
|
325
|
-
target_position = Position(market_id=market.id,
|
341
|
+
target_position = Position(market_id=market.id, amounts=amounts)
|
326
342
|
trades = self._build_rebalance_trades_from_positions(
|
327
343
|
existing_position, target_position, market=market
|
328
344
|
)
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import typing as t
|
2
|
-
from
|
3
|
-
from typing import NewType
|
2
|
+
from typing import NewType, Union
|
4
3
|
|
5
4
|
from eth_typing.evm import ( # noqa: F401 # Import for the sake of easy importing with others from here.
|
6
5
|
Address,
|
@@ -10,15 +9,13 @@ from eth_typing.evm import ( # noqa: F401 # Import for the sake of easy import
|
|
10
9
|
)
|
11
10
|
from pydantic.types import SecretStr
|
12
11
|
from pydantic.v1.types import SecretStr as SecretStrV1
|
13
|
-
from web3 import Web3
|
14
12
|
from web3.types import ( # noqa: F401 # Import for the sake of easy importing with others from here.
|
15
13
|
Nonce,
|
16
14
|
TxParams,
|
17
15
|
TxReceipt,
|
16
|
+
Wei,
|
18
17
|
)
|
19
|
-
from web3.types import Wei as Web3Wei
|
20
18
|
|
21
|
-
from prediction_market_agent_tooling.tools._generic_value import _GenericValue
|
22
19
|
from prediction_market_agent_tooling.tools.datetime_utc import ( # noqa: F401 # Import for the sake of easy importing with others from here.
|
23
20
|
DatetimeUTC,
|
24
21
|
)
|
@@ -26,118 +23,43 @@ from prediction_market_agent_tooling.tools.hexbytes_custom import ( # noqa: F40
|
|
26
23
|
HexBytes,
|
27
24
|
)
|
28
25
|
|
26
|
+
Wad = Wei # Wei tends to be referred to as `wad` variable in contracts.
|
27
|
+
USD = NewType("USD", float)
|
28
|
+
PrivateKey = NewType("PrivateKey", SecretStr)
|
29
|
+
xDai = NewType("xDai", float)
|
30
|
+
GNO = NewType("GNO", float)
|
31
|
+
ABI = NewType("ABI", str)
|
32
|
+
OmenOutcomeToken = NewType("OmenOutcomeToken", Wei)
|
33
|
+
OutcomeStr = NewType("OutcomeStr", str)
|
34
|
+
Probability = NewType("Probability", float)
|
35
|
+
Mana = NewType("Mana", float) # Manifold's "currency"
|
36
|
+
USDC = NewType("USDC", float)
|
37
|
+
ChainID = NewType("ChainID", int)
|
38
|
+
IPFSCIDVersion0 = NewType("IPFSCIDVersion0", str)
|
29
39
|
|
30
|
-
class Token(_GenericValue[int | float | str | Decimal, float], parser=float):
|
31
|
-
"""
|
32
|
-
Represents any token in its decimal form, it could be 1.1 GNO, WXDAI, XDAI, Mana, whatever. We don't know the currency, just that it's in the decimal form.
|
33
|
-
"""
|
34
|
-
|
35
|
-
@property
|
36
|
-
def as_wei(self) -> "Wei":
|
37
|
-
return Wei(Web3.to_wei(self.value, "ether"))
|
38
|
-
|
39
|
-
|
40
|
-
class OutcomeToken(_GenericValue[int | float | str | Decimal, float], parser=float):
|
41
|
-
"""
|
42
|
-
Represents outcome tokens in market in decimal form.
|
43
|
-
After you redeem the outcome tokens, 1 OutcomeToken equals to 1 Token, but before, it's important to distinguish between them.
|
44
|
-
For example, it's a big difference if you are going to sell 1 OutcomeToken, or 1 (collateral) Token.
|
45
|
-
But still, Token and OutcomeToken needs to be handled together in many cases, use available properties to convert between them explicitly.
|
46
|
-
"""
|
47
|
-
|
48
|
-
@staticmethod
|
49
|
-
def from_token(token: Token) -> "OutcomeToken":
|
50
|
-
return OutcomeToken(token.value)
|
51
|
-
|
52
|
-
@property
|
53
|
-
def as_outcome_wei(self) -> "OutcomeWei":
|
54
|
-
return OutcomeWei(Web3.to_wei(self.value, "ether"))
|
55
|
-
|
56
|
-
@property
|
57
|
-
def as_token(self) -> Token:
|
58
|
-
"""
|
59
|
-
OutcomeToken is essentialy Token as well, when you know you really need to convert it, you can convert it explicitly using this.
|
60
|
-
"""
|
61
|
-
return Token(self.value)
|
62
|
-
|
63
|
-
|
64
|
-
class USD(_GenericValue[int | float | str | Decimal, float], parser=float):
|
65
|
-
"""Represents values in USD."""
|
66
|
-
|
67
|
-
|
68
|
-
class xDai(_GenericValue[int | float | str | Decimal, float], parser=float):
|
69
|
-
"""Represents values in xDai."""
|
70
|
-
|
71
|
-
@property
|
72
|
-
def as_token(self) -> Token:
|
73
|
-
"""
|
74
|
-
xDai is essentialy Token as well, when you know you need to pass it, you can convert it using this.
|
75
|
-
"""
|
76
|
-
return Token(self.value)
|
77
|
-
|
78
|
-
@property
|
79
|
-
def as_xdai_wei(self) -> "xDaiWei":
|
80
|
-
return xDaiWei(Web3.to_wei(self.value, "ether"))
|
81
|
-
|
82
|
-
|
83
|
-
class Mana(_GenericValue[int | float | str | Decimal, float], parser=float):
|
84
|
-
"""Represents values in Manifold's Mana."""
|
85
|
-
|
86
|
-
|
87
|
-
class USDC(_GenericValue[int | float | str | Decimal, float], parser=float):
|
88
|
-
"""Represents values in USDC."""
|
89
|
-
|
90
|
-
|
91
|
-
class Wei(_GenericValue[Web3Wei | int | str, Web3Wei], parser=int):
|
92
|
-
"""Represents values in Wei. We don't know what currency, but in its integer form called Wei."""
|
93
|
-
|
94
|
-
@property
|
95
|
-
def as_token(self) -> Token:
|
96
|
-
return Token(Web3.from_wei(self.value, "ether"))
|
97
40
|
|
41
|
+
def usd_type(amount: Union[str, int, float]) -> USD:
|
42
|
+
return USD(float(amount))
|
98
43
|
|
99
|
-
class OutcomeWei(_GenericValue[Web3Wei | int | str, Web3Wei], parser=int):
|
100
|
-
"""
|
101
|
-
Similar to OutcomeToken, but in Wei units.
|
102
|
-
"""
|
103
44
|
|
104
|
-
|
105
|
-
|
106
|
-
return OutcomeWei(wei.value)
|
45
|
+
def wei_type(amount: Union[str, int, float]) -> Wei:
|
46
|
+
return Wei(int(amount))
|
107
47
|
|
108
|
-
@property
|
109
|
-
def as_outcome_token(self) -> OutcomeToken:
|
110
|
-
return OutcomeToken(Web3.from_wei(self.value, "ether"))
|
111
48
|
|
112
|
-
|
113
|
-
|
114
|
-
"""
|
115
|
-
OutcomeWei is essentialy Wei as well, when you know you need to pass it, you can convert it using this.
|
116
|
-
"""
|
117
|
-
return Wei(self.value)
|
49
|
+
def omen_outcome_type(amount: Union[str, int, Wei]) -> OmenOutcomeToken:
|
50
|
+
return OmenOutcomeToken(wei_type(amount))
|
118
51
|
|
119
52
|
|
120
|
-
|
121
|
-
|
53
|
+
def xdai_type(amount: Union[str, int, float]) -> xDai:
|
54
|
+
return xDai(float(amount))
|
122
55
|
|
123
|
-
@property
|
124
|
-
def as_xdai(self) -> xDai:
|
125
|
-
return xDai(Web3.from_wei(self.value, "ether"))
|
126
56
|
|
127
|
-
|
128
|
-
|
129
|
-
"""
|
130
|
-
xDaiWei is essentialy Wei as well, when you know you need to pass it, you can convert it using this.
|
131
|
-
"""
|
132
|
-
return Wei(self.value)
|
57
|
+
def mana_type(amount: Union[str, int, float]) -> Mana:
|
58
|
+
return Mana(float(amount))
|
133
59
|
|
134
60
|
|
135
|
-
|
136
|
-
|
137
|
-
OutcomeStr = NewType("OutcomeStr", str)
|
138
|
-
Probability = NewType("Probability", float)
|
139
|
-
ChainID = NewType("ChainID", int)
|
140
|
-
IPFSCIDVersion0 = NewType("IPFSCIDVersion0", str)
|
61
|
+
def usdc_type(amount: Union[str, int, float]) -> USDC:
|
62
|
+
return USDC(float(amount))
|
141
63
|
|
142
64
|
|
143
65
|
def private_key_type(k: str) -> PrivateKey:
|
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
|
|
4
4
|
from pydantic import BaseModel
|
5
5
|
|
6
6
|
from prediction_market_agent_tooling.deploy.betting_strategy import ProbabilisticAnswer
|
7
|
-
from prediction_market_agent_tooling.gtypes import
|
7
|
+
from prediction_market_agent_tooling.gtypes import Probability
|
8
8
|
from prediction_market_agent_tooling.markets.agent_market import (
|
9
9
|
AgentMarket,
|
10
10
|
ProcessedTradedMarket,
|
@@ -19,7 +19,8 @@ from prediction_market_agent_tooling.tools.utils import DatetimeUTC
|
|
19
19
|
class SimpleJob(BaseModel):
|
20
20
|
id: str
|
21
21
|
job: str
|
22
|
-
reward:
|
22
|
+
reward: float
|
23
|
+
currency: str
|
23
24
|
deadline: DatetimeUTC
|
24
25
|
|
25
26
|
|
@@ -37,7 +38,7 @@ class JobAgentMarket(AgentMarket, ABC):
|
|
37
38
|
"""Deadline for the job completion."""
|
38
39
|
|
39
40
|
@abstractmethod
|
40
|
-
def get_reward(self, max_bond:
|
41
|
+
def get_reward(self, max_bond: float) -> float:
|
41
42
|
"""Reward for completing this job."""
|
42
43
|
|
43
44
|
@classmethod
|
@@ -57,15 +58,16 @@ class JobAgentMarket(AgentMarket, ABC):
|
|
57
58
|
|
58
59
|
@abstractmethod
|
59
60
|
def submit_job_result(
|
60
|
-
self, agent_name: str, max_bond:
|
61
|
+
self, agent_name: str, max_bond: float, result: str
|
61
62
|
) -> ProcessedTradedMarket:
|
62
63
|
"""Submit the completed result for this job."""
|
63
64
|
|
64
|
-
def to_simple_job(self, max_bond:
|
65
|
+
def to_simple_job(self, max_bond: float) -> SimpleJob:
|
65
66
|
return SimpleJob(
|
66
67
|
id=self.id,
|
67
68
|
job=self.job,
|
68
69
|
reward=self.get_reward(max_bond),
|
70
|
+
currency=self.currency.value,
|
69
71
|
deadline=self.deadline,
|
70
72
|
)
|
71
73
|
|
@@ -2,14 +2,15 @@ import typing as t
|
|
2
2
|
|
3
3
|
from prediction_market_agent_tooling.config import APIKeys
|
4
4
|
from prediction_market_agent_tooling.deploy.betting_strategy import (
|
5
|
+
Currency,
|
5
6
|
KellyBettingStrategy,
|
6
7
|
TradeType,
|
7
8
|
)
|
8
|
-
from prediction_market_agent_tooling.gtypes import USD
|
9
9
|
from prediction_market_agent_tooling.jobs.jobs_models import JobAgentMarket
|
10
10
|
from prediction_market_agent_tooling.markets.agent_market import ProcessedTradedMarket
|
11
11
|
from prediction_market_agent_tooling.markets.data_models import PlacedTrade, Trade
|
12
12
|
from prediction_market_agent_tooling.markets.omen.omen import (
|
13
|
+
BetAmount,
|
13
14
|
OmenAgentMarket,
|
14
15
|
OmenMarket,
|
15
16
|
)
|
@@ -33,21 +34,21 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
33
34
|
def deadline(self) -> DatetimeUTC:
|
34
35
|
return self.close_time
|
35
36
|
|
36
|
-
def get_reward(self, max_bond:
|
37
|
+
def get_reward(self, max_bond: float) -> float:
|
37
38
|
trade = self.get_job_trade(
|
38
39
|
max_bond,
|
39
40
|
result="", # Pass empty result, as we are computing only potential reward at this point.
|
40
41
|
)
|
41
|
-
|
42
|
-
self.
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
)
|
48
|
-
- trade.amount
|
42
|
+
reward = (
|
43
|
+
self.get_buy_token_amount(
|
44
|
+
bet_amount=BetAmount(
|
45
|
+
amount=trade.amount.amount, currency=trade.amount.currency
|
46
|
+
),
|
47
|
+
direction=trade.outcome,
|
48
|
+
).amount
|
49
|
+
- trade.amount.amount
|
49
50
|
)
|
50
|
-
return
|
51
|
+
return reward
|
51
52
|
|
52
53
|
@classmethod
|
53
54
|
def get_jobs(
|
@@ -71,7 +72,7 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
71
72
|
)
|
72
73
|
|
73
74
|
def submit_job_result(
|
74
|
-
self, agent_name: str, max_bond:
|
75
|
+
self, agent_name: str, max_bond: float, result: str
|
75
76
|
) -> ProcessedTradedMarket:
|
76
77
|
if not APIKeys().enable_ipfs_upload:
|
77
78
|
raise RuntimeError(
|
@@ -91,7 +92,7 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
91
92
|
|
92
93
|
return processed_traded_market
|
93
94
|
|
94
|
-
def get_job_trade(self, max_bond:
|
95
|
+
def get_job_trade(self, max_bond: float, result: str) -> Trade:
|
95
96
|
# 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
97
|
strategy = KellyBettingStrategy(max_bet_amount=max_bond)
|
97
98
|
required_trades = strategy.calculate_trades(
|
@@ -105,6 +106,9 @@ class OmenJobAgentMarket(OmenAgentMarket, JobAgentMarket):
|
|
105
106
|
trade = required_trades[0]
|
106
107
|
assert trade.trade_type == TradeType.BUY, "Should only buy on job markets."
|
107
108
|
assert trade.outcome, "Should buy only YES on job markets."
|
109
|
+
assert (
|
110
|
+
trade.amount.currency == Currency.xDai
|
111
|
+
), "Should work only on real-money markets."
|
108
112
|
return required_trades[0]
|
109
113
|
|
110
114
|
@staticmethod
|