prediction-market-agent-tooling 0.14.1__tar.gz → 0.15.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/PKG-INFO +13 -1
  2. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/README.md +8 -0
  3. prediction_market_agent_tooling-0.15.1/prediction_market_agent_tooling/abis/erc20.abi.json +315 -0
  4. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/benchmark/agents.py +7 -1
  5. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/benchmark/benchmark.py +22 -24
  6. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/benchmark/utils.py +4 -0
  7. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/config.py +27 -4
  8. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/deploy/agent.py +3 -3
  9. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/agent_market.py +20 -9
  10. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/manifold/manifold.py +9 -1
  11. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/omen/data_models.py +42 -11
  12. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/omen/omen.py +135 -52
  13. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +36 -34
  14. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/omen/omen_replicate.py +11 -16
  15. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/omen/omen_resolve_replicated.py +32 -25
  16. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +46 -13
  17. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +1 -1
  18. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/monitor/markets/omen.py +5 -3
  19. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/monitor/markets/polymarket.py +3 -2
  20. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/monitor/monitor.py +26 -20
  21. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +1 -1
  22. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/contract.py +32 -17
  23. prediction_market_agent_tooling-0.15.1/prediction_market_agent_tooling/tools/costs.py +31 -0
  24. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/parallelism.py +16 -1
  25. prediction_market_agent_tooling-0.15.1/prediction_market_agent_tooling/tools/safe.py +130 -0
  26. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/web3_utils.py +100 -15
  27. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/pyproject.toml +5 -1
  28. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/LICENSE +0 -0
  29. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
  30. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
  31. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
  32. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
  33. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
  34. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
  35. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
  36. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/abis/wxdai.abi.json +0 -0
  37. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
  38. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
  39. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/deploy/constants.py +0 -0
  40. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
  41. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
  42. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
  43. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/gtypes.py +0 -0
  44. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/categorize.py +0 -0
  45. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/data_models.py +0 -0
  46. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
  47. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
  48. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
  49. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
  50. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/markets.py +0 -0
  51. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
  52. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
  53. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
  54. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -0
  55. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
  56. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
  57. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
  58. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
  59. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/py.typed +0 -0
  60. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/balances.py +0 -0
  61. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
  62. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
  63. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
  64. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/cache.py +0 -0
  65. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -0
  66. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/google.py +0 -0
  67. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
  68. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
  69. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/singleton.py +0 -0
  70. {prediction_market_agent_tooling-0.14.1 → prediction_market_agent_tooling-0.15.1}/prediction_market_agent_tooling/tools/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.14.1
3
+ Version: 0.15.1
4
4
  Summary: Tools to benchmark, deploy and monitor prediction market agents.
5
5
  Author: Gnosis
6
6
  Requires-Python: >=3.10,<3.12
@@ -11,6 +11,7 @@ Provides-Extra: google
11
11
  Provides-Extra: langchain
12
12
  Requires-Dist: autoflake (>=2.2.1,<3.0.0)
13
13
  Requires-Dist: cron-validator (>=1.0.8,<2.0.0)
14
+ Requires-Dist: eth-account (>=0.8.0,<0.9.0)
14
15
  Requires-Dist: eth-typing (>=3.0.0,<4.0.0)
15
16
  Requires-Dist: functions-framework (>=3.5.0,<4.0.0)
16
17
  Requires-Dist: google-api-python-client (==2.95.0) ; extra == "google"
@@ -24,8 +25,11 @@ Requires-Dist: langchain-openai (>=0.0.5,<0.0.6) ; extra == "langchain"
24
25
  Requires-Dist: loguru (>=0.7.2,<0.8.0)
25
26
  Requires-Dist: mech-client (>=0.2.13,<0.3.0)
26
27
  Requires-Dist: numpy (>=1.26.4,<2.0.0)
28
+ Requires-Dist: prompt-toolkit (>=3.0.43,<4.0.0)
27
29
  Requires-Dist: pydantic (>=2.6.1,<3.0.0)
28
30
  Requires-Dist: pydantic-settings (>=2.1.0,<3.0.0)
31
+ Requires-Dist: safe-cli (>=1.0.0,<2.0.0)
32
+ Requires-Dist: safe-eth-py (>=6.0.0b14,<7.0.0)
29
33
  Requires-Dist: scikit-learn (>=1.4.0,<2.0.0)
30
34
  Requires-Dist: streamlit (>=1.31.0,<2.0.0)
31
35
  Requires-Dist: subgrounds (>=1.8.1,<2.0.0)
@@ -104,6 +108,14 @@ class DeployableCoinFlipAgent(DeployableAgent):
104
108
  DeployableCoinFlipAgent().deploy_gcp(...)
105
109
  ```
106
110
 
111
+ For deploying a Safe manually for a given agent, run the script below:
112
+
113
+ ```commandline
114
+ poetry run python scripts/create_safe_for_agent.py --from-private-key <YOUR_AGENT_PRIVATE_KEY> --salt-nonce 42
115
+ ```
116
+ This will output the newly created Safe in the terminal, and it can then be copied over to the deployment part (e.g. Terraform).
117
+ Note that `salt_nonce` can be passed so that the created safe is deterministically created for each agent, so that, if the same `salt_nonce` is used, the script will not create a new Safe for the agent, instead it will output the previously existent Safe.
118
+
107
119
  ## Monitoring
108
120
 
109
121
  Monitor the performance of the agents deployed to GCP, as well as meta-metrics of the prediction market platforms they are deployed to.
@@ -65,6 +65,14 @@ class DeployableCoinFlipAgent(DeployableAgent):
65
65
  DeployableCoinFlipAgent().deploy_gcp(...)
66
66
  ```
67
67
 
68
+ For deploying a Safe manually for a given agent, run the script below:
69
+
70
+ ```commandline
71
+ poetry run python scripts/create_safe_for_agent.py --from-private-key <YOUR_AGENT_PRIVATE_KEY> --salt-nonce 42
72
+ ```
73
+ This will output the newly created Safe in the terminal, and it can then be copied over to the deployment part (e.g. Terraform).
74
+ Note that `salt_nonce` can be passed so that the created safe is deterministically created for each agent, so that, if the same `salt_nonce` is used, the script will not create a new Safe for the agent, instead it will output the previously existent Safe.
75
+
68
76
  ## Monitoring
69
77
 
70
78
  Monitor the performance of the agents deployed to GCP, as well as meta-metrics of the prediction market platforms they are deployed to.
@@ -0,0 +1,315 @@
1
+ [
2
+ {
3
+ "inputs": [],
4
+ "stateMutability": "nonpayable",
5
+ "type": "constructor"
6
+ },
7
+ {
8
+ "inputs": [
9
+ {
10
+ "internalType": "address",
11
+ "name": "spender",
12
+ "type": "address"
13
+ },
14
+ {
15
+ "internalType": "uint256",
16
+ "name": "allowance",
17
+ "type": "uint256"
18
+ },
19
+ {
20
+ "internalType": "uint256",
21
+ "name": "needed",
22
+ "type": "uint256"
23
+ }
24
+ ],
25
+ "name": "ERC20InsufficientAllowance",
26
+ "type": "error"
27
+ },
28
+ {
29
+ "inputs": [
30
+ {
31
+ "internalType": "address",
32
+ "name": "sender",
33
+ "type": "address"
34
+ },
35
+ {
36
+ "internalType": "uint256",
37
+ "name": "balance",
38
+ "type": "uint256"
39
+ },
40
+ {
41
+ "internalType": "uint256",
42
+ "name": "needed",
43
+ "type": "uint256"
44
+ }
45
+ ],
46
+ "name": "ERC20InsufficientBalance",
47
+ "type": "error"
48
+ },
49
+ {
50
+ "inputs": [
51
+ {
52
+ "internalType": "address",
53
+ "name": "approver",
54
+ "type": "address"
55
+ }
56
+ ],
57
+ "name": "ERC20InvalidApprover",
58
+ "type": "error"
59
+ },
60
+ {
61
+ "inputs": [
62
+ {
63
+ "internalType": "address",
64
+ "name": "receiver",
65
+ "type": "address"
66
+ }
67
+ ],
68
+ "name": "ERC20InvalidReceiver",
69
+ "type": "error"
70
+ },
71
+ {
72
+ "inputs": [
73
+ {
74
+ "internalType": "address",
75
+ "name": "sender",
76
+ "type": "address"
77
+ }
78
+ ],
79
+ "name": "ERC20InvalidSender",
80
+ "type": "error"
81
+ },
82
+ {
83
+ "inputs": [
84
+ {
85
+ "internalType": "address",
86
+ "name": "spender",
87
+ "type": "address"
88
+ }
89
+ ],
90
+ "name": "ERC20InvalidSpender",
91
+ "type": "error"
92
+ },
93
+ {
94
+ "anonymous": False,
95
+ "inputs": [
96
+ {
97
+ "indexed": True,
98
+ "internalType": "address",
99
+ "name": "owner",
100
+ "type": "address"
101
+ },
102
+ {
103
+ "indexed": True,
104
+ "internalType": "address",
105
+ "name": "spender",
106
+ "type": "address"
107
+ },
108
+ {
109
+ "indexed": False,
110
+ "internalType": "uint256",
111
+ "name": "value",
112
+ "type": "uint256"
113
+ }
114
+ ],
115
+ "name": "Approval",
116
+ "type": "event"
117
+ },
118
+ {
119
+ "anonymous": False,
120
+ "inputs": [
121
+ {
122
+ "indexed": True,
123
+ "internalType": "address",
124
+ "name": "from",
125
+ "type": "address"
126
+ },
127
+ {
128
+ "indexed": True,
129
+ "internalType": "address",
130
+ "name": "to",
131
+ "type": "address"
132
+ },
133
+ {
134
+ "indexed": False,
135
+ "internalType": "uint256",
136
+ "name": "value",
137
+ "type": "uint256"
138
+ }
139
+ ],
140
+ "name": "Transfer",
141
+ "type": "event"
142
+ },
143
+ {
144
+ "inputs": [
145
+ {
146
+ "internalType": "address",
147
+ "name": "owner",
148
+ "type": "address"
149
+ },
150
+ {
151
+ "internalType": "address",
152
+ "name": "spender",
153
+ "type": "address"
154
+ }
155
+ ],
156
+ "name": "allowance",
157
+ "outputs": [
158
+ {
159
+ "internalType": "uint256",
160
+ "name": "",
161
+ "type": "uint256"
162
+ }
163
+ ],
164
+ "stateMutability": "view",
165
+ "type": "function"
166
+ },
167
+ {
168
+ "inputs": [
169
+ {
170
+ "internalType": "address",
171
+ "name": "spender",
172
+ "type": "address"
173
+ },
174
+ {
175
+ "internalType": "uint256",
176
+ "name": "value",
177
+ "type": "uint256"
178
+ }
179
+ ],
180
+ "name": "approve",
181
+ "outputs": [
182
+ {
183
+ "internalType": "bool",
184
+ "name": "",
185
+ "type": "bool"
186
+ }
187
+ ],
188
+ "stateMutability": "nonpayable",
189
+ "type": "function"
190
+ },
191
+ {
192
+ "inputs": [
193
+ {
194
+ "internalType": "address",
195
+ "name": "account",
196
+ "type": "address"
197
+ }
198
+ ],
199
+ "name": "balanceOf",
200
+ "outputs": [
201
+ {
202
+ "internalType": "uint256",
203
+ "name": "",
204
+ "type": "uint256"
205
+ }
206
+ ],
207
+ "stateMutability": "view",
208
+ "type": "function"
209
+ },
210
+ {
211
+ "inputs": [],
212
+ "name": "decimals",
213
+ "outputs": [
214
+ {
215
+ "internalType": "uint8",
216
+ "name": "",
217
+ "type": "uint8"
218
+ }
219
+ ],
220
+ "stateMutability": "view",
221
+ "type": "function"
222
+ },
223
+ {
224
+ "inputs": [],
225
+ "name": "name",
226
+ "outputs": [
227
+ {
228
+ "internalType": "string",
229
+ "name": "",
230
+ "type": "string"
231
+ }
232
+ ],
233
+ "stateMutability": "view",
234
+ "type": "function"
235
+ },
236
+ {
237
+ "inputs": [],
238
+ "name": "symbol",
239
+ "outputs": [
240
+ {
241
+ "internalType": "string",
242
+ "name": "",
243
+ "type": "string"
244
+ }
245
+ ],
246
+ "stateMutability": "view",
247
+ "type": "function"
248
+ },
249
+ {
250
+ "inputs": [],
251
+ "name": "totalSupply",
252
+ "outputs": [
253
+ {
254
+ "internalType": "uint256",
255
+ "name": "",
256
+ "type": "uint256"
257
+ }
258
+ ],
259
+ "stateMutability": "view",
260
+ "type": "function"
261
+ },
262
+ {
263
+ "inputs": [
264
+ {
265
+ "internalType": "address",
266
+ "name": "to",
267
+ "type": "address"
268
+ },
269
+ {
270
+ "internalType": "uint256",
271
+ "name": "value",
272
+ "type": "uint256"
273
+ }
274
+ ],
275
+ "name": "transfer",
276
+ "outputs": [
277
+ {
278
+ "internalType": "bool",
279
+ "name": "",
280
+ "type": "bool"
281
+ }
282
+ ],
283
+ "stateMutability": "nonpayable",
284
+ "type": "function"
285
+ },
286
+ {
287
+ "inputs": [
288
+ {
289
+ "internalType": "address",
290
+ "name": "from",
291
+ "type": "address"
292
+ },
293
+ {
294
+ "internalType": "address",
295
+ "name": "to",
296
+ "type": "address"
297
+ },
298
+ {
299
+ "internalType": "uint256",
300
+ "name": "value",
301
+ "type": "uint256"
302
+ }
303
+ ],
304
+ "name": "transferFrom",
305
+ "outputs": [
306
+ {
307
+ "internalType": "bool",
308
+ "name": "",
309
+ "type": "bool"
310
+ }
311
+ ],
312
+ "stateMutability": "nonpayable",
313
+ "type": "function"
314
+ },
315
+ ]
@@ -9,7 +9,13 @@ from prediction_market_agent_tooling.benchmark.utils import (
9
9
 
10
10
 
11
11
  class AbstractBenchmarkedAgent:
12
- def __init__(self, agent_name: str, max_workers: t.Optional[int] = None):
12
+ def __init__(
13
+ self,
14
+ agent_name: str,
15
+ max_workers: t.Optional[int] = None,
16
+ model: str | None = None,
17
+ ):
18
+ self.model = model
13
19
  self.agent_name = agent_name
14
20
  self.max_workers = max_workers # Limit the number of workers that can run this worker in parallel threads
15
21
 
@@ -1,12 +1,10 @@
1
1
  import concurrent.futures
2
2
  import os
3
- import time
4
3
  import typing as t
5
4
  from collections import defaultdict
6
5
 
7
6
  import numpy as np
8
7
  import pandas as pd
9
- from langchain_community.callbacks import get_openai_callback
10
8
  from sklearn.metrics import precision_score, recall_score
11
9
  from tqdm import tqdm
12
10
 
@@ -15,9 +13,9 @@ from prediction_market_agent_tooling.benchmark.utils import (
15
13
  Prediction,
16
14
  PredictionsCache,
17
15
  Resolution,
18
- get_llm_api_call_cost,
19
16
  )
20
17
  from prediction_market_agent_tooling.markets.agent_market import AgentMarket
18
+ from prediction_market_agent_tooling.tools.costs import openai_costs
21
19
  from prediction_market_agent_tooling.tools.utils import (
22
20
  check_not_none,
23
21
  should_not_happen,
@@ -129,6 +127,7 @@ class Benchmarker:
129
127
  return self.predictions.get_prediction(agent_name=agent_name, question=question)
130
128
 
131
129
  def run_agents(self, enable_timing: bool = True) -> None:
130
+ agent: AbstractBenchmarkedAgent # Fix for mypy issue with tqdm.
132
131
  for agent in tqdm(self.registered_agents, desc="Running agents"):
133
132
  # Filter out cached predictions
134
133
  markets_to_run = [
@@ -142,27 +141,21 @@ class Benchmarker:
142
141
  def get_prediction_result(
143
142
  market: AgentMarket,
144
143
  ) -> tuple[str, Prediction]:
145
- with get_openai_callback() as cb:
146
- start = time.time()
144
+ with openai_costs(model=agent.model) as costs:
147
145
  prediction = (
148
146
  agent.check_and_predict(market_question=market.question)
149
147
  if not market.is_resolved()
150
- else agent.check_and_predict_restricted(
151
- market_question=market.question,
152
- time_restriction_up_to=market.created_time, # TODO: Add support for resolved_at and any time in between.
148
+ else (
149
+ agent.check_and_predict_restricted(
150
+ market_question=market.question,
151
+ time_restriction_up_to=market.created_time, # TODO: Add support for resolved_at and any time in between.
152
+ )
153
+ if market.created_time is not None
154
+ else should_not_happen()
153
155
  )
154
156
  )
155
-
156
- prediction.time = time.time() - start if enable_timing else None
157
-
158
- if cb.total_tokens > 0 and cb.total_cost == 0:
159
- # TODO: this is a hack to get the cost for an unsupported model
160
- cb.total_cost = get_llm_api_call_cost(
161
- model=agent.model,
162
- prompt_tokens=cb.prompt_tokens,
163
- completion_tokens=cb.completion_tokens,
164
- )
165
- prediction.cost = cb.total_cost
157
+ prediction.time = costs.time
158
+ prediction.cost = costs.cost
166
159
  return market.question, prediction
167
160
 
168
161
  # Run agents in parallel
@@ -208,7 +201,7 @@ class Benchmarker:
208
201
  return None
209
202
  mse = sum(
210
203
  [
211
- (check_not_none(p.outcome_prediction).p_yes - m.p_yes) ** 2
204
+ (check_not_none(p.outcome_prediction).p_yes - m.current_p_yes) ** 2
212
205
  for p, m in zip(predictions, markets)
213
206
  ]
214
207
  ) / len(predictions)
@@ -262,7 +255,10 @@ class Benchmarker:
262
255
 
263
256
  within_range_count = 0
264
257
  for p, m in zip(predictions, markets):
265
- if abs(check_not_none(p.outcome_prediction).p_yes - m.p_yes) <= tolerance:
258
+ if (
259
+ abs(check_not_none(p.outcome_prediction).p_yes - m.current_p_yes)
260
+ <= tolerance
261
+ ):
266
262
  within_range_count += 1
267
263
 
268
264
  return (100 * within_range_count) / len(predictions)
@@ -330,7 +326,7 @@ class Benchmarker:
330
326
  return None
331
327
 
332
328
  p_yes_errors = [
333
- abs(check_not_none(p.outcome_prediction).p_yes - m.p_yes)
329
+ abs(check_not_none(p.outcome_prediction).p_yes - m.current_p_yes)
334
330
  for p, m in zip(predictions, markets)
335
331
  ]
336
332
  confidences = [
@@ -420,7 +416,7 @@ class Benchmarker:
420
416
  for p in agent_predictions
421
417
  ]
422
418
  markets_summary[f"reference p_yes"] = [
423
- f"{m.p_yes:.2f} [{m.probable_resolution}]" for m in self.markets
419
+ f"{m.current_p_yes:.2f} [{m.probable_resolution}]" for m in self.markets
424
420
  ]
425
421
  return markets_summary
426
422
 
@@ -475,7 +471,9 @@ class Benchmarker:
475
471
  return None
476
472
 
477
473
  expected_value = (
478
- yes_shares * market.p_yes + no_shares * (1 - market.p_yes) - bet_units
474
+ yes_shares * market.current_p_yes
475
+ + no_shares * (1 - market.current_p_yes)
476
+ - bet_units
479
477
  )
480
478
  expected_returns_perc = 100 * expected_value / bet_units
481
479
 
@@ -80,6 +80,10 @@ def get_llm_api_call_cost(
80
80
  "prompt_tokens": 0.01,
81
81
  "completion_tokens": 0.03,
82
82
  },
83
+ "gpt-4-turbo-2024-04-09": {
84
+ "prompt_tokens": 0.01,
85
+ "completion_tokens": 0.03,
86
+ },
83
87
  "gpt-3.5-turbo-0125": {
84
88
  "prompt_tokens": 0.0005,
85
89
  "completion_tokens": 0.0015,
@@ -1,5 +1,6 @@
1
1
  import typing as t
2
2
 
3
+ from pydantic import BaseModel
3
4
  from pydantic.types import SecretStr
4
5
  from pydantic_settings import BaseSettings, SettingsConfigDict
5
6
 
@@ -23,6 +24,7 @@ class APIKeys(BaseSettings):
23
24
 
24
25
  MANIFOLD_API_KEY: t.Optional[SecretStr] = None
25
26
  BET_FROM_PRIVATE_KEY: t.Optional[PrivateKey] = None
27
+ SAFE_ADDRESS: t.Optional[ChecksumAddress] = None
26
28
  OPENAI_API_KEY: t.Optional[SecretStr] = None
27
29
 
28
30
  GOOGLE_SEARCH_API_KEY: t.Optional[SecretStr] = None
@@ -43,10 +45,6 @@ class APIKeys(BaseSettings):
43
45
  self.MANIFOLD_API_KEY, "MANIFOLD_API_KEY missing in the environment."
44
46
  )
45
47
 
46
- @property
47
- def bet_from_address(self) -> ChecksumAddress:
48
- return private_key_to_public_key(self.bet_from_private_key)
49
-
50
48
  @property
51
49
  def bet_from_private_key(self) -> PrivateKey:
52
50
  return check_not_none(
@@ -87,3 +85,28 @@ class APIKeys(BaseSettings):
87
85
  for k, v in self.model_dump().items()
88
86
  if APIKeys.model_fields[k].annotation in SECRET_TYPES and v is not None
89
87
  }
88
+
89
+
90
+ class PrivateCredentials(BaseModel):
91
+ private_key: PrivateKey
92
+ safe_address: ChecksumAddress | None
93
+
94
+ @property
95
+ def public_key(self) -> ChecksumAddress:
96
+ """If the SAFE is available, we always route transactions via SAFE. Otherwise we use the EOA."""
97
+ return (
98
+ self.safe_address
99
+ if self.safe_address is not None
100
+ else private_key_to_public_key(self.private_key)
101
+ )
102
+
103
+ @property
104
+ def has_safe_address(self) -> bool:
105
+ return self.safe_address is not None
106
+
107
+ @staticmethod
108
+ def from_api_keys(api_keys: APIKeys) -> "PrivateCredentials":
109
+ return PrivateCredentials(
110
+ private_key=api_keys.bet_from_private_key,
111
+ safe_address=api_keys.SAFE_ADDRESS,
112
+ )
@@ -7,7 +7,7 @@ from datetime import datetime
7
7
 
8
8
  from loguru import logger
9
9
 
10
- from prediction_market_agent_tooling.config import APIKeys
10
+ from prediction_market_agent_tooling.config import APIKeys, PrivateCredentials
11
11
  from prediction_market_agent_tooling.deploy.constants import (
12
12
  MARKET_TYPE_KEY,
13
13
  REPOSITORY_KEY,
@@ -181,11 +181,11 @@ def {entrypoint_function_name}(request) -> str:
181
181
  """
182
182
  Executes actions that occur before bets are placed.
183
183
  """
184
- keys = APIKeys()
184
+ private_credentials = PrivateCredentials.from_api_keys(APIKeys())
185
185
 
186
186
  if market_type == MarketType.OMEN:
187
187
  # Omen is specific, because the user (agent) needs to manually withdraw winnings from the market.
188
- redeem_from_all_user_positions(keys.bet_from_private_key)
188
+ redeem_from_all_user_positions(private_credentials)
189
189
 
190
190
  def process_bets(self, market_type: MarketType, _place_bet: bool = True) -> None:
191
191
  """
@@ -46,7 +46,7 @@ class AgentMarket(BaseModel):
46
46
  resolution: Resolution | None
47
47
  created_time: datetime | None
48
48
  close_time: datetime | None
49
- p_yes: Probability
49
+ current_p_yes: Probability
50
50
  url: str
51
51
  volume: float | None # Should be in currency of `currency` above.
52
52
 
@@ -58,8 +58,8 @@ class AgentMarket(BaseModel):
58
58
  )
59
59
 
60
60
  @property
61
- def p_no(self) -> Probability:
62
- return Probability(1 - self.p_yes)
61
+ def current_p_no(self) -> Probability:
62
+ return Probability(1 - self.current_p_yes)
63
63
 
64
64
  @property
65
65
  def yes_outcome_price(self) -> float:
@@ -67,7 +67,7 @@ class AgentMarket(BaseModel):
67
67
  Price at prediction market is equal to the probability of given outcome.
68
68
  Keep as an extra property, in case it wouldn't be true for some prediction market platform.
69
69
  """
70
- return self.p_yes
70
+ return self.current_p_yes
71
71
 
72
72
  @property
73
73
  def no_outcome_price(self) -> float:
@@ -75,7 +75,7 @@ class AgentMarket(BaseModel):
75
75
  Price at prediction market is equal to the probability of given outcome.
76
76
  Keep as an extra property, in case it wouldn't be true for some prediction market platform.
77
77
  """
78
- return self.p_no
78
+ return self.current_p_no
79
79
 
80
80
  @property
81
81
  def probable_resolution(self) -> Resolution:
@@ -85,7 +85,7 @@ class AgentMarket(BaseModel):
85
85
  else:
86
86
  raise ValueError(f"Unknown resolution: {self.resolution}")
87
87
  else:
88
- return Resolution.YES if self.p_yes > 0.5 else Resolution.NO
88
+ return Resolution.YES if self.current_p_yes > 0.5 else Resolution.NO
89
89
 
90
90
  @property
91
91
  def boolean_outcome(self) -> bool:
@@ -96,6 +96,20 @@ class AgentMarket(BaseModel):
96
96
  return False
97
97
  should_not_happen(f"Market {self.id} does not have a successful resolution.")
98
98
 
99
+ def get_last_trade_p_yes(self) -> Probability | None:
100
+ """
101
+ Get the last trade price for the YES outcome. This can be different from the current p_yes, for example if market is closed and it's probabilities are fixed to 0 and 1.
102
+ Could be None if no trades were made.
103
+ """
104
+ raise NotImplementedError("Subclasses must implement this method")
105
+
106
+ def get_last_trade_p_no(self) -> Probability | None:
107
+ """
108
+ Get the last trade price for the NO outcome. This can be different from the current p_yes, for example if market is closed and it's probabilities are fixed to 0 and 1.
109
+ Could be None if no trades were made.
110
+ """
111
+ raise NotImplementedError("Subclasses must implement this method")
112
+
99
113
  def get_bet_amount(self, amount: float) -> BetAmount:
100
114
  return BetAmount(amount=amount, currency=self.currency)
101
115
 
@@ -148,9 +162,6 @@ class AgentMarket(BaseModel):
148
162
  except ValueError:
149
163
  raise ValueError(f"Outcome `{outcome}` not found in `{self.outcomes}`.")
150
164
 
151
- def get_squared_error(self) -> float:
152
- return (self.p_yes - self.boolean_outcome) ** 2
153
-
154
165
  def get_token_balance(self, user_id: str, outcome: str) -> TokenAmount:
155
166
  raise NotImplementedError("Subclasses must implement this method")
156
167