The Problem

Clients need a thin wrapper around Twelve Data’s REST and WebSocket endpoints to fetch market‑time series, fundamentals and technical indicators. Without a dedicated client they must hand‑craft URLs, parse CSV/JSON, and manage authentication for each request, which leads to duplicated boiler‑plate and error‑prone code.

What This Does

The repository implements a Python client library (twelvedata package) that abstracts the HTTP and WebSocket APIs. Core files are:

  • src/twelvedata/client.py – builds a TDClient object, holds the API key and exposes high‑level methods (time_series, get_stocks_list, etc.).
  • src/twelvedata/endpoints.py – constructs endpoint URLs, validates symbols, and delegates to the HTTP client.
  • src/twelvedata/time_series.py – wraps a time‑series response and provides convenience renderers (as_json, as_csv, as_pandas, as_plotly_figure).
  • src/twelvedata/websocket.py – manages real‑time streams via the websocket-client library.

Supporting modules (utils.py, mixins.py, renders.py, http_client.py, exceptions.py) provide shared helpers, error handling and optional pandas/matplotlib/plotly output.

How It Is Wired

Execution starts when a user creates TDClient(apikey="YOUR_KEY") (class defined in src/twelvedata/client.py). The client stores the key and creates a DefaultHttpClient (in src/twelvedata/http_client.py).

  • Endpoint resolution – Calls execute in src/twelvedata/endpoints.py (line 225) which invokes build_url (135 calls) and get_symbol (96 calls). Both functions rely on purify_symbol from the same file.
  • HTTP request – execute forwards the URL to DefaultHttpClient.get, which performs the outbound network call (4 functions in the repo make external requests).
  • Response handling – The raw JSON is passed to src/twelvedata/time_series.py where as_json, as_csv, as_pandas, as_plotly_figure are defined. These are the most‑used helpers (called 90‑130 times each).
  • WebSocket – TDClient.websocket creates a WebSocket object (src/twelvedata/websocket.py) that opens a socket, registers default logger, symbols and event queue, then yields live messages.

The internal call graph shows 1,263 resolved edges; the hub functions (as_json, as_url, as_csv, as_pandas) have the widest blast radius because they are referenced from 96‑132 places across the code base.

Circular imports involve seven modules (endpoints.py, utils.py, __init__.py, time_series.py, client.py, mixins.py, renders.py). This adds maintenance friction: a change in any of these files risks import‑time failures unless imports are deferred or refactored.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/twelvedata-python
cd twelvedata-python

# Install core package (pandas, matplotlib, plotly, websocket optional)
pip install -e .[pandas,matplotlib,plotly,websocket-client]

# Example usage
python - <<'PY'
from twelvedata import TDClient
client = TDClient(apikey="YOUR_KEY")
ts = client.time_series(symbol="AAPL", interval="1min", outputsize=5)
print(ts.as_json())
PY

Configuration – The only required runtime value is the API key passed to TDClient. No external config files are present.

Running tests – pytest tests/test_client.py executes the two test files; they rely on a mocked HTTP client (_fake_resp, _fake_json_resp).

Real‑World Use

A trading platform can embed the client to pull end‑of‑day OHLC data for a watchlist, convert it to a pandas DataFrame (as_pandas), and feed it into a back‑testing engine. Real‑time price updates are received via client.websocket() and routed into an in‑memory queue for low‑latency order‑book reconstruction.

Code Health & Issues

  • High – Oversized files: src/twelvedata/endpoints.py, src/twelvedata/time_series.py, tests/test_client.py each exceed 8 k lines, making local changes high‑risk.
  • High – Import cycles: 7 modules (e.g., endpoints.py, utils.py, __init__.py) form circular dependencies, complicating refactoring.
  • High – Deep nesting: src/twelvedata/renders.py and src/twelvedata/time_series.py contain nesting depth of 9, reducing readability.
  • High – Duplicated logic: Repeated 6‑line blocks appear in both endpoints.py and time_series.py.
  • Medium – Broad exception handling: src/twelvedata/__init__.py catches generic Exception, potentially hiding errors.
  • Medium – High branching density: docs/conf.py has 28 branches in 70 lines, making the Sphinx config harder to maintain.
  • Medium – Large binary asset: asset/chart-example.gif (12.3 MB) inflates repository size; should be moved to Git LFS or external storage.
  • Low – Missing lockfile: Dependencies are declared in Pipfile without a lockfile, leading to non‑reproducible builds.

The Bottom Line

The library delivers a functional wrapper around Twelve Data’s API with convenient output formats, but the codebase suffers from oversized, tightly coupled modules and circular imports that hamper maintainability. It is suitable for teams that need quick integration and are prepared to refactor the core files for long‑term stability.