Skip to content

fix(dhan): paginated statement API + history row shape#3

Merged
SwathiMystery merged 1 commit intomainfrom
fix/dhan-statement-api
Apr 20, 2026
Merged

fix(dhan): paginated statement API + history row shape#3
SwathiMystery merged 1 commit intomainfrom
fix/dhan-statement-api

Conversation

@SwathiMystery
Copy link
Copy Markdown
Contributor

What

Fix the Dhan adapter to match the v2 API's actual behaviour. Historical-trades endpoint is GET /trades/{from}/{to}/{page} (page is a required 3rd path segment), not GET /trades/{from}/{to} as originally guessed. Also fix several smaller shape mismatches discovered during the first real sync.

Why

The first live khata sync --broker dhan call 4xx'd on the Statement API. Probing against a live account revealed the true endpoint shape plus three related quirks that would have silently corrupted data on ingest.

Changes

  • client.py: get_trades_range now takes a page argument and maps to /trades/{from}/{to}/{page}.
  • adapter.py: fetch_trades paginates each date chunk until the response is empty (safety-bounded at 100 pages).
  • mapper.py:
    • Falls back to orderId when exchangeTradeId is "0" (history rows are aggregated per-order-per-day). Without this, UNIQUE(broker, broker_trade_id) would collapse every history row to a single insert.
    • Parses both "YYYY-MM-DD HH:MM:SS" (today's /trades) and "YYYY-MM-DDTHH:MM:SS" (history pages).
    • Handles literal "NA" in createTime / updateTime without crashing.
    • Strips trailing whitespace in underlying extraction so "NIFTY 21 APR 24300 PUT""NIFTY", not "NIFTY ".
  • tests/fixtures/dhan/ + tests/test_dhan_mapper.py: 10 regression tests covering every fix above. Fixtures use synthetic IDs only (TEST_CLIENT_*, TEST_ORDER_*) — no real account data.

Verification

  • 15/15 tests green locally (5 existing round-trip + 10 new mapper).
  • ruff check + ruff format --check clean.
  • Verified end-to-end against a live Dhan account: 103 executions over 30 days, 18 round-trip trades reconstructed.

Checklist

  • Tests added (10 new cases, all green locally)
  • uv run ruff check khata tests clean
  • uv run ruff format khata tests applied
  • Docs updated — public API unchanged; adapter internals only
  • Fixture file + mapper tests included
  • No schema change

Screenshots / output

$ uv run khata sync --broker dhan --since-days 30
→ authenticating with dhan…
→ fetching executions since 2026-03-21 …
  got 103 executions
  inserted 103 new rows
→ rebuilding round-trip trades…
  ✓ trades=18 (open=0) across 17 contracts

Discovered while running the first real sync: the Dhan v2 Statement API
doesn't match what I originally guessed. Actual shape:

  GET /trades/{from}/{to}/{page}

- Page number is a REQUIRED third path segment (not optional).
- Page size is ~20, newest-first. Paginate until empty list.
- History rows are aggregated per-order-per-day, so exchangeTradeId='0'.
  Falling back to orderId so UNIQUE(broker, broker_trade_id) holds.
- Timestamps come in two formats: 'YYYY-MM-DD HH:MM:SS' (today's /trades)
  and 'YYYY-MM-DDTHH:MM:SS' (history pages). Parser handles both.
- createTime/updateTime can be literal 'NA' on history rows.
- customSymbol on history has spaces ('NIFTY 21 APR 24300 PUT'); underlying
  extractor strips trailing whitespace.

Adds tests/fixtures/dhan/{trades_today,trades_history_page0}.json and
tests/test_dhan_mapper.py (10 cases) covering every fix above. Fixtures
use synthetic IDs only; no real account data.

Verified against a live account: 103 executions over 30 days, 18 round-trip
trades reconstructed cleanly.
@SwathiMystery SwathiMystery force-pushed the fix/dhan-statement-api branch from 6a1571c to ee660a9 Compare April 20, 2026 18:53
@SwathiMystery SwathiMystery merged commit 8c287f0 into main Apr 20, 2026
7 checks passed
@SwathiMystery SwathiMystery deleted the fix/dhan-statement-api branch April 20, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant