everestapi 0.2.6__tar.gz → 0.2.7__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.
- {everestapi-0.2.6/src/everestapi.egg-info → everestapi-0.2.7}/PKG-INFO +60 -6
- {everestapi-0.2.6 → everestapi-0.2.7}/README.md +52 -5
- {everestapi-0.2.6 → everestapi-0.2.7}/pyproject.toml +4 -1
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/__init__.py +12 -1
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/cli.py +1 -1
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/client.py +84 -33
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/mcp/server.py +687 -43
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/plots.py +4 -5
- everestapi-0.2.7/src/everestapi/scoring.py +197 -0
- {everestapi-0.2.6 → everestapi-0.2.7/src/everestapi.egg-info}/PKG-INFO +60 -6
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi.egg-info/SOURCES.txt +6 -1
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi.egg-info/requires.txt +8 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/tests/test_client.py +87 -5
- everestapi-0.2.7/tests/test_eve953_mcp_progress.py +176 -0
- everestapi-0.2.7/tests/test_eve957_mcp_annotations_resources.py +75 -0
- everestapi-0.2.7/tests/test_eve959_toolsets.py +72 -0
- everestapi-0.2.7/tests/test_mcp_and_models.py +570 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/tests/test_prediction_range.py +2 -2
- everestapi-0.2.7/tests/test_scoring.py +112 -0
- everestapi-0.2.6/tests/test_mcp_and_models.py +0 -195
- {everestapi-0.2.6 → everestapi-0.2.7}/LICENSE +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/setup.cfg +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/__main__.py +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/mcp/__init__.py +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/mcp/__main__.py +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi/types.py +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi.egg-info/dependency_links.txt +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi.egg-info/entry_points.txt +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/src/everestapi.egg-info/top_level.txt +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/tests/test_cli.py +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/tests/test_diagnostics.py +0 -0
- {everestapi-0.2.6 → everestapi-0.2.7}/tests/test_json_or_raise.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: everestapi
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Python SDK for the Everesteer prediction tournament platform
|
|
5
5
|
Author-email: Everesteer <support@everesteer.ai>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -24,10 +24,17 @@ Requires-Dist: click>=8.0
|
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
26
26
|
Requires-Dist: pytest-httpx>=0.34.0; extra == "dev"
|
|
27
|
+
Requires-Dist: numpy>=1.26; extra == "dev"
|
|
28
|
+
Requires-Dist: pandas>=2.0; extra == "dev"
|
|
29
|
+
Requires-Dist: scipy>=1.10; extra == "dev"
|
|
27
30
|
Provides-Extra: mcp
|
|
28
31
|
Requires-Dist: mcp>=1.0; extra == "mcp"
|
|
29
32
|
Provides-Extra: viz
|
|
30
33
|
Requires-Dist: plotnine>=0.13; extra == "viz"
|
|
34
|
+
Provides-Extra: scoring
|
|
35
|
+
Requires-Dist: numpy>=1.26; extra == "scoring"
|
|
36
|
+
Requires-Dist: pandas>=2.0; extra == "scoring"
|
|
37
|
+
Requires-Dist: scipy>=1.10; extra == "scoring"
|
|
31
38
|
Dynamic: license-file
|
|
32
39
|
|
|
33
40
|
# everestapi
|
|
@@ -89,8 +96,11 @@ api.submit_futures_predictions(model_id="my-fut-model", predictions={...})
|
|
|
89
96
|
Both Parquet and CSV are accepted. **Parquet is recommended** — float precision round-trips cleanly, files compress well, and it matches the format the SDK serves to you (`download_dataset` returns parquet).
|
|
90
97
|
|
|
91
98
|
```python
|
|
99
|
+
# A model slot must exist before you can submit — the platform never auto-creates one.
|
|
100
|
+
api.create_model(name="my-model")
|
|
101
|
+
|
|
92
102
|
api.submit_predictions_file(
|
|
93
|
-
|
|
103
|
+
model_id="my-model",
|
|
94
104
|
file_path="predictions.parquet", # or "predictions.csv"
|
|
95
105
|
tournament="equities",
|
|
96
106
|
)
|
|
@@ -168,16 +178,59 @@ api.get_stake_balance(model_id="my-model")
|
|
|
168
178
|
api.claim_payout(model_id="my-model", round_id="42")
|
|
169
179
|
```
|
|
170
180
|
|
|
171
|
-
###
|
|
181
|
+
### Score validation predictions offline
|
|
182
|
+
|
|
183
|
+
Reproduce the server's **exact** scoring — CORR20, AIMC20, FNC — *before* you
|
|
184
|
+
submit, so you stop guessing the sign of your signal ("submit raw and negated, let
|
|
185
|
+
the server decide"). The `everestapi.scoring` functions are a verbatim port of the
|
|
186
|
+
platform's scoring engine (verified equal to 1e-12), so your offline number **is**
|
|
187
|
+
the server's number.
|
|
188
|
+
|
|
189
|
+
Install the optional scoring extra (keeps the base SDK light — numpy/pandas/scipy
|
|
190
|
+
are only pulled in here):
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
pip install "everestapi[scoring]"
|
|
194
|
+
```
|
|
172
195
|
|
|
173
196
|
```python
|
|
174
197
|
import pandas as pd
|
|
198
|
+
from everestapi import scoring
|
|
175
199
|
|
|
176
|
-
val = pd.read_parquet("
|
|
177
|
-
|
|
178
|
-
|
|
200
|
+
val = pd.read_parquet("eiq_validation.parquet")
|
|
201
|
+
preds = my_model.predict(val.filter(like="feature_"))
|
|
202
|
+
|
|
203
|
+
# Score per exped (cross-section), then average — matches how the server scores.
|
|
204
|
+
per_exped = [
|
|
205
|
+
scoring.corr20(preds[val.exped == e], val.loc[val.exped == e, "target"])
|
|
206
|
+
for e in val.exped.unique()
|
|
207
|
+
]
|
|
208
|
+
print("mean CORR20:", sum(per_exped) / len(per_exped))
|
|
209
|
+
|
|
210
|
+
# Or every metric at once for one exped (ai_model = crowd consensus for that exped):
|
|
211
|
+
scoring.score(preds_e, target_e, ai_model=consensus_e, features=features_e)
|
|
212
|
+
# -> {"corr20", "aimc20", "payout", "fnc", "feature_exposure"}
|
|
179
213
|
```
|
|
180
214
|
|
|
215
|
+
**Sanity-check your pipeline against the example predictions.** The published
|
|
216
|
+
`eiq_validation_example_preds` are a benchmark-grade signal (the Minera ensemble)
|
|
217
|
+
and score a positive mean **CORR20 of ≈ 0.07**. Score that file and reproduce a
|
|
218
|
+
similar number — if you instead get ≈ −0.07, your sign is flipped; if you get ≈ 0,
|
|
219
|
+
your ids/alignment are off:
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
ex = pd.read_parquet("eiq_validation_example_preds.parquet") # column: prediction
|
|
223
|
+
val = pd.read_parquet("eiq_validation.parquet")
|
|
224
|
+
ref = [
|
|
225
|
+
scoring.corr20(ex.loc[val.exped == e, "prediction"], val.loc[val.exped == e, "target"])
|
|
226
|
+
for e in val.exped.unique()
|
|
227
|
+
]
|
|
228
|
+
print(sum(ref) / len(ref)) # ~0.07 -> pipeline + sign are correct
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
A quick convenience for a single overall correlation is also available:
|
|
232
|
+
`EverestAPI.evaluate(predictions, val, target="target_everest_20")`.
|
|
233
|
+
|
|
181
234
|
### CLI
|
|
182
235
|
|
|
183
236
|
```bash
|
|
@@ -207,6 +260,7 @@ with EverestAPI(api_key="...") as api:
|
|
|
207
260
|
|
|
208
261
|
- Python 3.10+
|
|
209
262
|
- httpx >= 0.27
|
|
263
|
+
- Optional `scoring` extra (`pip install "everestapi[scoring]"`): numpy, pandas, scipy — only needed for offline `everestapi.scoring`.
|
|
210
264
|
|
|
211
265
|
## Disclaimers
|
|
212
266
|
|
|
@@ -57,8 +57,11 @@ api.submit_futures_predictions(model_id="my-fut-model", predictions={...})
|
|
|
57
57
|
Both Parquet and CSV are accepted. **Parquet is recommended** — float precision round-trips cleanly, files compress well, and it matches the format the SDK serves to you (`download_dataset` returns parquet).
|
|
58
58
|
|
|
59
59
|
```python
|
|
60
|
+
# A model slot must exist before you can submit — the platform never auto-creates one.
|
|
61
|
+
api.create_model(name="my-model")
|
|
62
|
+
|
|
60
63
|
api.submit_predictions_file(
|
|
61
|
-
|
|
64
|
+
model_id="my-model",
|
|
62
65
|
file_path="predictions.parquet", # or "predictions.csv"
|
|
63
66
|
tournament="equities",
|
|
64
67
|
)
|
|
@@ -136,16 +139,59 @@ api.get_stake_balance(model_id="my-model")
|
|
|
136
139
|
api.claim_payout(model_id="my-model", round_id="42")
|
|
137
140
|
```
|
|
138
141
|
|
|
139
|
-
###
|
|
142
|
+
### Score validation predictions offline
|
|
143
|
+
|
|
144
|
+
Reproduce the server's **exact** scoring — CORR20, AIMC20, FNC — *before* you
|
|
145
|
+
submit, so you stop guessing the sign of your signal ("submit raw and negated, let
|
|
146
|
+
the server decide"). The `everestapi.scoring` functions are a verbatim port of the
|
|
147
|
+
platform's scoring engine (verified equal to 1e-12), so your offline number **is**
|
|
148
|
+
the server's number.
|
|
149
|
+
|
|
150
|
+
Install the optional scoring extra (keeps the base SDK light — numpy/pandas/scipy
|
|
151
|
+
are only pulled in here):
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
pip install "everestapi[scoring]"
|
|
155
|
+
```
|
|
140
156
|
|
|
141
157
|
```python
|
|
142
158
|
import pandas as pd
|
|
159
|
+
from everestapi import scoring
|
|
143
160
|
|
|
144
|
-
val = pd.read_parquet("
|
|
145
|
-
|
|
146
|
-
|
|
161
|
+
val = pd.read_parquet("eiq_validation.parquet")
|
|
162
|
+
preds = my_model.predict(val.filter(like="feature_"))
|
|
163
|
+
|
|
164
|
+
# Score per exped (cross-section), then average — matches how the server scores.
|
|
165
|
+
per_exped = [
|
|
166
|
+
scoring.corr20(preds[val.exped == e], val.loc[val.exped == e, "target"])
|
|
167
|
+
for e in val.exped.unique()
|
|
168
|
+
]
|
|
169
|
+
print("mean CORR20:", sum(per_exped) / len(per_exped))
|
|
170
|
+
|
|
171
|
+
# Or every metric at once for one exped (ai_model = crowd consensus for that exped):
|
|
172
|
+
scoring.score(preds_e, target_e, ai_model=consensus_e, features=features_e)
|
|
173
|
+
# -> {"corr20", "aimc20", "payout", "fnc", "feature_exposure"}
|
|
147
174
|
```
|
|
148
175
|
|
|
176
|
+
**Sanity-check your pipeline against the example predictions.** The published
|
|
177
|
+
`eiq_validation_example_preds` are a benchmark-grade signal (the Minera ensemble)
|
|
178
|
+
and score a positive mean **CORR20 of ≈ 0.07**. Score that file and reproduce a
|
|
179
|
+
similar number — if you instead get ≈ −0.07, your sign is flipped; if you get ≈ 0,
|
|
180
|
+
your ids/alignment are off:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
ex = pd.read_parquet("eiq_validation_example_preds.parquet") # column: prediction
|
|
184
|
+
val = pd.read_parquet("eiq_validation.parquet")
|
|
185
|
+
ref = [
|
|
186
|
+
scoring.corr20(ex.loc[val.exped == e, "prediction"], val.loc[val.exped == e, "target"])
|
|
187
|
+
for e in val.exped.unique()
|
|
188
|
+
]
|
|
189
|
+
print(sum(ref) / len(ref)) # ~0.07 -> pipeline + sign are correct
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
A quick convenience for a single overall correlation is also available:
|
|
193
|
+
`EverestAPI.evaluate(predictions, val, target="target_everest_20")`.
|
|
194
|
+
|
|
149
195
|
### CLI
|
|
150
196
|
|
|
151
197
|
```bash
|
|
@@ -175,6 +221,7 @@ with EverestAPI(api_key="...") as api:
|
|
|
175
221
|
|
|
176
222
|
- Python 3.10+
|
|
177
223
|
- httpx >= 0.27
|
|
224
|
+
- Optional `scoring` extra (`pip install "everestapi[scoring]"`): numpy, pandas, scipy — only needed for offline `everestapi.scoring`.
|
|
178
225
|
|
|
179
226
|
## Disclaimers
|
|
180
227
|
|
|
@@ -27,13 +27,16 @@ dependencies = [
|
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
[project.optional-dependencies]
|
|
30
|
-
dev = ["pytest>=8.0", "pytest-httpx>=0.34.0"]
|
|
30
|
+
dev = ["pytest>=8.0", "pytest-httpx>=0.34.0", "numpy>=1.26", "pandas>=2.0", "scipy>=1.10"]
|
|
31
31
|
# MCP server (`python -m everestapi.mcp`). Optional — the server falls back to a
|
|
32
32
|
# built-in JSON-RPC stdio loop when the official `mcp` SDK isn't installed.
|
|
33
33
|
mcp = ["mcp>=1.0"]
|
|
34
34
|
# Plotting helpers (`everestapi.plots`). Heavy — pulls matplotlib/pandas/numpy/
|
|
35
35
|
# scipy/statsmodels/mizani. Optional: the SDK and MCP server never import it.
|
|
36
36
|
viz = ["plotnine>=0.13"]
|
|
37
|
+
# Local scoring (`everestapi.scoring`). Optional — keeps the base SDK light
|
|
38
|
+
# (httpx + click only); pull these in to score validation preds offline.
|
|
39
|
+
scoring = ["numpy>=1.26", "pandas>=2.0", "scipy>=1.10"]
|
|
37
40
|
|
|
38
41
|
[project.scripts]
|
|
39
42
|
everestapi = "everestapi.cli:cli"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""EverestAPI — Python SDK for the Everesteer prediction tournament platform."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.2.
|
|
3
|
+
__version__ = "0.2.7"
|
|
4
4
|
|
|
5
5
|
from everestapi.client import EverestAPI, EverestError
|
|
6
6
|
from everestapi.types import (
|
|
@@ -29,4 +29,15 @@ __all__ = [
|
|
|
29
29
|
"StakeResponse",
|
|
30
30
|
"Submission",
|
|
31
31
|
"UniverseResponse",
|
|
32
|
+
"scoring",
|
|
32
33
|
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def __getattr__(name):
|
|
37
|
+
# Lazy import so `import everestapi` stays light (httpx + click only) — the
|
|
38
|
+
# numpy/pandas/scipy stack is only loaded if you actually use scoring.
|
|
39
|
+
if name == "scoring":
|
|
40
|
+
import everestapi.scoring as scoring
|
|
41
|
+
|
|
42
|
+
return scoring
|
|
43
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -108,7 +108,7 @@ def submit(model: str, file_path: str, tournament: str, api_key: str | None) ->
|
|
|
108
108
|
try:
|
|
109
109
|
if ext == "parquet":
|
|
110
110
|
result = api.submit_predictions_file(
|
|
111
|
-
|
|
111
|
+
model_id=model,
|
|
112
112
|
file_path=file_path,
|
|
113
113
|
tournament=tournament,
|
|
114
114
|
)
|
|
@@ -133,9 +133,7 @@ def _json_or_raise(resp: httpx.Response) -> dict:
|
|
|
133
133
|
except Exception:
|
|
134
134
|
body = (resp.text or "").strip()
|
|
135
135
|
looks_like_cf = (
|
|
136
|
-
"<html" in body[:200].lower()
|
|
137
|
-
or "cloudflare" in body.lower()
|
|
138
|
-
or "AccessDenied" in body
|
|
136
|
+
"<html" in body[:200].lower() or "cloudflare" in body.lower() or "AccessDenied" in body
|
|
139
137
|
)
|
|
140
138
|
hint = (
|
|
141
139
|
" — this looks like a Cloudflare Access challenge; set "
|
|
@@ -145,14 +143,11 @@ def _json_or_raise(resp: httpx.Response) -> dict:
|
|
|
145
143
|
)
|
|
146
144
|
raise EverestError(
|
|
147
145
|
resp.status_code,
|
|
148
|
-
f"expected a JSON response but received non-JSON content{hint}: "
|
|
149
|
-
f"{body[:200]}",
|
|
146
|
+
f"expected a JSON response but received non-JSON content{hint}: {body[:200]}",
|
|
150
147
|
)
|
|
151
148
|
|
|
152
149
|
|
|
153
|
-
def _check_prediction_range(
|
|
154
|
-
values: dict[str, float], *, lo: float = 0.0, hi: float = 1.0
|
|
155
|
-
) -> None:
|
|
150
|
+
def _check_prediction_range(values: dict[str, float], *, lo: float = 0.0, hi: float = 1.0) -> None:
|
|
156
151
|
"""Raise ``ValueError`` if any prediction is non-finite or outside ``[lo, hi]``.
|
|
157
152
|
|
|
158
153
|
Mirrors the server-side futures bound so a bad submission fails fast
|
|
@@ -173,8 +168,7 @@ def _check_prediction_range(
|
|
|
173
168
|
preview = ", ".join(bad[:5])
|
|
174
169
|
more = f" (+{len(bad) - 5} more)" if len(bad) > 5 else ""
|
|
175
170
|
raise ValueError(
|
|
176
|
-
f"{len(bad)} prediction(s) must be finite and within "
|
|
177
|
-
f"[{lo}, {hi}]: {preview}{more}"
|
|
171
|
+
f"{len(bad)} prediction(s) must be finite and within [{lo}, {hi}]: {preview}{more}"
|
|
178
172
|
)
|
|
179
173
|
|
|
180
174
|
|
|
@@ -187,11 +181,7 @@ def _resolve_default_base_url() -> str:
|
|
|
187
181
|
(CloudFront→S3) that serves no ``/api`` — defaulting there returns an S3
|
|
188
182
|
``AccessDenied`` for every call, so it is deliberately not the fallback.
|
|
189
183
|
"""
|
|
190
|
-
return (
|
|
191
|
-
os.getenv("EIQ_BASE_URL")
|
|
192
|
-
or os.getenv("EVEREST_API_URL")
|
|
193
|
-
or "https://app.everesteer.ai"
|
|
194
|
-
)
|
|
184
|
+
return os.getenv("EIQ_BASE_URL") or os.getenv("EVEREST_API_URL") or "https://app.everesteer.ai"
|
|
195
185
|
|
|
196
186
|
|
|
197
187
|
class EverestAPI:
|
|
@@ -326,29 +316,42 @@ class EverestAPI:
|
|
|
326
316
|
|
|
327
317
|
def submit_predictions_file(
|
|
328
318
|
self,
|
|
329
|
-
|
|
330
|
-
file_path: str,
|
|
319
|
+
model_id: str | None = None,
|
|
320
|
+
file_path: str | None = None,
|
|
331
321
|
tournament: str | None = None,
|
|
322
|
+
*,
|
|
323
|
+
model_name: str | None = None,
|
|
332
324
|
) -> dict:
|
|
333
325
|
"""POST /api/v1/predictions/upload — submit predictions as a CSV or Parquet file.
|
|
334
326
|
|
|
335
327
|
Parameters
|
|
336
328
|
----------
|
|
337
|
-
|
|
338
|
-
Model identifier.
|
|
329
|
+
model_id : str
|
|
330
|
+
Model identifier. (``model_name`` is a deprecated alias.)
|
|
339
331
|
file_path : str
|
|
340
332
|
Path to a ``.csv`` or ``.parquet`` file with columns ``ticker`` (str)
|
|
341
333
|
and ``score`` (float in [-1, 1]).
|
|
342
334
|
tournament : str, optional
|
|
343
335
|
Tournament identifier. Defaults to the client's tournament.
|
|
344
336
|
"""
|
|
337
|
+
if model_id is None:
|
|
338
|
+
if model_name is None:
|
|
339
|
+
raise TypeError("submit_predictions_file() missing required argument: 'model_id'")
|
|
340
|
+
import warnings
|
|
341
|
+
|
|
342
|
+
warnings.warn(
|
|
343
|
+
"model_name= is deprecated; use model_id=", DeprecationWarning, stacklevel=2
|
|
344
|
+
)
|
|
345
|
+
model_id = model_name
|
|
346
|
+
if file_path is None:
|
|
347
|
+
raise TypeError("submit_predictions_file() missing required argument: 'file_path'")
|
|
345
348
|
tourn = tournament or self.tournament
|
|
346
349
|
with open(file_path, "rb") as f:
|
|
347
350
|
fname = file_path.rsplit("/", 1)[-1].rsplit("\\", 1)[-1]
|
|
348
351
|
resp = self._client.post(
|
|
349
352
|
"/api/v1/predictions/upload",
|
|
350
353
|
files={"file": (fname, f, "application/octet-stream")},
|
|
351
|
-
params={"model_id":
|
|
354
|
+
params={"model_id": model_id, "tournament": tourn},
|
|
352
355
|
)
|
|
353
356
|
return _json_or_raise(resp)
|
|
354
357
|
|
|
@@ -491,9 +494,7 @@ class EverestAPI:
|
|
|
491
494
|
)
|
|
492
495
|
return "\n".join(lines)
|
|
493
496
|
|
|
494
|
-
def get_validation_panel(
|
|
495
|
-
self, model_id: str, days: int = 365, source: str = "auto"
|
|
496
|
-
) -> dict:
|
|
497
|
+
def get_validation_panel(self, model_id: str, days: int = 365, source: str = "auto") -> dict:
|
|
497
498
|
"""GET /api/v1/models/{model_id}/diagnostics/validation — full validation metrics.
|
|
498
499
|
|
|
499
500
|
``source="auto"`` (default) returns the latest completed validation-diagnostics
|
|
@@ -551,9 +552,19 @@ class EverestAPI:
|
|
|
551
552
|
output_path,
|
|
552
553
|
)
|
|
553
554
|
|
|
554
|
-
def get_scores(self, model_id: str, days: int = 30) -> dict:
|
|
555
|
-
"""GET /api/v1/scores — scoring results for a model.
|
|
556
|
-
|
|
555
|
+
def get_scores(self, model_id: str, days: int = 30, response_format: str = "concise") -> dict:
|
|
556
|
+
"""GET /api/v1/scores — scoring results for a model.
|
|
557
|
+
|
|
558
|
+
``response_format="detailed"`` asks the platform to add a plain-language
|
|
559
|
+
``interpretation`` field that reads the model's own latest numbers and
|
|
560
|
+
state and explains how to improve. ``"concise"`` (default) leaves the
|
|
561
|
+
response unchanged.
|
|
562
|
+
"""
|
|
563
|
+
params = {
|
|
564
|
+
"model_id": model_id,
|
|
565
|
+
"days": str(days),
|
|
566
|
+
"response_format": response_format,
|
|
567
|
+
}
|
|
557
568
|
return self._request("GET", "/api/v1/scores", params=params)
|
|
558
569
|
|
|
559
570
|
def get_leaderboard(self, period: str = "30d") -> dict:
|
|
@@ -632,9 +643,15 @@ class EverestAPI:
|
|
|
632
643
|
params["date"] = date
|
|
633
644
|
return self._request("GET", f"/api/v1/diagnostics/{model_id}", params=params)
|
|
634
645
|
|
|
635
|
-
def get_round_diagnostics(self, model_id: str) -> dict:
|
|
636
|
-
"""GET /api/v1/diagnostics/{model_id}/rounds — per-round scoring breakdown.
|
|
637
|
-
|
|
646
|
+
def get_round_diagnostics(self, model_id: str, response_format: str = "concise") -> dict:
|
|
647
|
+
"""GET /api/v1/diagnostics/{model_id}/rounds — per-round scoring breakdown.
|
|
648
|
+
|
|
649
|
+
``response_format="detailed"`` asks the platform to add a plain-language
|
|
650
|
+
``interpretation`` field grounded in the model's own latest numbers and
|
|
651
|
+
state. ``"concise"`` (default) leaves the response unchanged.
|
|
652
|
+
"""
|
|
653
|
+
params = {"response_format": response_format}
|
|
654
|
+
return self._request("GET", f"/api/v1/diagnostics/{model_id}/rounds", params=params)
|
|
638
655
|
|
|
639
656
|
# -- futures tournament -----------------------------------------------
|
|
640
657
|
|
|
@@ -900,8 +917,8 @@ class EverestAPI:
|
|
|
900
917
|
|
|
901
918
|
# -- rounds -----------------------------------------------------------
|
|
902
919
|
|
|
903
|
-
def get_rounds(self, tournament: str = "
|
|
904
|
-
"""GET /api/v1/rounds — list tournament rounds."""
|
|
920
|
+
def get_rounds(self, tournament: str = "futures", limit: int = 25) -> dict:
|
|
921
|
+
"""GET /api/v1/rounds — list tournament rounds (defaults to 'futures'; equities is unlaunched)."""
|
|
905
922
|
return self._request(
|
|
906
923
|
"GET",
|
|
907
924
|
"/api/v1/rounds",
|
|
@@ -911,8 +928,13 @@ class EverestAPI:
|
|
|
911
928
|
},
|
|
912
929
|
)
|
|
913
930
|
|
|
914
|
-
def get_current_round(self, tournament: str = "
|
|
915
|
-
"""GET /api/v1/rounds/current — current active round.
|
|
931
|
+
def get_current_round(self, tournament: str = "futures") -> dict:
|
|
932
|
+
"""GET /api/v1/rounds/current — current active round (defaults to 'futures'; equities is unlaunched).
|
|
933
|
+
|
|
934
|
+
With a hackathon-scoped key there is no live round — the response is a
|
|
935
|
+
diagnostics-mode payload (mode='diagnostics_hackathon') directing you to
|
|
936
|
+
download_dataset + submit_validation_diagnostics.
|
|
937
|
+
"""
|
|
916
938
|
return self._request(
|
|
917
939
|
"GET",
|
|
918
940
|
"/api/v1/rounds/current",
|
|
@@ -925,6 +947,35 @@ class EverestAPI:
|
|
|
925
947
|
"""GET /api/v1/schedule — round schedule for both tournaments."""
|
|
926
948
|
return self._request("GET", "/api/v1/schedule")
|
|
927
949
|
|
|
950
|
+
def get_started(self) -> dict:
|
|
951
|
+
"""GET /api/v1/get_started — mode-aware orientation.
|
|
952
|
+
|
|
953
|
+
Returns what to do next given this key's scope: the display-only
|
|
954
|
+
diagnostics-hackathon loop, or the live futures tournament flow.
|
|
955
|
+
"""
|
|
956
|
+
return self._request("GET", "/api/v1/get_started")
|
|
957
|
+
|
|
958
|
+
def get_status(self) -> dict:
|
|
959
|
+
"""GET /api/v1/status — state-aware orientation ("where am I").
|
|
960
|
+
|
|
961
|
+
Your whole situational picture in one call: the models you own, each
|
|
962
|
+
one's latest submission and score state, the open round's clock, your
|
|
963
|
+
stake, and a ``next_actions`` list — instead of stitching together
|
|
964
|
+
get_models + get_scores + get_current_round. Display-only.
|
|
965
|
+
"""
|
|
966
|
+
return self._request("GET", "/api/v1/status")
|
|
967
|
+
|
|
968
|
+
def get_capabilities(self) -> dict:
|
|
969
|
+
"""GET / (site root) with ``Accept: application/json`` — capability index.
|
|
970
|
+
|
|
971
|
+
A small machine-readable map of where everything lives: pointers to
|
|
972
|
+
``llms.txt``, the OpenAPI spec, the MCP endpoint, the API base, the SDK,
|
|
973
|
+
and related discovery URLs. Hit before anything else to learn the
|
|
974
|
+
platform's shape without hardcoding paths. The index sits at the host
|
|
975
|
+
root; a leading-slash path resolves there against the API host base URL.
|
|
976
|
+
"""
|
|
977
|
+
return self._request("GET", "/", headers={"Accept": "application/json"})
|
|
978
|
+
|
|
928
979
|
# -- model uploads ----------------------------------------------------
|
|
929
980
|
|
|
930
981
|
def upload_model(self, model_id: str, file_path: str) -> dict:
|