Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions data/sample/events_sample.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000001", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-27T21:00:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "MSFT"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000002", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-27T21:05:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "GOOGL"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000003", "event_type": "MACRO_DATA_CPI", "timing_category": "SCHEDULED", "event_datetime": "2026-01-28T13:30:00Z", "focal_assets": []},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000003", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-28T12:10:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "BA"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000004", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-28T21:00:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "META"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000005", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-28T21:02:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "TSLA"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000006", "event_type": "FOMC_MEETING", "timing_category": "SCHEDULED", "event_datetime": "2026-01-28T19:00:00Z", "focal_assets": []},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000006", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-28T21:10:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "IBM"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000007", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-29T21:00:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "AAPL"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000008", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-29T21:03:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "AMZN"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000009", "event_type": "MACRO_DATA_JOBS", "timing_category": "SCHEDULED", "event_datetime": "2026-01-30T13:30:00Z", "focal_assets": []},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-000000000009", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-01-30T12:00:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "CVX"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-00000000000a", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-02-03T21:00:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "AMD"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-00000000000b", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-02-04T21:00:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "NVDA"}]},
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-00000000000c", "event_type": "UNSCHEDULED_8K", "timing_category": "UNSCHEDULED", "event_datetime": "2026-02-04T14:12:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "BA"}]}
{"event_id": "0f8c2a10-1b2c-4d5e-8a9b-00000000000c", "event_type": "EARNINGS_RELEASE", "timing_category": "SCHEDULED", "event_datetime": "2026-02-04T21:05:00Z", "focal_assets": [{"identifier_type": "TICKER", "identifier_value": "QCOM"}]}
]
33 changes: 17 additions & 16 deletions notebooks/00_api_quickstart.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "de059abe",
"id": "0",
"metadata": {},
"source": [
"# 00 — API quickstart\n",
Expand All @@ -27,7 +27,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "f265bfab",
"id": "1",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -53,20 +53,21 @@
},
{
"cell_type": "markdown",
"id": "ac4f8bec",
"id": "2",
"metadata": {},
"source": [
"## 1. Events calendar — `GET /events`\n",
"\n",
"The calendar lists scheduled and realized events. Each event has a type\n",
"(`EARNINGS_RELEASE`, `FOMC_MEETING`, `MACRO_DATA_CPI`, …), a timestamp, and its\n",
"focal assets. We flatten it into a tidy, sorted table."
"The calendar lists scheduled and realized events. Each event has a type — an open\n",
"string set; currently only `EARNINGS_RELEASE` is emitted, though new types may be\n",
"added over time — a timestamp, and its focal assets. We flatten it into a tidy,\n",
"sorted table."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f10f5b96",
"id": "3",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -84,7 +85,7 @@
},
{
"cell_type": "markdown",
"id": "e4b600a9",
"id": "4",
"metadata": {},
"source": [
"A stacked daily bar makes the shape of the calendar obvious at a glance — how many events land each day, split by type."
Expand All @@ -93,7 +94,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "5b235d06",
"id": "5",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -103,7 +104,7 @@
},
{
"cell_type": "markdown",
"id": "f643972a",
"id": "6",
"metadata": {},
"source": [
"## 2. Historical archive — `GET /archive`\n",
Expand All @@ -115,7 +116,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "9c6ae5d4",
"id": "7",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -129,7 +130,7 @@
},
{
"cell_type": "markdown",
"id": "7a908689",
"id": "8",
"metadata": {},
"source": [
"## 3. Webhook self-test — `POST /webhook/test`\n",
Expand All @@ -144,7 +145,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "0ed1ae69",
"id": "9",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -164,7 +165,7 @@
},
{
"cell_type": "markdown",
"id": "a4d5fd07",
"id": "10",
"metadata": {},
"source": [
"## 4. Submission health — `GET /health`\n",
Expand All @@ -177,7 +178,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "4bfe3063",
"id": "11",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -191,7 +192,7 @@
},
{
"cell_type": "markdown",
"id": "b68c2b90",
"id": "12",
"metadata": {},
"source": [
"## Next steps\n",
Expand Down
35 changes: 19 additions & 16 deletions notebooks/01_historical_archive.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"id": "fe91093f",
"id": "0",
"metadata": {},
"source": [
"# 01 — Historical archive\n",
Expand All @@ -27,7 +27,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "55ec7f88",
"id": "1",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -49,7 +49,7 @@
},
{
"cell_type": "markdown",
"id": "976571f4",
"id": "2",
"metadata": {},
"source": [
"## 1. Browse the manifest\n",
Expand All @@ -62,7 +62,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "92bf78c9",
"id": "3",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -77,7 +77,7 @@
},
{
"cell_type": "markdown",
"id": "b458237d",
"id": "4",
"metadata": {},
"source": [
"## 2. Download & cache\n",
Expand All @@ -90,7 +90,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "cc9c32ba",
"id": "5",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -111,7 +111,7 @@
},
{
"cell_type": "markdown",
"id": "f91590d0",
"id": "6",
"metadata": {},
"source": [
"## 3. Load into pandas\n",
Expand All @@ -124,7 +124,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "606a8720",
"id": "7",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -136,7 +136,7 @@
},
{
"cell_type": "markdown",
"id": "416486f5",
"id": "8",
"metadata": {},
"source": [
"## 4. Inspect one event\n",
Expand All @@ -149,7 +149,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "4c85dae3",
"id": "9",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -173,7 +173,7 @@
},
{
"cell_type": "markdown",
"id": "fa6bd3bd",
"id": "10",
"metadata": {},
"source": [
"## 5. Reproduce the baseline scoring regressions\n",
Expand Down Expand Up @@ -204,7 +204,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "a2f1e8d0",
"id": "11",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -230,7 +230,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "45e5fce0",
"id": "12",
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -267,7 +267,7 @@
},
{
"cell_type": "markdown",
"id": "f757e389",
"id": "13",
"metadata": {},
"source": [
"## Where to go from here\n",
Expand All @@ -277,8 +277,11 @@
"\n",
"1. Pair each event with the realized next-day reaction for its focal asset, from\n",
" your own market-data source.\n",
"2. Convert that reaction into a percentile against the asset's historical\n",
" distribution — the same `[0, 1]` target the competition scores.\n",
"2. Convert that reaction into a percentile rank in `[0, 1]` **across the\n",
" quarter's cross-section** of scored event outcomes — a rank against all the\n",
" period's events, not against the asset's own history. That's the target the\n",
" competition scores; `examples.scoring.percentile_ranks` is the exact\n",
" transform (see section 5).\n",
"3. Score your model's predicted percentile against it offline, and iterate.\n",
"\n",
"When your model is ready, move it into a deployed webhook handler (see the starter\n",
Expand Down
5 changes: 3 additions & 2 deletions src/examples/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
These mirror the competition's OpenAPI schemas (``/docs/api``). They are
deliberately **lenient** — ``extra="allow"`` — so unknown or newly added fields
pass through untouched rather than raising. Event types in particular are an
open string set (``EARNINGS_RELEASE``, ``FOMC_MEETING``, ``MACRO_DATA_CPI``, …),
so we keep them as plain ``str`` and never validate against a closed enum.
open string set — currently only ``EARNINGS_RELEASE`` is emitted — so we keep
them as plain ``str`` and never validate against a closed enum; new types can
appear without breaking parsing.

Only the read/exercise endpoints are modeled here. Prediction *submission*
(``POST /predictions``) is intentionally omitted — that belongs to a live agent
Expand Down
23 changes: 16 additions & 7 deletions tests/test_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@


def test_events_frame_sorts_and_flattens(sample_events: list[dict]) -> None:
events = [CalendarEvent.model_validate(e) for e in sample_events]
# event_type is an open string set: an as-yet-unknown type (here with no
# focal assets) must flow through without any special-casing.
future_event = {
"event_id": "0f8c2a10-1b2c-4d5e-8a9b-0000000000ff",
"event_type": "SOME_FUTURE_TYPE",
"timing_category": "SCHEDULED",
"event_datetime": "2026-01-28T13:30:00Z",
"focal_assets": [],
}
events = [CalendarEvent.model_validate(e) for e in [*sample_events, future_event]]
df = events_frame(events)

assert list(df.columns) == [
Expand All @@ -24,10 +33,10 @@ def test_events_frame_sorts_and_flattens(sample_events: list[dict]) -> None:
earnings = df[df["event_type"] == "EARNINGS_RELEASE"].iloc[0]
assert earnings["n_assets"] == 1
assert earnings["tickers"] != ""
# A macro event with no focal assets renders as empty tickers, zero count.
macro = df[df["event_type"] == "MACRO_DATA_CPI"].iloc[0]
assert macro["tickers"] == ""
assert macro["n_assets"] == 0
# An event with no focal assets renders as empty tickers, zero count.
no_assets = df[df["event_type"] == "SOME_FUTURE_TYPE"].iloc[0]
assert no_assets["tickers"] == ""
assert no_assets["n_assets"] == 0


def test_events_frame_empty() -> None:
Expand All @@ -41,7 +50,7 @@ def test_manifest_frame_hides_urls_and_sorts() -> None:
{
"files": [
{
"event_type": "FOMC_MEETING",
"event_type": "SOME_FUTURE_TYPE",
"quarter": "2026Q2",
"key": "k2",
"url": "https://cdn/secret2",
Expand All @@ -62,7 +71,7 @@ def test_manifest_frame_hides_urls_and_sorts() -> None:
df = manifest_frame(manifest)
# Signed URLs never surface in the display frame.
assert not any("url" in c for c in df.columns)
# Sorted by (event_type, quarter): EARNINGS before FOMC.
# Sorted by (event_type, quarter): EARNINGS_RELEASE before SOME_FUTURE_TYPE.
assert df.iloc[0]["event_type"] == "EARNINGS_RELEASE"
assert df.iloc[0]["size_mb"] == 0.0 # 863 bytes rounds to 0.00 MB
assert df.iloc[1]["size_mb"] == 2.0
Expand Down
Loading