Python
The chartdeck package - client, namespaces, pagination, retries, errors, the stream helper and webhook verification. Standard library only.
pip install chartdeckPython 3.9 or newer; no third-party dependencies (REST, the stream and webhook checks use the standard library).
#Client
from chartdeck import Client
client = Client() # the key from CHARTDECK_API_KEY
client = Client(api_key="cdk_...", timeout=30, max_retries=3)Methods are grouped like the API: client.account, client.calendar, client.news, client.strata, client.market, client.flow, client.footprint, client.screener, client.twap, client.indices, client.webhooks. Every operation's reference page names its method. Path parameters are positional, query parameters keywords (from is from_), and time parameters accept datetime objects.
r = client.market.candles(venue="binance", symbol="BTCUSDT", res="60", limit=500)
r.data # the bars
r.meta # attribution, next_cursor, weight, terms
r.rate_limit # limit, remaining, reset, quota_limit, quota_remaining, weight
r.request_idclient.call("getCandles", venue=..., ...) calls any operation by its operationId.
#Pagination
Paginated operations have an iter_ twin that follows next_cursor:
for bar in client.market.iter_candles(venue="binance", symbol="BTCUSDT", res="60", max_items=5000):
...#Retries and errors
The client retries 429 rate_limited, 502, 503, 504 and network errors with backoff and jitter, honouring Retry-After (max_retries, default 3). It never retries the monthly quota or other 4xx. Every write carries an Idempotency-Key (generated, or yours with idempotency_key=), so a retried write acts once.
Errors are ChartDeckError subclasses with .status, .code, .message, .request_id, .details: AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, InvalidRequestError, RateLimitError (.retry_after, .quota_exceeded), ServiceUnavailableError, APIConnectionError.
#Stream
with client.stream(["candles:binance:BTCUSDT:1", "calendar:US"], filters={"calendar": {"min_importance": 3}}) as s:
for frame in s:
print(frame["ch"], frame["type"], frame["data"])The helper sends the key in the upgrade header, answers pings, reconnects with backoff (at once after a restart, never after a refused key), re-subscribes, resumes event channels from the last event_id and drops replays it already delivered. Control messages (hello, ack, gap, notice) go to on_control=.
#Webhooks
from chartdeck import construct_event, verify, SignatureVerificationError
ok = verify(raw_body, signature_header, secret) # True / False
event = construct_event(raw_body, signature_header, secret) # parsed event, or raises