Metadata-Version: 2.4
Name: david-data
Version: 0.1.1
Summary: Official Python client for the David Data financial-data API (api.davidhf.com).
Project-URL: Homepage, https://davidhf.com
Project-URL: Documentation, https://api.davidhf.com/docs
Project-URL: Source, https://github.com/davidhf/david-data-python
Author-email: David Data <investors@davidhf.com>
License: MIT
License-File: LICENSE
Keywords: api,david-data,finance,fundamentals,market-data,stocks
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: pandas>=1.5; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: pandas
Requires-Dist: pandas>=1.5; extra == 'pandas'
Description-Content-Type: text/markdown

# David Data — Python SDK

Official Python client for the [David Data](https://davidhf.com) financial-data
API (`https://api.davidhf.com`). One consistent interface for **real** market
data and **synthetic** scenarios — prices, fundamentals, filings, news,
earnings, analyst & insider data, 13F holdings, and macro series.

```bash
pip install david-data           # core (httpx only)
pip install david-data[pandas]   # + DataFrame helpers
```

## Quickstart

Every data call is keyed by a **`scenario_id`** — a synthetic world. Pick one,
then pull data from it.

```python
from david_data import DavidData

dd = DavidData(api_key="sk_...")        # or set DAVID_DATA_API_KEY

# 1. Find a scenario
scenario = dd.scenarios.list(limit=1)[0]
sid = scenario["id"]
print(scenario["name"])

# 2. Pull data from it
bars = dd.prices.get("AAPL", scenario_id=sid, start_date="2024-01-01")
income = dd.financials.income_statements("AAPL", scenario_id=sid, period="quarterly", limit=5)
news = dd.news.list(ticker="AAPL", scenario_id=sid, limit=10)

print(bars[0])      # {'ticker': 'AAPL', 'open': ..., 'close': ..., 'volume': ...}
```

Repeating `scenario_id=` on every call gets old — set it once on the client and
omit it thereafter:

```python
dd = DavidData(api_key="sk_...", scenario_id=sid)
dd.prices.get("AAPL")                    # uses the client default
dd.prices.get("AAPL", scenario_id="other-world")   # override per call
```

Calling a data endpoint with no `scenario_id` (and no client default) raises a
clear error instead of guessing.

Set the key once via the environment and you can skip the argument entirely:

```bash
export DAVID_DATA_API_KEY="sk_..."
```

```python
from david_data import DavidData
dd = DavidData()
```

## Returns

Methods return parsed JSON — a `list` of record dicts for collection endpoints,
a `dict` for single-object endpoints — exactly like the underlying API, with the
envelope unwrapped for you (`dd.prices.get(...)` gives you the list of bars
directly). Convert any result to a DataFrame:

```python
from david_data import to_df
df = to_df(dd.prices.get("AAPL", start_date="2024-01-01"))
```

## Scenarios

A scenario is a self-contained synthetic world with its own universe of
companies, prices, fundamentals, filings, and events. David builds and curates
the library; browse it and pull data from any scenario:

```python
for s in dd.scenarios.list(limit=10):
    print(s["id"], "-", s["name"])

# Inspect one
dd.scenarios.get(sid)
dd.scenarios.validation(sid)        # data-integrity report
```

## What you can pull

| Group | Examples |
|-------|----------|
| `dd.prices` | `get`, `snapshot`, `market_snapshot`, `tickers` |
| `dd.financials` | `income_statements`, `balance_sheets`, `cash_flow_statements`, `metrics`, `segments`, `as_reported`, `kpi_metrics`, `screener`, `line_items` |
| `dd.company` | `list`, `facts`, `tickers`, `ciks` |
| `dd.news` / `dd.filings` | `list`, `get` / `list`, `items`, `types` |
| `dd.earnings` / `dd.analyst` | `list`, `calendar` / `estimates`, `notes` |
| `dd.insiders` / `dd.institutional` | `trades`, `transactions` / `holdings`, `investors` |
| `dd.index_funds` / `dd.corporate_actions` | `list` |
| `dd.macro` | `series`, `interest_rates`, `banks` |
| `dd.events` | `timeline` |
| `dd.scenarios` | `list`, `get`, `validation` |
| `dd.metadata` | `sectors`, `scenario_themes`, … |

Dates accept either ISO strings (`"2024-01-01"`) or `datetime.date` objects.

## Errors & retries

All exceptions subclass `DavidDataError`. HTTP failures map to specific types:

```python
from david_data import DavidData, NotFoundError, RateLimitError

dd = DavidData()
try:
    dd.prices.get("AAPL")
except RateLimitError as e:
    print("slow down; retry after", e.retry_after)
except NotFoundError:
    print("no such ticker / scenario")
```

The client automatically retries `429` and transient `5xx` responses with
exponential backoff (honouring `Retry-After`); tune with `max_retries=`.

## Escape hatch

Any endpoint not yet wrapped is reachable directly:

```python
dd.get("/metadata/institutional-readiness")
dd.post("/financials/search/screener", json={"scenario_id": "real", "filters": [...]})
```

## Anything else

- `with DavidData() as dd: ...` closes the connection pool on exit.
- Bring your own `httpx.Client` via `http_client=` for proxies/custom transport.
- Full endpoint reference: <https://api.davidhf.com/docs>

## License

MIT
