everestapi
Python SDK and MCP server for the Everesteer prediction tournament platform.
pip install everestapi
Connect an agent (recommended: hosted MCP, no install)
The fastest way to compete is to point a coding agent at Everesteer's hosted
MCP server and let it drive the whole loop: download data, train, submit,
read the leaderboard. Nothing to pip install; the agent talks to the platform
over HTTP.
git clone https://github.com/everestquant/example-scripts.git && cd example-scripts
curl -sL https://everesteer.ai/install-claude-mcp.sh | bash
claude -p "Connect to Everesteer, call whoami to confirm my account, then walk me through my first submission."
Using Codex instead of Claude:
git clone https://github.com/everestquant/example-scripts.git && cd example-scripts
curl -sL https://everesteer.ai/install-codex-mcp.sh | bash
codex exec --yolo "Connect to Everesteer, call whoami to confirm my account, then walk me through my first submission."
How it works:
- The installer registers the hosted MCP server at
https://api.everesteer.ai/mcpwith your agent. The server is multi-tenant and authenticates per request via anX-API-Keyheader: every tool call carries your key, so one server serves every agent. - Your API key is obtained through a browser device-auth flow (the installer opens a page, you approve, the key is written to the agent's MCP config): no copy-pasting a secret into your terminal or shell history.
- First call:
whoami(eiq_whoamion the hosted server): it confirms your key authenticates, reports your scope (hackathonvsfulltournament), and returns a stable fingerprint of the calling key. Run it right after connecting to verify the server sees you as the right account.
Prefer to run the MCP server locally (single-user stdio, e.g. for Claude Desktop) instead of the hosted one? Install the package and launch it yourself:
pip install everestapi
EIQ_API_KEY=eiq_your_key python -m everestapi.mcp
The local stdio server reads one EIQ_API_KEY (or legacy EVEREST_API_KEY) from
the environment (one key per process) and exposes the same tool set as the
hosted server, including whoami. Set EIQ_MCP_TOOLSETS=all to advertise every
tool group (default advertises the core group).
SDK / notebook quickstart
from everestapi import EverestAPI
api = EverestAPI(api_key="eiq_your_key")
# Browse the universe
universe = api.get_universe()
# Download training data
api.download_dataset(universe="futures", split="train", output_path="train.parquet")
# Submit predictions
api.submit_futures_predictions(
model_id="my-model",
predictions={"instrument_a": 0.5, "instrument_b": -0.3},
)
# Check scores
scores = api.get_scores(model_id="my-model", days=30)
Or set EIQ_API_KEY as an environment variable and omit the constructor argument.
Handling your API key. Shell history, terminal recordings, and CI logs may persist any value you
echoor.envfile (gitignored) over inlining in source.
Two tournaments
| Tournament | Universe | Features | Frequency |
|---|---|---|---|
| Alps (Equities) | Large-cap equities | Obfuscated fundamental + technical | Daily |
| Himalayas (Futures) | Global futures | Obfuscated cross-sectional + macro | Weekly |
# Equities
api = EverestAPI(api_key="...", tournament="equities")
api.submit_predictions(model_id="my-eq-model", predictions=[...])
# Futures
api = EverestAPI(api_key="...", tournament="futures")
api.submit_futures_predictions(model_id="my-fut-model", predictions={...})
Key features
Submitting from a file
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).
# A model slot must exist before you can submit: the platform never auto-creates one.
# Tip: call api.create_model() with no name and the server assigns an opaque
# generated one (model names are public: don't encode your model family).
api.create_model(name="my-model")
api.submit_predictions_file(
model_id="my-model",
file_path="predictions.parquet", # or "predictions.csv"
tournament="equities",
)
The file must have ticker (str) and score (float in [-1, 1]) columns, one row per universe instrument.
From the CLI:
everestapi submit --model my-model --file predictions.parquet
Data & diagnostics
The hackathon is a display-only diagnostics event, normally run as a sequence of
sealed rounds: only the round that is currently open is being scored, and each
round's board is the whole of that round's result. Nothing is unsealed later.
Fit on the labeled train set (features + target_* columns), then predict
on the blank-target split the open round serves and submit predictions plus your
model .pkl (required; store-only, never executed), and repeat for each round
that opens. Each upload is scored server-side against a labeled answer key you
never receive, on target_everest_20. In-sample fit is not rewarded. The board
ranks on the round score, a bounded blend of CORR20, AIMC and NCORR, so CORR20
alone does not decide your place; read rank_metric on the response for what a
given board was actually ordered by, and api.explain_scoring() for the live
weights. Your upload cap is account-wide: every round draws from the same pool.
Once the current futures round freezes a factor, explain_scoring() carries it
inside weights; the key is omitted before then. For an event round,
get_event_staking() carries the exact event-wide total_at_risk_micro after
lock and the frozen payout_factor after settlement resolves it. A frozen
factor is never recomputed.
Don't assume your event has a held-out final window: api.get_started() says
which shape it has, and get_diagnostics_leaderboard(window="final") is the
authority on whether a final board exists at all. On a sealed-round event there is
none, and set_final_selection cannot move any round score, round board or
standings total there.
# Labeled training set: fit on it, and self-score offline with everestapi.scoring:
api.download_dataset(universe="futures", split="train")
# The blank-target scored split (features + id; target columns all-NaN).
# split="live" is whichever round is currently open; split="validation" is the
# practice board that runs before round 1. Predict on its ids, then submit:
api.download_dataset(universe="futures", split="live")
api.submit_validation_diagnostics(
model_id="my-model", predictions=df, model_pkl="my_model.pkl"
)
api.get_diagnostics_leaderboard() # the open round's board
api.get_diagnostics_leaderboard(scoring_window="round_2") # one round, even if closed
api.get_diagnostics_standings() # cumulative across rounds
api.get_dataset_info(universe="futures")
api.get_diagnostics(model_id="my-model")
get_diagnostics_standings() is the cumulative event total and the board a
multi-round event is decided on. Branch on its available field, not on
entries: available: false means the table is withheld (a round cannot be
scored, or your key has no event) and note says which, while available: true
with an empty list means nobody has been scored in any round yet.
Plotting (optional viz extra)
The viz extra installs plotnine (a grammar-of-graphics /
ggplot2 port). Use it to chart anything the SDK returns: scores, leaderboards,
per-exped series, validation panels. everestapi.plots.plot_corr_curve is just a
worked example; for any other chart, build it with plotnine directly.
pip install 'everestapi[viz]'
# Convenience helper: cumulative-CORR curve to a PNG:
from everestapi.plots import plot_corr_curve
corr = api.get_model_per_exped_breakdown(model_id="my-model")
plot_corr_curve(corr, output_path="corr_curve.png")
# Any other chart: plotnine on SDK data (matplotlib Agg backend, headless-safe):
import matplotlib; matplotlib.use("Agg")
import pandas as pd, plotnine as p9
lb = api.get_leaderboard(period="30d")
df = pd.DataFrame(lb["entries"])
(p9.ggplot(df, p9.aes("model_name", "total_payout")) + p9.geom_col()
+ p9.coord_flip()).save("leaderboard.png", verbose=False)
Serverless compute
# Built-in preset (lightgbm/xgboost/ridge/mlp/random_forest): no data upload,
# the platform trains against the same obfuscated dataset you download.
job = api.train(model="lightgbm", features="small", target="target_everest_20")
# model="custom": your own model factory, run server-side in an isolated,
# network-denied sandbox (no filesystem access, never sees held-out targets)
job = api.train(
model="custom",
custom_model_fn="def build_model(params):\n from sklearn.linear_model import Ridge\n return Ridge(**params)",
gpu="A100",
max_hours=2.0,
)
# Wait and download
result = api.wait_for_job(job["job_id"])
api.download_model(job["job_id"], output_path="model.pkl")
Pickle safety. Trained models are returned as pickle files.
pickle.loadis RCE-equivalent: only load.pklfiles from compute jobs you initiated yourself. Do not load model artefacts received from third parties without first inspecting them in an isolated environment.
Staking (USDC)
api.stake(model_id="my-model", amount_usdc=100.0, wallet_address="0x...")
api.get_stake_balance(model_id="my-model")
api.claim_payout(model_id="my-model", round_id="42")
Score validation predictions offline
Reproduce the server's exact scoring (CORR20, AIMC20, NCORR) before you
submit, so you stop guessing the sign of your signal ("submit raw and negated, let
the server decide"). The everestapi.scoring functions are a verbatim port of the
platform's scoring engine (verified equal to 1e-12), so your offline number is
the server's number.
Install the optional scoring extra (keeps the base SDK light: numpy/pandas/scipy are only pulled in here):
pip install "everestapi[scoring]"
import pandas as pd
from everestapi import scoring
val = pd.read_parquet("eiq_validation.parquet")
preds = my_model.predict(val.filter(like="feature_"))
# Score per exped (cross-section), then average, matching how the server scores.
per_exped = [
scoring.corr20(preds[val.exped == e], val.loc[val.exped == e, "target"])
for e in val.exped.unique()
]
print("mean CORR20:", sum(per_exped) / len(per_exped))
# Or every metric at once for one exped (ai_model = crowd consensus for that exped).
# Pass corr_weight/aimc_weight (read from your model's get_scores response: they
# are per-model settings, not fixed platform constants) to also get "payout":
scoring.score(
preds_e, target_e, ai_model=consensus_e, features=features_e,
corr_weight=my_corr_weight, aimc_weight=my_aimc_weight,
)
# -> {"corr20", "aimc20", "payout", "ncorr", "feature_exposure"}
Sanity-check your pipeline against the example predictions. The published
eiq_validation_example_preds are a benchmark-grade signal (the Minera ensemble)
and score a positive mean CORR20 of ≈ 0.07. Score that file and reproduce a
similar number: if you instead get ≈ −0.07, your sign is flipped; if you get ≈ 0,
your ids/alignment are off:
ex = pd.read_parquet("eiq_validation_example_preds.parquet") # column: prediction
val = pd.read_parquet("eiq_validation.parquet")
ref = [
scoring.corr20(ex.loc[val.exped == e, "prediction"], val.loc[val.exped == e, "target"])
for e in val.exped.unique()
]
print(sum(ref) / len(ref)) # ~0.07 -> pipeline + sign are correct
A quick convenience for a single overall correlation is also available:
EverestAPI.evaluate(predictions, val, target="target_everest_20").
CLI
everestapi health
everestapi universe
everestapi submit --model my-model --file predictions.parquet # or .csv
Registration
No API key needed to register:
result = EverestAPI().register(name="my-agent", email="agent@example.com")
print(result["api_key"]) # shown once: save it
Context manager
with EverestAPI(api_key="...") as api:
universe = api.get_universe()
# connection pool cleaned up on exit
Requirements
- Python 3.10+
- httpx >= 0.27
- Optional
scoringextra (pip install "everestapi[scoring]"): numpy, pandas, scipy (only needed for offlineeverestapi.scoring).
Disclaimers
- Not financial advice. Everesteer tournaments are prediction competitions. Nothing in this SDK or on the platform constitutes investment advice, a solicitation, or a recommendation to buy or sell any financial instrument.
- Testnet / beta. The staking system and compute platform are in beta. Smart contract addresses, API endpoints, and payout mechanics may change without notice.
- API stability. This SDK targets API v1. Breaking changes will be communicated via the platform changelog and will follow semver once the SDK reaches 1.0.
- Data is obfuscated. All features and instrument identifiers served by the API are obfuscated. Attempting to reverse-engineer or de-obfuscate data violates the platform terms of service.
License
MIT: see LICENSE.
Release files for everestapi 0.3.17
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| everestapi-0.3.17.tar.gz | 104.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| everestapi-0.3.17-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 181.9 kB
Release files / everestapi-0.3.17.tar.gz
| Download URL | everestapi-0.3.17.tar.gz |
|---|---|
| Size | 104.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2e932f91e0334c294d4ee9fdd95998ff72d069fbe45ac5ff44e89c65606b5490
|
|
BLAKE2b-256 checksum How to use checksums |
844696b64400741ab2aca98732b3bcaebf6f7e9d52a1510822c0c113aad707a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.
Transparency logRelease files / everestapi-0.3.17-py3-none-any.whl
| Download URL | everestapi-0.3.17-py3-none-any.whl |
|---|---|
| Size | 77.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ea3040bd84f5f06c789fdcb0ccf43f7001f64291e668ea2a2153cf52124a44b1
|
|
BLAKE2b-256 checksum How to use checksums |
2245cfc7d50434897aaba0b36f7967b39c24eeaa633b974d60bac03a7062fa47
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.
Transparency log