prediction-market-agent-tooling 0.13.1__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/PKG-INFO +4 -3
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/benchmark/utils.py +1 -1
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/config.py +7 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/deploy/agent.py +0 -1
- prediction_market_agent_tooling-0.14.0/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +152 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +31 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/gtypes.py +14 -16
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/agent_market.py +14 -8
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/data_models.py +15 -2
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/manifold/api.py +16 -4
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +13 -14
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +3 -2
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/omen/data_models.py +21 -6
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/omen/omen.py +74 -12
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/monitor/markets/manifold.py +37 -17
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/monitor/markets/omen.py +37 -18
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/monitor/markets/polymarket.py +5 -21
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/monitor/monitor.py +71 -39
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/monitor/monitor_app.py +18 -5
- prediction_market_agent_tooling-0.14.0/prediction_market_agent_tooling/monitor/monitor_settings.py +27 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/gnosis_rpc.py +3 -2
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +5 -2
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/parallelism.py +6 -1
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/web3_utils.py +1 -2
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/pyproject.toml +5 -4
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/README.md +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/abis/wxdai.abi.json +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/markets.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/omen/omen_replicate.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/omen/omen_resolve_replicated.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/py.typed +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/balances.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/cache.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/contract.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/google.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
- {prediction_market_agent_tooling-0.13.1 → prediction_market_agent_tooling-0.14.0}/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.
|
3
|
+
Version: 0.14.0
|
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,7 +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-typing (>=
|
14
|
+
Requires-Dist: eth-typing (>=3.0.0,<4.0.0)
|
15
15
|
Requires-Dist: functions-framework (>=3.5.0,<4.0.0)
|
16
16
|
Requires-Dist: google-api-python-client (==2.95.0) ; extra == "google"
|
17
17
|
Requires-Dist: google-cloud-functions (>=1.16.0,<2.0.0)
|
@@ -22,6 +22,7 @@ Requires-Dist: langchain (>=0.1.9,<0.2.0) ; extra == "langchain"
|
|
22
22
|
Requires-Dist: langchain-community (>=0.0.19)
|
23
23
|
Requires-Dist: langchain-openai (>=0.0.5,<0.0.6) ; extra == "langchain"
|
24
24
|
Requires-Dist: loguru (>=0.7.2,<0.8.0)
|
25
|
+
Requires-Dist: mech-client (>=0.2.13,<0.3.0)
|
25
26
|
Requires-Dist: numpy (>=1.26.4,<2.0.0)
|
26
27
|
Requires-Dist: pydantic (>=2.6.1,<3.0.0)
|
27
28
|
Requires-Dist: pydantic-settings (>=2.1.0,<3.0.0)
|
@@ -32,7 +33,7 @@ Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
|
32
33
|
Requires-Dist: tqdm (>=4.66.2,<5.0.0)
|
33
34
|
Requires-Dist: typer (>=0.9.0,<0.10.0)
|
34
35
|
Requires-Dist: types-pytz (>=2024.1.0.20240203,<2025.0.0.0)
|
35
|
-
Requires-Dist: types-requests (>=2.31.0.
|
36
|
+
Requires-Dist: types-requests (>=2.31.0.0,<3.0.0.0)
|
36
37
|
Requires-Dist: web3 (>=6.15.1,<7.0.0)
|
37
38
|
Description-Content-Type: text/markdown
|
38
39
|
|
@@ -4,6 +4,7 @@ from pydantic.types import SecretStr
|
|
4
4
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
5
5
|
|
6
6
|
from prediction_market_agent_tooling.gtypes import ChecksumAddress, PrivateKey
|
7
|
+
from prediction_market_agent_tooling.markets.manifold.api import get_authenticated_user
|
7
8
|
from prediction_market_agent_tooling.tools.utils import check_not_none
|
8
9
|
from prediction_market_agent_tooling.tools.web3_utils import private_key_to_public_key
|
9
10
|
|
@@ -30,6 +31,12 @@ class APIKeys(BaseSettings):
|
|
30
31
|
ENABLE_CACHE: bool = True
|
31
32
|
CACHE_DIR: str = "./.cache"
|
32
33
|
|
34
|
+
@property
|
35
|
+
def manifold_user_id(self) -> str:
|
36
|
+
return get_authenticated_user(
|
37
|
+
api_key=self.manifold_api_key.get_secret_value()
|
38
|
+
).id
|
39
|
+
|
33
40
|
@property
|
34
41
|
def manifold_api_key(self) -> SecretStr:
|
35
42
|
return check_not_none(
|
@@ -122,7 +122,6 @@ def {entrypoint_function_name}(request) -> str:
|
|
122
122
|
|
123
123
|
monitor_agent = MARKET_TYPE_TO_DEPLOYED_AGENT[market_type].from_api_keys(
|
124
124
|
name=gcp_fname,
|
125
|
-
deployableagent_class_name=self.__class__.__name__,
|
126
125
|
start_time=start_time or utcnow(),
|
127
126
|
api_keys=gcp_resolve_api_keys_secrets(api_keys),
|
128
127
|
)
|
@@ -0,0 +1,152 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from pydantic import BaseModel
|
5
|
+
|
6
|
+
|
7
|
+
class Metadata(BaseModel):
|
8
|
+
creationTimestamp: datetime
|
9
|
+
generation: int
|
10
|
+
name: str
|
11
|
+
namespace: str
|
12
|
+
resourceVersion: str
|
13
|
+
uid: str
|
14
|
+
labels: dict[str, str]
|
15
|
+
|
16
|
+
|
17
|
+
class Metadata1(BaseModel):
|
18
|
+
creationTimestamp: datetime | None
|
19
|
+
name: str
|
20
|
+
|
21
|
+
|
22
|
+
class Metadata2(BaseModel):
|
23
|
+
creationTimestamp: datetime | None
|
24
|
+
name: str
|
25
|
+
|
26
|
+
|
27
|
+
class SecretKeyRef(BaseModel):
|
28
|
+
key: str
|
29
|
+
name: str
|
30
|
+
optional: bool
|
31
|
+
|
32
|
+
|
33
|
+
class ValueFrom(BaseModel):
|
34
|
+
secretKeyRef: SecretKeyRef
|
35
|
+
|
36
|
+
|
37
|
+
class EnvItem(BaseModel):
|
38
|
+
name: str
|
39
|
+
valueFrom: ValueFrom
|
40
|
+
|
41
|
+
|
42
|
+
class ConfigMapRef(BaseModel):
|
43
|
+
name: str
|
44
|
+
optional: bool
|
45
|
+
|
46
|
+
|
47
|
+
class EnvFromItem(BaseModel):
|
48
|
+
configMapRef: ConfigMapRef
|
49
|
+
|
50
|
+
|
51
|
+
class Limits(BaseModel):
|
52
|
+
cpu: str
|
53
|
+
memory: str
|
54
|
+
|
55
|
+
|
56
|
+
class Requests(BaseModel):
|
57
|
+
cpu: str
|
58
|
+
memory: str
|
59
|
+
|
60
|
+
|
61
|
+
class Resources(BaseModel):
|
62
|
+
limits: Limits
|
63
|
+
requests: Requests
|
64
|
+
|
65
|
+
|
66
|
+
class Container(BaseModel):
|
67
|
+
env: list[EnvItem]
|
68
|
+
envFrom: list[EnvFromItem]
|
69
|
+
image: str
|
70
|
+
imagePullPolicy: str
|
71
|
+
name: str
|
72
|
+
resources: Resources
|
73
|
+
terminationMessagePath: str
|
74
|
+
terminationMessagePolicy: str
|
75
|
+
|
76
|
+
|
77
|
+
class NodeSelector(BaseModel):
|
78
|
+
role: str
|
79
|
+
|
80
|
+
|
81
|
+
class Toleration(BaseModel):
|
82
|
+
effect: str
|
83
|
+
key: str
|
84
|
+
operator: str
|
85
|
+
value: str
|
86
|
+
|
87
|
+
|
88
|
+
class Spec2(BaseModel):
|
89
|
+
automountServiceAccountToken: bool
|
90
|
+
containers: list[Container]
|
91
|
+
dnsPolicy: str
|
92
|
+
enableServiceLinks: bool
|
93
|
+
nodeSelector: NodeSelector
|
94
|
+
restartPolicy: str
|
95
|
+
schedulerName: str
|
96
|
+
securityContext: dict[str, Any]
|
97
|
+
shareProcessNamespace: bool
|
98
|
+
terminationGracePeriodSeconds: int
|
99
|
+
tolerations: list[Toleration]
|
100
|
+
|
101
|
+
|
102
|
+
class Template(BaseModel):
|
103
|
+
metadata: Metadata2
|
104
|
+
spec: Spec2
|
105
|
+
|
106
|
+
|
107
|
+
class Spec1(BaseModel):
|
108
|
+
activeDeadlineSeconds: int
|
109
|
+
backoffLimit: int
|
110
|
+
completions: int
|
111
|
+
manualSelector: bool
|
112
|
+
parallelism: int
|
113
|
+
template: Template
|
114
|
+
|
115
|
+
|
116
|
+
class JobTemplate(BaseModel):
|
117
|
+
metadata: Metadata1
|
118
|
+
spec: Spec1
|
119
|
+
|
120
|
+
|
121
|
+
class Spec(BaseModel):
|
122
|
+
concurrencyPolicy: str
|
123
|
+
failedJobsHistoryLimit: int
|
124
|
+
jobTemplate: JobTemplate
|
125
|
+
schedule: str
|
126
|
+
successfulJobsHistoryLimit: int
|
127
|
+
suspend: bool
|
128
|
+
timeZone: str
|
129
|
+
|
130
|
+
|
131
|
+
class Status(BaseModel):
|
132
|
+
lastScheduleTime: str | None = None
|
133
|
+
lastSuccessfulTime: str | None = None
|
134
|
+
|
135
|
+
|
136
|
+
class KubernetesCronJob(BaseModel):
|
137
|
+
apiVersion: str
|
138
|
+
kind: str
|
139
|
+
metadata: Metadata
|
140
|
+
spec: Spec
|
141
|
+
status: Status
|
142
|
+
|
143
|
+
|
144
|
+
class Metadata3(BaseModel):
|
145
|
+
resourceVersion: str
|
146
|
+
|
147
|
+
|
148
|
+
class KubernetesCronJobsModel(BaseModel):
|
149
|
+
apiVersion: str
|
150
|
+
items: list[KubernetesCronJob]
|
151
|
+
kind: str
|
152
|
+
metadata: Metadata3
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import json
|
1
2
|
import subprocess
|
2
3
|
import sys
|
3
4
|
|
@@ -8,6 +9,9 @@ from google.cloud.functions_v2.types.functions import Function
|
|
8
9
|
from google.cloud.secretmanager import SecretManagerServiceClient
|
9
10
|
|
10
11
|
from prediction_market_agent_tooling.config import APIKeys
|
12
|
+
from prediction_market_agent_tooling.deploy.gcp.kubernetes_models import (
|
13
|
+
KubernetesCronJobsModel,
|
14
|
+
)
|
11
15
|
|
12
16
|
|
13
17
|
def gcloud_deploy_cmd(
|
@@ -153,6 +157,33 @@ def list_gcp_functions() -> list[Function]:
|
|
153
157
|
return functions
|
154
158
|
|
155
159
|
|
160
|
+
def list_gcp_cronjobs(namespace: str) -> KubernetesCronJobsModel:
|
161
|
+
return KubernetesCronJobsModel.model_validate_json(
|
162
|
+
subprocess.run(
|
163
|
+
f"kubectl get cronjobs -o json -n {namespace}",
|
164
|
+
shell=True,
|
165
|
+
capture_output=True,
|
166
|
+
check=True,
|
167
|
+
)
|
168
|
+
.stdout.decode()
|
169
|
+
.strip()
|
170
|
+
)
|
171
|
+
|
172
|
+
|
173
|
+
def get_gcp_configmap_data(namespace: str, name: str) -> dict[str, str]:
|
174
|
+
data: dict[str, str] = json.loads(
|
175
|
+
subprocess.run(
|
176
|
+
f"kubectl get configmap {name} -o json -n {namespace}",
|
177
|
+
shell=True,
|
178
|
+
capture_output=True,
|
179
|
+
check=True,
|
180
|
+
)
|
181
|
+
.stdout.decode()
|
182
|
+
.strip()
|
183
|
+
)["data"]
|
184
|
+
return data
|
185
|
+
|
186
|
+
|
156
187
|
def get_gcp_function(fname: str) -> Function:
|
157
188
|
response = list_gcp_functions()
|
158
189
|
for function in response:
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import typing as t
|
2
2
|
from datetime import datetime
|
3
|
-
from decimal import Decimal
|
4
3
|
from typing import NewType, Union
|
5
4
|
|
6
5
|
from eth_typing.evm import ( # noqa: F401 # Import for the sake of easy importing with others from here.
|
@@ -23,23 +22,22 @@ from prediction_market_agent_tooling.tools.hexbytes_custom import ( # noqa: F40
|
|
23
22
|
)
|
24
23
|
|
25
24
|
Wad = Wei # Wei tends to be referred to as `wad` variable in contracts.
|
26
|
-
USD = NewType(
|
27
|
-
"USD", Decimal
|
28
|
-
) # Decimals are more precise than floats, good for finances.
|
25
|
+
USD = NewType("USD", float)
|
29
26
|
PrivateKey = NewType("PrivateKey", SecretStr)
|
30
|
-
xDai = NewType("xDai",
|
31
|
-
GNO = NewType("GNO",
|
27
|
+
xDai = NewType("xDai", float)
|
28
|
+
GNO = NewType("GNO", float)
|
32
29
|
ABI = NewType("ABI", str)
|
33
30
|
OmenOutcomeToken = NewType("OmenOutcomeToken", int)
|
31
|
+
OutcomeStr = NewType("OutcomeStr", str)
|
34
32
|
Probability = NewType("Probability", float)
|
35
|
-
Mana = NewType("Mana",
|
36
|
-
USDC = NewType("USDC",
|
33
|
+
Mana = NewType("Mana", float) # Manifold's "currency"
|
34
|
+
USDC = NewType("USDC", float)
|
37
35
|
DatetimeWithTimezone = NewType("DatetimeWithTimezone", datetime)
|
38
36
|
ChainID = NewType("ChainID", int)
|
39
37
|
|
40
38
|
|
41
|
-
def usd_type(amount: Union[str, int, float
|
42
|
-
return USD(
|
39
|
+
def usd_type(amount: Union[str, int, float]) -> USD:
|
40
|
+
return USD(float(amount))
|
43
41
|
|
44
42
|
|
45
43
|
def wei_type(amount: Union[str, int]) -> Wei:
|
@@ -50,16 +48,16 @@ def omen_outcome_type(amount: Union[str, int, Wei]) -> OmenOutcomeToken:
|
|
50
48
|
return OmenOutcomeToken(wei_type(amount))
|
51
49
|
|
52
50
|
|
53
|
-
def xdai_type(amount: Union[str, int, float
|
54
|
-
return xDai(
|
51
|
+
def xdai_type(amount: Union[str, int, float]) -> xDai:
|
52
|
+
return xDai(float(amount))
|
55
53
|
|
56
54
|
|
57
|
-
def mana_type(amount: Union[str, int, float
|
58
|
-
return Mana(
|
55
|
+
def mana_type(amount: Union[str, int, float]) -> Mana:
|
56
|
+
return Mana(float(amount))
|
59
57
|
|
60
58
|
|
61
|
-
def usdc_type(amount: Union[str, int, float
|
62
|
-
return USDC(
|
59
|
+
def usdc_type(amount: Union[str, int, float]) -> USDC:
|
60
|
+
return USDC(float(amount))
|
63
61
|
|
64
62
|
|
65
63
|
def private_key_type(k: str) -> PrivateKey:
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import typing as t
|
2
2
|
from datetime import datetime
|
3
|
-
from decimal import Decimal
|
4
3
|
from enum import Enum
|
5
4
|
|
6
5
|
from pydantic import BaseModel, field_validator
|
@@ -9,6 +8,7 @@ from prediction_market_agent_tooling.gtypes import Probability
|
|
9
8
|
from prediction_market_agent_tooling.markets.data_models import (
|
10
9
|
BetAmount,
|
11
10
|
Currency,
|
11
|
+
Position,
|
12
12
|
Resolution,
|
13
13
|
TokenAmount,
|
14
14
|
)
|
@@ -45,10 +45,10 @@ class AgentMarket(BaseModel):
|
|
45
45
|
outcomes: list[str]
|
46
46
|
resolution: Resolution | None
|
47
47
|
created_time: datetime | None
|
48
|
-
close_time: datetime
|
48
|
+
close_time: datetime | None
|
49
49
|
p_yes: Probability
|
50
50
|
url: str
|
51
|
-
volume:
|
51
|
+
volume: float | None # Should be in currency of `currency` above.
|
52
52
|
|
53
53
|
_add_timezone_validator_created_time = field_validator("created_time")(
|
54
54
|
add_utc_timezone_validator
|
@@ -62,20 +62,20 @@ class AgentMarket(BaseModel):
|
|
62
62
|
return Probability(1 - self.p_yes)
|
63
63
|
|
64
64
|
@property
|
65
|
-
def yes_outcome_price(self) ->
|
65
|
+
def yes_outcome_price(self) -> float:
|
66
66
|
"""
|
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
|
70
|
+
return self.p_yes
|
71
71
|
|
72
72
|
@property
|
73
|
-
def no_outcome_price(self) ->
|
73
|
+
def no_outcome_price(self) -> float:
|
74
74
|
"""
|
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
|
78
|
+
return self.p_no
|
79
79
|
|
80
80
|
@property
|
81
81
|
def probable_resolution(self) -> Resolution:
|
@@ -96,7 +96,7 @@ 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_bet_amount(self, amount:
|
99
|
+
def get_bet_amount(self, amount: float) -> BetAmount:
|
100
100
|
return BetAmount(amount=amount, currency=self.currency)
|
101
101
|
|
102
102
|
def get_tiny_bet_amount(self) -> BetAmount:
|
@@ -153,3 +153,9 @@ class AgentMarket(BaseModel):
|
|
153
153
|
|
154
154
|
def get_token_balance(self, user_id: str, outcome: str) -> TokenAmount:
|
155
155
|
raise NotImplementedError("Subclasses must implement this method")
|
156
|
+
|
157
|
+
def get_positions(self, user_id: str) -> list[Position]:
|
158
|
+
"""
|
159
|
+
Get all non-zero positions a user has in any market.
|
160
|
+
"""
|
161
|
+
raise NotImplementedError("Subclasses must implement this method")
|
@@ -1,10 +1,11 @@
|
|
1
1
|
from datetime import datetime
|
2
|
-
from decimal import Decimal
|
3
2
|
from enum import Enum
|
4
3
|
from typing import TypeAlias
|
5
4
|
|
6
5
|
from pydantic import BaseModel
|
7
6
|
|
7
|
+
from prediction_market_agent_tooling.gtypes import OutcomeStr
|
8
|
+
|
8
9
|
|
9
10
|
class Currency(str, Enum):
|
10
11
|
xDai = "xDai"
|
@@ -20,7 +21,7 @@ class Resolution(str, Enum):
|
|
20
21
|
|
21
22
|
|
22
23
|
class TokenAmount(BaseModel):
|
23
|
-
amount:
|
24
|
+
amount: float
|
24
25
|
currency: Currency
|
25
26
|
|
26
27
|
|
@@ -43,3 +44,15 @@ class ResolvedBet(Bet):
|
|
43
44
|
@property
|
44
45
|
def is_correct(self) -> bool:
|
45
46
|
return self.outcome == self.market_outcome
|
47
|
+
|
48
|
+
|
49
|
+
class Position(BaseModel):
|
50
|
+
market_id: str
|
51
|
+
amounts: dict[OutcomeStr, TokenAmount]
|
52
|
+
|
53
|
+
def __str__(self) -> str:
|
54
|
+
amounts_str = ", ".join(
|
55
|
+
f"{amount.amount} '{outcome}' tokens"
|
56
|
+
for outcome, amount in self.amounts.items()
|
57
|
+
)
|
58
|
+
return f"Position for market id {self.market_id}: {amounts_str}"
|
@@ -5,8 +5,7 @@ import requests
|
|
5
5
|
import tenacity
|
6
6
|
from loguru import logger
|
7
7
|
|
8
|
-
from prediction_market_agent_tooling.
|
9
|
-
from prediction_market_agent_tooling.gtypes import Mana
|
8
|
+
from prediction_market_agent_tooling.gtypes import Mana, SecretStr
|
10
9
|
from prediction_market_agent_tooling.markets.data_models import (
|
11
10
|
BetAmount,
|
12
11
|
Currency,
|
@@ -107,7 +106,9 @@ def get_one_manifold_binary_market() -> ManifoldMarket:
|
|
107
106
|
wait=tenacity.wait_fixed(1),
|
108
107
|
after=lambda x: logger.debug(f"place_bet failed, {x.attempt_number=}."),
|
109
108
|
)
|
110
|
-
def place_bet(
|
109
|
+
def place_bet(
|
110
|
+
amount: Mana, market_id: str, outcome: bool, manifold_api_key: SecretStr
|
111
|
+
) -> None:
|
111
112
|
outcome_str = "YES" if outcome else "NO"
|
112
113
|
url = f"{MANIFOLD_API_BASE_URL}/v0/bet"
|
113
114
|
params = {
|
@@ -117,7 +118,7 @@ def place_bet(amount: Mana, market_id: str, outcome: bool) -> None:
|
|
117
118
|
}
|
118
119
|
|
119
120
|
headers = {
|
120
|
-
"Authorization": f"Key {
|
121
|
+
"Authorization": f"Key {manifold_api_key.get_secret_value()}",
|
121
122
|
"Content-Type": "application/json",
|
122
123
|
}
|
123
124
|
response = requests.post(url, json=params, headers=headers)
|
@@ -139,12 +140,18 @@ def get_authenticated_user(api_key: str) -> ManifoldUser:
|
|
139
140
|
headers = {
|
140
141
|
"Authorization": f"Key {api_key}",
|
141
142
|
"Content-Type": "application/json",
|
143
|
+
"Cache-Control": "private, no-store, max-age=0",
|
142
144
|
}
|
143
145
|
response = requests.get(url, headers=headers)
|
144
146
|
response.raise_for_status()
|
145
147
|
return ManifoldUser.model_validate(response.json())
|
146
148
|
|
147
149
|
|
150
|
+
@tenacity.retry(
|
151
|
+
stop=tenacity.stop_after_attempt(3),
|
152
|
+
wait=tenacity.wait_fixed(1),
|
153
|
+
after=lambda x: logger.debug(f"get_manifold_market failed, {x.attempt_number=}."),
|
154
|
+
)
|
148
155
|
def get_manifold_market(market_id: str) -> ManifoldMarket:
|
149
156
|
url = f"{MANIFOLD_API_BASE_URL}/v0/market/{market_id}"
|
150
157
|
response = requests.get(url)
|
@@ -152,6 +159,11 @@ def get_manifold_market(market_id: str) -> ManifoldMarket:
|
|
152
159
|
return ManifoldMarket.model_validate(response.json())
|
153
160
|
|
154
161
|
|
162
|
+
@tenacity.retry(
|
163
|
+
stop=tenacity.stop_after_attempt(3),
|
164
|
+
wait=tenacity.wait_fixed(1),
|
165
|
+
after=lambda x: logger.debug(f"get_manifold_bets failed, {x.attempt_number=}."),
|
166
|
+
)
|
155
167
|
def get_manifold_bets(
|
156
168
|
user_id: str,
|
157
169
|
start_time: datetime,
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import typing as t
|
2
2
|
from datetime import datetime, timedelta
|
3
|
-
from decimal import Decimal
|
4
3
|
|
5
4
|
from pydantic import BaseModel, field_validator
|
6
5
|
|
@@ -123,17 +122,17 @@ class ManifoldUser(BaseModel):
|
|
123
122
|
class ManifoldBetFills(BaseModel):
|
124
123
|
amount: Mana
|
125
124
|
matchedBetId: t.Optional[str]
|
126
|
-
shares:
|
125
|
+
shares: float
|
127
126
|
timestamp: int
|
128
127
|
|
129
128
|
|
130
129
|
class ManifoldBetFees(BaseModel):
|
131
|
-
platformFee:
|
132
|
-
liquidityFee:
|
133
|
-
creatorFee:
|
130
|
+
platformFee: float
|
131
|
+
liquidityFee: float
|
132
|
+
creatorFee: float
|
134
133
|
|
135
|
-
def get_total(self) ->
|
136
|
-
return
|
134
|
+
def get_total(self) -> float:
|
135
|
+
return sum([self.platformFee, self.liquidityFee, self.creatorFee])
|
137
136
|
|
138
137
|
|
139
138
|
class ManifoldBet(BaseModel):
|
@@ -141,7 +140,7 @@ class ManifoldBet(BaseModel):
|
|
141
140
|
https://docs.manifold.markets/api#get-v0bets
|
142
141
|
"""
|
143
142
|
|
144
|
-
shares:
|
143
|
+
shares: float
|
145
144
|
probBefore: Probability
|
146
145
|
isFilled: t.Optional[bool] = None
|
147
146
|
probAfter: Probability
|
@@ -187,13 +186,13 @@ class ManifoldContractMetric(BaseModel):
|
|
187
186
|
hasNoShares: bool
|
188
187
|
hasShares: bool
|
189
188
|
hasYesShares: bool
|
190
|
-
invested:
|
191
|
-
loan:
|
189
|
+
invested: float
|
190
|
+
loan: float
|
192
191
|
maxSharesOutcome: t.Optional[str]
|
193
|
-
payout:
|
194
|
-
profit:
|
195
|
-
profitPercent:
|
196
|
-
totalShares: dict[str,
|
192
|
+
payout: float
|
193
|
+
profit: float
|
194
|
+
profitPercent: float
|
195
|
+
totalShares: dict[str, float]
|
197
196
|
userId: str
|
198
197
|
userUsername: str
|
199
198
|
userName: str
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import typing as t
|
2
2
|
from datetime import datetime
|
3
|
-
from decimal import Decimal
|
4
3
|
from math import ceil
|
5
4
|
|
5
|
+
from prediction_market_agent_tooling.config import APIKeys
|
6
6
|
from prediction_market_agent_tooling.gtypes import Mana, Probability, mana_type
|
7
7
|
from prediction_market_agent_tooling.markets.agent_market import (
|
8
8
|
AgentMarket,
|
@@ -32,7 +32,7 @@ class ManifoldAgentMarket(AgentMarket):
|
|
32
32
|
base_url: t.ClassVar[str] = MANIFOLD_BASE_URL
|
33
33
|
|
34
34
|
def get_tiny_bet_amount(self) -> BetAmount:
|
35
|
-
return BetAmount(amount=
|
35
|
+
return BetAmount(amount=1, currency=self.currency)
|
36
36
|
|
37
37
|
def get_minimum_bet_to_win(self, answer: bool, amount_to_win: float) -> Mana:
|
38
38
|
# Manifold lowest bet is 1 Mana, so we need to ceil the result.
|
@@ -45,6 +45,7 @@ class ManifoldAgentMarket(AgentMarket):
|
|
45
45
|
amount=Mana(amount.amount),
|
46
46
|
market_id=self.id,
|
47
47
|
outcome=outcome,
|
48
|
+
manifold_api_key=APIKeys().manifold_api_key,
|
48
49
|
)
|
49
50
|
|
50
51
|
@staticmethod
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import typing as t
|
2
2
|
from datetime import datetime
|
3
|
-
from decimal import Decimal
|
4
3
|
|
5
4
|
from pydantic import BaseModel
|
6
5
|
from web3 import Web3
|
@@ -90,6 +89,24 @@ class OmenPosition(BaseModel):
|
|
90
89
|
collateralTokenAddress: HexAddress
|
91
90
|
indexSets: list[int]
|
92
91
|
|
92
|
+
@property
|
93
|
+
def condition_id(self) -> HexBytes:
|
94
|
+
# I didn't find any example where this wouldn't hold, but keeping this double-check here in case something changes in the future.
|
95
|
+
# May be the case if the market is created with multiple oracles.
|
96
|
+
if len(self.conditionIds) != 1:
|
97
|
+
raise ValueError(
|
98
|
+
f"Bug in the logic, please investigate why zero or multiple conditions are returned for position {self.id=}"
|
99
|
+
)
|
100
|
+
return self.conditionIds[0]
|
101
|
+
|
102
|
+
@property
|
103
|
+
def index_set(self) -> int:
|
104
|
+
if len(self.indexSets) != 1:
|
105
|
+
raise ValueError(
|
106
|
+
f"Bug in the logic, please investigate why zero or multiple index sets are returned for position {self.id=}"
|
107
|
+
)
|
108
|
+
return self.indexSets[0]
|
109
|
+
|
93
110
|
@property
|
94
111
|
def collateral_token_contract_address_checksummed(self) -> ChecksumAddress:
|
95
112
|
return Web3.to_checksum_address(self.collateralTokenAddress)
|
@@ -133,7 +150,7 @@ class OmenMarket(BaseModel):
|
|
133
150
|
fee: t.Optional[Wei]
|
134
151
|
resolutionTimestamp: t.Optional[int] = None
|
135
152
|
answerFinalizedTimestamp: t.Optional[int] = None
|
136
|
-
currentAnswer: t.Optional[
|
153
|
+
currentAnswer: t.Optional[HexBytes] = None
|
137
154
|
creationTimestamp: int
|
138
155
|
condition: Condition
|
139
156
|
question: Question
|
@@ -156,7 +173,7 @@ class OmenMarket(BaseModel):
|
|
156
173
|
|
157
174
|
@property
|
158
175
|
def answer_index(self) -> t.Optional[int]:
|
159
|
-
return
|
176
|
+
return self.currentAnswer.as_int() if self.currentAnswer else None
|
160
177
|
|
161
178
|
@property
|
162
179
|
def has_valid_answer(self) -> bool:
|
@@ -338,9 +355,7 @@ class OmenBet(BaseModel):
|
|
338
355
|
)
|
339
356
|
|
340
357
|
return ResolvedBet(
|
341
|
-
amount=BetAmount(
|
342
|
-
amount=Decimal(self.collateralAmountUSD), currency=Currency.xDai
|
343
|
-
),
|
358
|
+
amount=BetAmount(amount=self.collateralAmountUSD, currency=Currency.xDai),
|
344
359
|
outcome=self.boolean_outcome,
|
345
360
|
created_time=self.creation_datetime,
|
346
361
|
market_question=self.title,
|