# Catalyst Calendar — earnings, IPO & lockup dates (`brandon_nava/catalyst-calendar`) Actor

Provenance-stamped US-equity catalyst calendar for AI agents: upcoming earnings, IPOs, and computed lockup expiries. Every row cites its primary source.

- **URL**: https://apify.com/brandon\_nava/catalyst-calendar.md
- **Developed by:** [Brandon Nava](https://apify.com/brandon_nava) (community)
- **Categories:** AI
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 catalyst events

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Catalyst Calendar — earnings, IPO & lockup-expiry dates with provenance

A US-equity **catalyst calendar built for AI agents and quant workflows**:
upcoming earnings dates, recent IPOs, and computed **lockup-expiry dates —
parsed from the actual SEC prospectus clause**, not assumed. Every row cites
its primary source and carries a deterministic version stamp.

No API keys to manage: run it on Apify, pay per event returned. Works with
agent stacks out of the box (MCP tool discovery, x402 agentic payments via
Apify's integration).

### What one event looks like

```json
{
  "symbol": "SGP",
  "event_type": "lockup_expiry",
  "event_date": "2026-08-06",
  "status": "confirmed",
  "detail": {
    "ipo_date": "2026-02-06",
    "lockup_days": 181,
    "lockup_basis": "parsed",
    "evidence": "…beginning 181 days after the date of this prospectus, subject to the terms of the lock-up and market standoff agreements…",
    "spac": false
  },
  "provenance": {
    "sources": ["https://www.sec.gov/Archives/edgar/data/1778922/000162828026006068/spyglass-424b4.htm"],
    "first_seen": "2026-07-09T20:02:11+00:00",
    "last_changed": "2026-07-09T20:02:11+00:00",
    "last_verified": "2026-07-13T10:00:04+00:00",
    "model_version": "catalyst-v0.4.0-p4",
    "inputs_hash": "9c1a4f0e2b7d6a31"
  }
}
```

Yes — that lockup is **181 days, not 180**, because that's what the filing
says. Blind 180-day assumptions ship wrong dates; this Actor reads the clause
and shows you the evidence.

### Why this calendar

- **Provenance on every row** — the SEC filing URL, seen/verified timestamps,
  model version, and a deterministic input hash. Auditable by machine.
- **Parsed lockup terms** — expiry computed from the prospectus lock-up
  clause (with the quoted evidence). Unparseable clauses fall back to 180
  days and are *labeled* `estimated` / `assumed` — never passed off as fact.
- **Honest earnings estimates** — next expected earnings date from each
  company's own 8-K reporting cadence, always `status: estimated`, with the
  sample size and interval spread included so you can judge the confidence.
- **Measured accuracy, published** — hold-out backtest on 30 large caps:
  **median error 2 days, 90% within ±7 days, 12/30 exact**. Lockup terms:
  **75% parsed directly from prospectuses.** These numbers will be
  re-published monthly.
- **SPACs tagged** — blank-check IPOs are flagged (`detail.spac`) so you can
  filter them.
- **Primary sources only** — SEC EDGAR (public domain). No aggregator
  scraping, no licensing time-bombs in your pipeline.

### Event types

| type | what | status |
|---|---|---|
| `earnings` | Next expected earnings date per symbol (8-K item-2.02 cadence model) | `estimated` |
| `ipo` | IPO pricing events from 424(b)(4) filings, follow-on offerings excluded | `confirmed` |
| `lockup_expiry` | IPO date + parsed lock-up term | `confirmed` when parsed, `estimated` when assumed |

### Input

| field | default | notes |
|---|---|---|
| `symbols` | *(empty)* | Empty = full universe: ~90 US large caps ∪ all recent IPOs. Pass tickers to target. |
| `event_types` | all | Any of `earnings`, `ipo`, `lockup_expiry` |
| `days_ahead` | 90 | Horizon for upcoming events (past IPOs are kept — they anchor lockup rows) |
| `include_estimated` | true | `false` = confirmed rows only |
| `next_event_only` | false | One nearest event per symbol, with `days_out` — built for position-holding agents |
| `changed_since` | — | **Delta mode** (ISO timestamp): only events that are new, date-moved, or status-changed since then. Backed by a persistent event history — `provenance.first_seen` / `last_changed` are real across runs. Poll daily, pay only for what moved |

### Typical costs (pay per event, $0.002/event)

- Full default pull (~550 events): **≈ $1.15**
- One symbol, `next_event_only`: **≈ $0.01**
- Targeted watchlist of 20 symbols: **≈ $0.05–0.15**

### Limitations (read this)

- Earnings dates are **estimates** until IR-confirmed sources ship (roadmap):
  cadence models miss when companies move reporting weeks (worst backtest
  case: 16 days). The `interval_spread_days` field tells you how regular each
  company's cadence is.
- US-listed equities only. Foreign private issuers (6-K filers) and ETFs get
  no earnings estimates. Recent IPOs need 3+ reported quarters first.
- \~Half of recent 424(b)(4) IPOs are SPACs — filter with `detail.spac`.
- Not investment advice. This is calendar structure — dates and provenance —
  not signals or recommendations.

### Roadmap

Lockup **early-release detection** (8-K/S-3 waiver monitoring), IR-confirmed
earnings dates, macro release calendar, monthly accuracy self-reports
published in this README (the predicted-vs-actual scoring is already
accumulating on every run).

***

### Development

Monorepo: `actors/catalyst-calendar/` in `agent-market-api`. `src/events.py`,
`src/earnings.py`, `src/lockup.py` are pure compute (no SDK, no I/O);
`src/sources/edgar.py` is the only network layer (throttled ≤4 req/s, bounded
5xx retry, fail-open per chunk). Requires `EDGAR_USER_AGENT` env var
(descriptive UA with contact email — SEC fair-access policy).

```bash
pytest                                        # unit tests, no network
python -m scripts.validate_earnings_cadence   # accuracy backtest (network)
apify run --purge                             # local run
```

# Actor input Schema

## `symbols` (type: `array`):

Ticker symbols to include. Empty = full covered universe (~90 large caps + all recent IPOs).

## `event_types` (type: `array`):

Any of: earnings, ipo, lockup\_expiry. Empty = all types. Tip: clear both this and Symbols for the full calendar (takes ~10 min).

## `days_ahead` (type: `integer`):

Horizon in days for upcoming events.

## `include_estimated` (type: `boolean`):

Include events whose date is estimated (not yet confirmed by a primary source). Estimated rows are always labeled.

## `changed_since` (type: `string`):

ISO-8601 timestamp. Return only events that are new, moved, or status-changed since this time. Designed for daily polling.

## `next_event_only` (type: `boolean`):

Return only the nearest upcoming event per symbol, with days\_out.

## Actor input object example

```json
{
  "symbols": [
    "AAPL",
    "MSFT",
    "NVDA",
    "AMZN",
    "META",
    "TSLA"
  ],
  "event_types": [
    "earnings"
  ],
  "days_ahead": 90,
  "include_estimated": true,
  "next_event_only": false
}
```

# Actor output Schema

## `events` (type: `string`):

All catalyst event rows returned by this run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "symbols": [
        "AAPL",
        "MSFT",
        "NVDA",
        "AMZN",
        "META",
        "TSLA"
    ],
    "event_types": [
        "earnings"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("brandon_nava/catalyst-calendar").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "symbols": [
        "AAPL",
        "MSFT",
        "NVDA",
        "AMZN",
        "META",
        "TSLA",
    ],
    "event_types": ["earnings"],
}

# Run the Actor and wait for it to finish
run = client.actor("brandon_nava/catalyst-calendar").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "symbols": [
    "AAPL",
    "MSFT",
    "NVDA",
    "AMZN",
    "META",
    "TSLA"
  ],
  "event_types": [
    "earnings"
  ]
}' |
apify call brandon_nava/catalyst-calendar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,brandon_nava/catalyst-calendar"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/dMFPOAhoJareSknvM/builds/LYVr9S27NXpH7sGqK/openapi.json
