Skip to main content
david-data is the official Python client for the David API. It wraps every endpoint, handles auth and retries, and unwraps responses into plain Python objects.

Install

pip install david-data            # core
pip install david-data[pandas]    # + DataFrame helpers
Requires Python 3.9+.

Authenticate

Pass your key directly, or set the DAVID_DATA_API_KEY environment variable and omit it.
from david_data import DavidData

dd = DavidData(api_key="YOUR_API_KEY")
# or: export DAVID_DATA_API_KEY=YOUR_API_KEY  ->  dd = DavidData()

Quickstart

Every data call is keyed by a scenario_id. Pick a scenario from the library, then pull from it.
# 1. Pick a scenario
scenario = dd.scenarios.list(limit=1)[0]
sid = scenario["id"]

# 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': ...}
Methods return parsed JSON with the response envelope removed: a list of records for collections, a dict for single objects.

Set a default scenario

Repeating scenario_id= everywhere gets old. Set it once on the client and omit it; override per call when needed.
dd = DavidData(scenario_id=sid)
dd.prices.get("AAPL")                          # uses the default
dd.prices.get("AAPL", scenario_id="other")     # override
Calling a data endpoint with no scenario_id (and no default) raises a clear error instead of guessing.

What you can pull

ResourceMethods
dd.pricesget, snapshot, market_snapshot, tickers
dd.financialsincome_statements, balance_sheets, cash_flow_statements, all_statements, metrics, segments, as_reported, kpi_metrics, screener, line_items
dd.companylist, facts, tickers, ciks
dd.news / dd.filingslist, get / list, items, types
dd.earnings / dd.analystlist, calendar / estimates, notes
dd.insiders / dd.institutionaltrades, transactions / holdings, investors
dd.index_funds / dd.corporate_actionslist
dd.macroseries, interest_rates, banks
dd.eventstimeline
dd.scenarioslist, get, validation
Dates accept ISO strings ("2024-01-01") or datetime.date objects.

DataFrames

Convert any result to a pandas DataFrame with to_df (needs the [pandas] extra):
from david_data import to_df

df = to_df(dd.prices.get("AAPL", scenario_id=sid, start_date="2024-01-01"))

Errors & retries

Every exception subclasses DavidDataError. The client automatically retries 429 and transient 5xx responses with exponential backoff (honoring Retry-After); tune with max_retries=.
from david_data import DavidData, NotFoundError, RateLimitError

dd = DavidData()
try:
    dd.prices.get("AAPL", scenario_id=sid)
except RateLimitError as e:
    print("slow down; retry after", e.retry_after)
except NotFoundError:
    print("no such ticker or scenario")
ExceptionRaised on
AuthenticationError401 invalid or missing key
PermissionDeniedError403 not allowed
NotFoundError404 unknown scenario, ticker, or id
BadRequestError400 invalid parameters
RateLimitError429 rate limit exceeded (.retry_after)
ServerError5xx server error
APIConnectionError / APITimeoutErrornetwork failure / timeout

Escape hatch

Any endpoint not yet wrapped is reachable directly:
dd.get("/health")
dd.post("/financials/search/screener", json={"scenario_id": sid, "filters": {"gross_margin": {"gte": 0.4}}})

Client options

OptionDefaultDescription
api_keyDAVID_DATA_API_KEYYour API key.
scenario_idnoneDefault scenario for every data call.
base_urlhttps://api.davidhf.comAPI root (or DAVID_DATA_BASE_URL).
timeout30.0Per-request timeout in seconds.
max_retries3Retries for 429 and transient 5xx.
with DavidData() as dd:   # closes the connection pool on exit
    dd.prices.get("AAPL", scenario_id=sid)