Skip to main content

pyIPO

A production-grade Python library for fetching and parsing IPO data from the Nasdaq calendar API. Designed for serverless contexts (AWS Lambda) and programmatic pipelines — strictly typed, stateless, and zero-dependency beyond curl_cffi.


Table of Contents


Features

  • Strict types — all deals returned as frozen IPODeal dataclass instances; no raw dicts leak through the public surface
  • 4 deal lifecycle states — FILING, UPCOMING, PRICED, WITHDRAWN
  • Chrome TLS impersonation — uses curl_cffi to bypass Akamai/Cloudflare WAF filtering applied to standard HTTP clients
  • Serverless-safe — 10-second request timeout ceiling, stateless client, no global connections
  • Rolling window queries — fetch across N months in one call, with automatic deduplication
  • Resilient parsing — null-flag normalisation ("N/A", "TBD", "" → None), price-range splitting, shorthand share counts ("1.5M" → 1_500_000)

Installation

pip install -e .

Requires Python ≥ 3.10. The only runtime dependency is curl_cffi ≥ 0.6.


Quick Start

from pyipo import NasdaqClient, DealState

client = NasdaqClient()

# All deals across a rolling 3-month window (default)
deals = client.get_ipos()

# Filter by state
upcoming = [d for d in deals if d.deal_state == DealState.UPCOMING]
priced   = [d for d in deals if d.deal_state == DealState.PRICED]

for deal in upcoming:
    print(f"{deal.company_name} ({deal.symbol}) — {deal.price_low}–{deal.price_high} — {deal.expected_date}")

Single-month query:

deals = client.get_calendar("2024-06")

Public API

NasdaqClient

class NasdaqClient:
    def get_ipos(self, lookback_months: int = 3) -> list[IPODeal]: ...
    def get_calendar(self, month: str) -> list[IPODeal]: ...

get_ipos(lookback_months=3)

Queries the rolling window of lookback_months calendar months (current month + N−1 prior months). Months are fetched sequentially with a 1-second polite throttle between requests. Deals with the same (company_name, deal_state) appearing in multiple months are deduplicated — only the first occurrence is kept.

Parameter Type Default Description
lookback_months int 3 Number of months to look back from today

Returns: list[IPODeal]
Raises: NasdaqAPIError on network or HTTP errors

get_calendar(month)

Fetches all IPO deals for a single specific month.

Parameter Type Description
month str Month in 'YYYY-MM' format, e.g. "2024-06"

Returns: list[IPODeal]
Raises: NasdaqAPIError on network or HTTP errors


IPODeal

Immutable (frozen=True) dataclass representing a single IPO deal.

from pyipo import IPODeal
Field Type States Description
company_name str all Legal company name
deal_state DealState all Lifecycle stage
symbol Optional[str] all Proposed ticker symbol
market Optional[str] UPCOMING, PRICED Exchange (NASDAQ, NYSE, …)
offer_amount Optional[float] all Total dollar value of shares offered
shares_outstanding Optional[int] UPCOMING, PRICED Number of shares offered
price_low Optional[float] UPCOMING Lower bound of proposed price range
price_high Optional[float] UPCOMING Upper bound of proposed price range
actual_price Optional[float] PRICED Final offer price
expected_date Optional[date] UPCOMING Expected pricing date
filing_date Optional[date] FILING, PRICED Date of S-1 filing or pricing
withdrawn_date Optional[date] WITHDRAWN Date the deal was pulled

None values mean the data was absent or a null-flag ("N/A", "TBD", etc.) in the source.


DealState

from pyipo import DealState

DealState.FILING    # "filing"   — S-1 filed, no firm date yet
DealState.UPCOMING  # "upcoming" — On the calendar, roadshow active
DealState.PRICED    # "priced"   — Final price set, ready to trade
DealState.WITHDRAWN # "withdrawn"— Deal pulled / cancelled

NasdaqAPIError

from pyipo import NasdaqAPIError

try:
    deals = client.get_ipos()
except NasdaqAPIError as e:
    print(e)               # human-readable message
    print(e.status_code)   # int HTTP status, or None for connection errors

Raised on:

  • HTTP responses with status ≠ 200
  • Connection timeouts (hard ceiling: 10 seconds)
  • Any network-layer failure (DNS, TLS, reset)

Data Model

All four deal states are sourced from a single Nasdaq endpoint:

GET https://api.nasdaq.com/api/ipo/calendar?date=YYYY-MM

The response contains four top-level buckets which map directly to DealState:

Bucket Response key DealState
Early filings data.filed.rows FILING
Active roadshows data.upcoming.upcomingTable.rows UPCOMING
Priced deals data.priced.rows PRICED
Cancelled deals data.withdrawn.rows WITHDRAWN

Error Handling

from pyipo import NasdaqClient, NasdaqAPIError

client = NasdaqClient()

try:
    deals = client.get_calendar("2024-06")
except NasdaqAPIError as e:
    if e.status_code == 429:
        # Rate-limited — back off and retry
        ...
    elif e.status_code is None:
        # Connection failure (timeout, DNS, TLS)
        ...
    else:
        # Unexpected HTTP error
        raise

Development

# Clone and install with dev dependencies
pip install -e ".[dev]"

# Run tests (no network calls)
pytest tests/ -v -p no:typeguard

# Run a single test file
pytest tests/test_parsers.py -v -p no:typeguard

Note: The -p no:typeguard flag works around a broken typeguard pytest plugin that may be present in some environments. It has no effect if typeguard is not installed.

Project Structure

pyIPO/
├── src/
│   └── pyipo/
│       ├── __init__.py     # Public exports
│       ├── enums.py        # DealState enum
│       ├── models.py       # IPODeal dataclass
│       ├── client.py       # HTTP transport (curl_cffi)
│       ├── parsers.py      # JSON → IPODeal conversion
│       └── exceptions.py   # NasdaqAPIError
├── tests/
│   ├── conftest.py         # Frozen JSON fixtures
│   ├── test_parsers.py     # Parser unit tests (36 tests)
│   └── test_client.py      # Client integration tests (15 tests)
├── pyproject.toml
└── ipo.py                  # Original standalone script (kept for reference)

Architecture

NasdaqClient
    │
    ├── get_ipos(lookback_months)       ← rolling window, dedup
    └── get_calendar(month)             ← single month
            │
            └── _fetch_month(month)     ← curl_cffi GET, raises NasdaqAPIError
                    │
                    └── _parse_all(data)
                            ├── parse_filings(rows)   → list[IPODeal(FILING)]
                            ├── parse_upcoming(rows)  → list[IPODeal(UPCOMING)]
                            ├── parse_priced(rows)    → list[IPODeal(PRICED)]
                            └── parse_withdrawn(rows) → list[IPODeal(WITHDRAWN)]

Parsing helpers in parsers.py handle all edge cases internally — callers always receive clean, typed values or None; raw strings never escape the parser layer.

Release files for pyipo 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyipo 0.2.0
File Size Uploaded
pyipo-0.2.0.tar.gz 13.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyipo 0.2.0
File Interpreter ABI Platform
pyipo-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.9 kB

Release files / pyipo-0.2.0.tar.gz

Download URL pyipo-0.2.0.tar.gz
Size 13.7 kB
Tags Source
SHA-256 checksum
How to use checksums
505fd005fd4b342bef4bf4137e933fb10eddca5c8a07e74fc61286f40329c233
BLAKE2b-256 checksum
How to use checksums
b9db9f400ac1d2fa54f9f21cedb0fe69d058732a8496ffb98b533333ef036c5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.8

Release files / pyipo-0.2.0-py3-none-any.whl

Download URL pyipo-0.2.0-py3-none-any.whl
Size 18.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
80a0bb592abb3f7a07a44589a69877df873fc71703889606b2cabbb76b6029bf
BLAKE2b-256 checksum
How to use checksums
065e293c0c6a4b553d34354ea4b272c5fe8d0bffa4e0f5437d66b68fba54dbfc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.8

Release history Release notifications | RSS feed

0.2.2

2 release files

0.2.1

2 release files

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page