Participant SDK for the EPIC — ELIOS Predictive Intelligence Challenge platform.
Project description
EPIC Participant SDK
The EPIC client is the official Python SDK for the EPIC platform. It gives everything you need to participate in a contest: authentication, contest discovery, real-time data streaming, forecast submission, and results inspection; all from a few lines of Python, in scripts and Jupyter notebooks alike.
Installation
pip install epic-elios-client
For the Jupyter quickstart notebook, install the optional extras (adds pandas for the CSV helpers):
pip install "epic-elios-client[notebook]"
The SDK requires Python 3.11 or later.
Quickstart
The steps below walk through a complete participation cycle. For a full narrative walkthrough with plots and model-building, see the quickstart notebook.
1. Authenticate
from epic_client import EPICClient
client = EPICClient("https://epic.elioslab.net")
login = client.login("your-username", "your-password")
if login.get("status") == "ERROR":
print("Login failed:", login["message"])
else:
print("Logged in.")
login() stores the bearer token internally. All subsequent calls are authenticated automatically.
2. Browse and register for a contest
contests = client.list_contests(status="ACTIVE")
for c in contests:
print(c["contest_id"], c["name"], c["sampling_rate_hz"], "Hz")
contest_id = contests[0]["contest_id"]
task_spec = client.get_task_spec(contest_id)
registration = client.register(contest_id) # idempotent — safe to call more than once
print(registration)
3. Collect observations during the observation phase
collect() opens a WebSocket connection and returns a list of observation dicts when either duration_seconds elapses or the observation phase ends — whichever comes first.
import asyncio
observations = asyncio.run(client.collect(contest_id, duration_seconds=60))
print(f"Collected {len(observations)} observations")
print(observations[-1])
# {"sequence_id": 42, "timestamp": "2027-01-10T09:01:00Z", "sensors": {"position": 0.134}}
You can also save to CSV for offline analysis:
observations = asyncio.run(
client.collect(contest_id, duration_seconds=60, csv_path="data.csv")
)
The CSV file is written with one column per sensor, for example sequence_id,timestamp,position,velocity.
For finer control, use the async generator stream() directly:
async def collect_custom():
async for obs in client.stream(contest_id):
print(obs["sequence_id"], obs["sensors"])
# break early, filter, etc.
asyncio.run(collect_custom())
stream() stops automatically when the observation phase ends. Pass include_events=True to also receive control events such as evaluation_started before the generator stops.
4. Build your model
Use whatever modelling approach you like. The simplest possible baseline repeats the last observed value:
last = observations[-1]["sensors"]
task_spec = client.get_task_spec(contest_id)
eval_steps = task_spec["eval_steps"]
target_variables = task_spec["target_variables"]
forecast = {
target: [last[target]] * eval_steps
for target in target_variables
}
The number of steps to predict is derived from the contest configuration:
eval_steps = round(prediction_horizon_seconds × sampling_rate_hz)
Read eval_steps and the required target_variables directly from the task spec as shown above.
5. Submit your forecast
Wait until the submission window opens (the evaluation phase has ended), then submit:
submission = client.submit(
contest_id=contest_id,
task_id="forecasting",
payload={"forecast": forecast},
)
print(submission)
payload["forecast"] must map each required target variable to a list of exactly eval_steps float values. You may submit multiple times — the platform scores each submission and keeps your best on the leaderboard. If the submission window is not open yet, submit() returns {"status": "NOT_OPEN", "opens_at": "..."} and emits a warning instead of raising.
6. Check your scores and the leaderboard
scores = client.get_scores(contest_id)
for sub in scores["submissions"]:
print(sub["submission_id"], sub["scores"])
leaderboard = client.get_leaderboard(contest_id)
for entry in leaderboard["entries"]:
print(entry["rank"], entry["username"], entry["score"])
Complete example
import asyncio
from epic_client import EPICClient
async def main():
client = EPICClient("https://epic.elioslab.net")
login = client.login("your-username", "your-password")
if login.get("status") == "ERROR":
print("Login failed:", login["message"])
return
# Discover the contest
contests = client.list_contests(status="ACTIVE")
contest_id = contests[0]["contest_id"]
task_spec = client.get_task_spec(contest_id)
eval_steps = task_spec["eval_steps"]
target_variables = task_spec["target_variables"]
# Register (safe to call even if already registered)
client.register(contest_id)
# Collect data during the observation phase
observations = await client.collect(contest_id, duration_seconds=120)
print(f"Collected {len(observations)} observations")
# Build a naive forecast (replace with your model)
last_sensors = observations[-1]["sensors"]
forecast = {
sensor: [value] * eval_steps
for sensor, value in last_sensors.items()
if sensor in target_variables
}
# Submit
submission = client.submit(
contest_id=contest_id,
task_id="forecasting",
payload={"forecast": forecast},
)
print("Submitted:", submission["submission_id"])
# Check scores
scores = client.get_scores(contest_id)
print("Scores:", scores)
asyncio.run(main())
API Reference
EPICClient(server_url, raise_on_error=False)
Instantiate the client by passing the server URL. Defaults to "https://epic.elioslab.net" if omitted. By default the SDK is notebook-friendly: expected platform states and API errors become warnings plus structured return values instead of stack traces. Pass raise_on_error=True when writing scripts that should fail fast.
| Method | Signature | Description |
|---|---|---|
login |
login(username, password) → dict |
Authenticate and store the bearer token for all subsequent requests. Returns the token payload, or {"status": "ERROR", ...} with a warning on invalid credentials. |
list_contests |
list_contests(status=None, visibility=None, limit=100, offset=0) → list[dict] |
Return all contests visible to you. Pass status="ACTIVE" to filter to running contests. |
get_contest |
get_contest(contest_id) → dict |
Return the full contest object, including task and sensor configuration. |
get_task_spec |
get_task_spec(contest_id, task_type="FORECASTING") → dict |
Return the task with convenience fields: eval_steps, target_variables, sampling_rate_hz, and sensor_ids. |
register |
register(contest_id, raise_on_not_open=False) → dict |
Register for a contest. Idempotent — safe to call on an already-registered contest. |
collect |
collect(contest_id, duration_seconds, csv_path=None, raise_on_stream_error=False) → list[dict] |
Stream observations for up to duration_seconds and return them as a list. Stops early if the observation phase ends. Optionally writes to CSV as observations arrive. |
stream |
stream(contest_id, include_events=False) → AsyncIterator[dict] |
Async generator yielding one observation dict per sensor tick. Reconnects on transient network errors. Stops when the observation phase ends. |
submit |
submit(contest_id, task_id, payload, raise_on_not_open=False) → dict |
Submit a forecast. task_id is "forecasting". payload must be {"forecast": {"target_variable": [v1, v2, …], …}} with exactly eval_steps values per target variable. |
get_scores |
get_scores(contest_id) → dict |
Return all your submissions for this contest with their computed scores. |
get_leaderboard |
get_leaderboard(contest_id) → dict |
Return the current public leaderboard for this contest. |
Observation dict
Each observation yielded by stream() or returned in the list from collect():
{
"sequence_id": 42, # monotonically increasing integer
"committed_through": 40, # latest sequence durably stored by the server
"timestamp": "2027-01-10T09:00:04.200Z", # UTC ISO-8601 string
"sensors": { # one key per configured sensor
"position": 0.134,
"velocity": -0.021,
},
}
Forecast payload
{
"forecast": {
"position": [0.130, 0.127, 0.124, ...], # exactly eval_steps floats
"velocity": [-0.019, -0.018, -0.017, ...],
}
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file epic_elios_client-1.0.13.tar.gz.
File metadata
- Download URL: epic_elios_client-1.0.13.tar.gz
- Upload date:
- Size: 17.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29e766a83ebe422562523626cf85ea57dd079c1b61df783c60ff14306244d778
|
|
| MD5 |
e0225d3592ef9c12f0ca32d153238847
|
|
| BLAKE2b-256 |
8cc1889f4c923e85b0230e24f79b0f6e92b81dc3c919c03fc819fb4f1c7c8bb5
|
Provenance
The following attestation bundles were made for epic_elios_client-1.0.13.tar.gz:
Publisher:
publish-client.yml on Elios-Lab/epic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
epic_elios_client-1.0.13.tar.gz -
Subject digest:
29e766a83ebe422562523626cf85ea57dd079c1b61df783c60ff14306244d778 - Sigstore transparency entry: 1870324596
- Sigstore integration time:
-
Permalink:
Elios-Lab/epic@d231eb90c486f26714d9fe75784b064f1673b428 -
Branch / Tag:
refs/tags/client-v1.0.13 - Owner: https://github.com/Elios-Lab
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-client.yml@d231eb90c486f26714d9fe75784b064f1673b428 -
Trigger Event:
push
-
Statement type:
File details
Details for the file epic_elios_client-1.0.13-py3-none-any.whl.
File metadata
- Download URL: epic_elios_client-1.0.13-py3-none-any.whl
- Upload date:
- Size: 9.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3fe7fcc29e76ed9eb7173eac3f73ca720afa11450509f1a8f7de03a243de265
|
|
| MD5 |
de18d0b7855aa2357ebe58cab2f5d668
|
|
| BLAKE2b-256 |
e2a6071bf3f2e9a0960a965af5904dec912f6cc3cf946d1210ca6649da2d5af2
|
Provenance
The following attestation bundles were made for epic_elios_client-1.0.13-py3-none-any.whl:
Publisher:
publish-client.yml on Elios-Lab/epic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
epic_elios_client-1.0.13-py3-none-any.whl -
Subject digest:
b3fe7fcc29e76ed9eb7173eac3f73ca720afa11450509f1a8f7de03a243de265 - Sigstore transparency entry: 1870324672
- Sigstore integration time:
-
Permalink:
Elios-Lab/epic@d231eb90c486f26714d9fe75784b064f1673b428 -
Branch / Tag:
refs/tags/client-v1.0.13 - Owner: https://github.com/Elios-Lab
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-client.yml@d231eb90c486f26714d9fe75784b064f1673b428 -
Trigger Event:
push
-
Statement type: