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
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

Notebook examples for exploring the [Explaining Markets](https://explainingmarkets.ai/)
competition API and its historical data archive. Notebook-first, with the repeated
competition API and its historical data archive — including the two disclosure items
each earnings event carries, the ten call facts and (from 2026Q3) the earnings
preview. Notebook-first, with the repeated
API / parsing / plotting boilerplate factored into a small `examples` package so the
notebooks stay short and readable.

Expand All @@ -18,8 +20,9 @@ notebooks stay short and readable.
| [`notebooks/00_api_quickstart.ipynb`](notebooks/00_api_quickstart.ipynb) | The read endpoints — events calendar (table + chart), submission health, archive manifest, webhook self-test |
| [`notebooks/01_historical_archive.ipynb`](notebooks/01_historical_archive.ipynb) | Download, cache, and load the historical archive, then reproduce the baseline scoring regressions (Koijen & Levy WP, Table 3) with the competition's exact scoring transform |
| [`notebooks/02_earnings_call_facts.ipynb`](notebooks/02_earnings_call_facts.ipynb) | Where each event's ten-fact `disclosure` comes from — the exact prompt, model config, and parsing behind it, and how extraction failures surface |
| [`notebooks/03_earnings_previews.ipynb`](notebooks/03_earnings_previews.ipynb) | The **earnings preview** — the agent-written pre-release research note that recent events carry as a second disclosure item: how it is built (at a high level), what it looks like, and how it pairs with the facts and the realized reaction |

All three run top-to-bottom. With an API key they hit the live API; **without one they
All four run top-to-bottom. With an API key they hit the live API; **without one they
fall back to a small bundled sample** (`data/sample/`), so you can run them — and CI
can execute them — with no credentials.

Expand Down Expand Up @@ -60,7 +63,7 @@ events_frame(events).head()

```text
notebooks/ the numbered, narrative examples
src/examples/ helper package: config · client · schemas · frames · plotting · archive · scoring · summary
src/examples/ helper package: config · client · schemas · frames · plotting · archive · scoring · summary · preview
scripts/ small runnable scripts (e.g. headless archive download)
tests/ offline unit tests (mocked HTTP + bundled sample data)
data/
Expand Down
8 changes: 8 additions & 0 deletions data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ Just enough data for the notebooks to run top-to-bottom **without an API key**
documented event payload with an inlined disclosure (`facts`). It is a
**stand-in for exposition** — the real archive is served by the API and its
lines may include additional fields. Treat the API as the source of truth.
- `archive_EARNINGS_RELEASE_2026Q3.jsonl.gz` — six **real** archive lines (NVDA,
WMT, HD, CRM, AVGO, ORCL), copied verbatim from the live 2026Q3 file on
2026-09-24. Each carries both disclosure items — the ten facts and the
agent-written **earnings preview** — plus the realized `event_returns`,
`metrics`, and `knowledge_cutoff` the archive adds once an event is scored, so
`notebooks/03_earnings_previews.ipynb` and the preview section of notebook 01
run offline on genuine content. 2026Q3 was unsealed when this was pulled, so
fields may later change upstream; the API remains the source of truth.
- `transcript_sample.json` — a **synthetic** earnings-call transcript for a
fictional company (Northwind Logistics). Real transcripts are licensed and are
not distributed with this repo; this one exists so
Expand Down
Binary file not shown.
63 changes: 23 additions & 40 deletions notebooks/00_api_quickstart.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,18 @@
"id": "0",
"metadata": {},
"source": [
"# 00 — API quickstart\n",
"# 00 \u2014 API quickstart\n",
"\n",
"A guided tour of the endpoints you *read from* while exploring the\n",
"[Explaining Markets](https://explainingmarkets.ai/) competition:\n",
"A guided tour of the endpoints you *read from* while exploring the [Explaining Markets](https://explainingmarkets.ai/) competition:\n",
"\n",
"- **`GET /events`** — the events calendar, shown as a clean table and a chart\n",
"- **`GET /archive`** — a peek at the historical-data manifest\n",
"- **`POST /webhook/test`** — fire a synthetic delivery at your webhook\n",
"- **`GET /health`** — your submission's rolling delivery + prediction counters\n",
"- **`GET /events`** \u2014 the events calendar, shown as a clean table and a chart\n",
"- **`GET /archive`** \u2014 a peek at the historical-data manifest\n",
"- **`POST /webhook/test`** \u2014 fire a synthetic delivery at your webhook\n",
"- **`GET /health`** \u2014 your submission's rolling delivery + prediction counters\n",
"\n",
"Everything runs top-to-bottom. With an API key in `.env` you hit the live API;\n",
"without one, the calendar section falls back to a small bundled sample so you can\n",
"still see the shape of things.\n",
"Everything runs top-to-bottom. With an API key in `.env` you hit the live API; without one, the calendar section falls back to a small bundled sample so you can still see the shape of things.\n",
"\n",
"> **Not covered here:** submitting predictions (`POST /predictions`). That places a\n",
"> real, scored entry and belongs in a deployed webhook handler — see the starter\n",
"> repos, not these examples."
"> **Not covered here:** submitting predictions (`POST /predictions`). That places a real, scored entry and belongs in a deployed webhook handler \u2014 see the starter repos, not these examples."
]
},
{
Expand All @@ -47,7 +42,7 @@
"SAMPLE = REPO / \"data\" / \"sample\"\n",
"\n",
"config = load_config()\n",
"print(\"Mode: \", \"LIVE\" if config.is_live else \"SAMPLE (no EM_API_KEY — using bundled data)\")\n",
"print(\"Mode: \", \"LIVE\" if config.is_live else \"SAMPLE (no EM_API_KEY \u2014 using bundled data)\")\n",
"print(\"API base:\", config.api_base_url)"
]
},
Expand All @@ -56,12 +51,9 @@
"id": "2",
"metadata": {},
"source": [
"## 1. Events calendar — `GET /events`\n",
"## 1. Events calendar \u2014 `GET /events`\n",
"\n",
"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."
"The calendar lists scheduled and realized events. Each event has a type \u2014 an open string set; currently only `EARNINGS_RELEASE` is emitted, though new types may be added over time \u2014 a timestamp, and its focal assets. We flatten it into a tidy, sorted table."
]
},
{
Expand All @@ -88,7 +80,7 @@
"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."
"A stacked daily bar makes the shape of the calendar obvious at a glance \u2014 how many events land each day, split by type."
]
},
{
Expand All @@ -107,10 +99,9 @@
"id": "6",
"metadata": {},
"source": [
"## 2. Historical archive — `GET /archive`\n",
"## 2. Historical archive \u2014 `GET /archive`\n",
"\n",
"The archive is how you get historical events for offline backtesting. Here we just\n",
"glance at the manifest; **notebook 01** downloads, caches, and loads the data."
"The archive is how you get historical events for offline backtesting. Here we just glance at the manifest; **notebook 01** downloads, caches, and loads the data."
]
},
{
Expand All @@ -133,13 +124,9 @@
"id": "8",
"metadata": {},
"source": [
"## 3. Webhook self-test — `POST /webhook/test`\n",
"## 3. Webhook self-test \u2014 `POST /webhook/test`\n",
"\n",
"Fires a synthetic `event_type=TEST` delivery at the webhook URL registered for\n",
"your submission. If it's enqueued you get a `202`; the delivery should reach your\n",
"endpoint within a few seconds and show up in the health counters below. A failure\n",
"here usually means no webhook URL is set, or credentials aren't initialized in the\n",
"portal yet."
"Fires a synthetic `event_type=TEST` delivery at the webhook URL registered for your submission. If it's enqueued you get a `202`; the delivery should reach your endpoint within a few seconds and show up in the health counters below. A failure here usually means no webhook URL is set, or credentials aren't initialized in the portal yet."
]
},
{
Expand All @@ -155,10 +142,10 @@
" try:\n",
" with Client.from_env() as client:\n",
" status = client.send_test_event()\n",
" print(f\"✓ Test event enqueued (HTTP {status}). It should reach your webhook\")\n",
" print(\" within a few seconds — watch the health counters in the next section.\")\n",
" print(f\"\u2713 Test event enqueued (HTTP {status}). It should reach your webhook\")\n",
" print(\" within a few seconds \u2014 watch the health counters in the next section.\")\n",
" except ApiError as exc:\n",
" print(f\"✗ Test event failed (HTTP {exc.status_code}).\")\n",
" print(f\"\u2717 Test event failed (HTTP {exc.status_code}).\")\n",
" print(\" Check that your submission has a webhook URL and initialized credentials.\")\n",
" print(f\" Details: {exc}\")"
]
Expand All @@ -168,11 +155,9 @@
"id": "10",
"metadata": {},
"source": [
"## 4. Submission health — `GET /health`\n",
"## 4. Submission health \u2014 `GET /health`\n",
"\n",
"Rolling 24-hour counters for outbound webhook deliveries and inbound predictions.\n",
"Right after the self-test above, you should see `webhook_n_2xx` (and\n",
"`webhook_last_delivery_at`) tick up — proof the round trip works end to end."
"Rolling 24-hour counters for outbound webhook deliveries and inbound predictions. Right after the self-test above, you should see `webhook_n_2xx` (and `webhook_last_delivery_at`) tick up \u2014 proof the round trip works end to end."
]
},
{
Expand All @@ -197,10 +182,8 @@
"source": [
"## Next steps\n",
"\n",
"- **`01_historical_archive.ipynb`** — download, cache, and load the historical\n",
" archive for offline experiments.\n",
"- Ready to compete? Deploy a webhook handler with one of the starter repos and\n",
" submit predictions from there."
"- **`01_historical_archive.ipynb`** \u2014 download, cache, and load the historical archive for offline experiments.\n",
"- Ready to compete? Deploy a webhook handler with one of the starter repos and submit predictions from there."
]
}
],
Expand Down
Loading
Loading