fix(dhan): symbol parsing + recompute fees for unsettled today rows#4
Merged
SwathiMystery merged 1 commit intomainfrom Apr 20, 2026
Merged
fix(dhan): symbol parsing + recompute fees for unsettled today rows#4SwathiMystery merged 1 commit intomainfrom
SwathiMystery merged 1 commit intomainfrom
Conversation
Running against a live account exposed three more shape quirks in
Dhan v2's /trades (today) endpoint vs /trades/{from}/{to}/{page} (history):
1. Hyphenated tradingSymbol on today's rows
'NIFTY-Apr2026-24300-PE' was resolving underlying to 'NIFTY-Apr'
because the parser only stopped at digits. Now stops at digit,
hyphen, or whitespace — handles all three formats observed:
concat: NIFTY24APR2624300PE
space-sep: NIFTY 21 APR 24300 PUT
hyphenated: NIFTY-Apr2026-24300-PE
2. drvOptionType='NA' on today's rows
Today's /trades leaves drvOptionType='NA' even when the tradingSymbol
clearly ends '-PE' / '-CE'. Added _option_type_from_symbol fallback
that reads the suffix.
3. `instrument` field missing entirely on today's rows
Every row defaulted to InstrumentType.EQ, which blocked the new
option_type fallback and the fee recompute below. Added
_infer_instrument_type: explicit field → option markers → FNO
segment → EQ.
4. Fees absent on today's rows (not a mapping bug, real data gap)
Today's /trades omits fee fields entirely — they settle at EOD.
Added khata/adapters/dhan/fees.py with Indian F&O options fee
formula (brokerage flat ₹20 or 0.03% whichever lower, STT 0.0625%
on SELL, NSE exch 0.03503%, SEBI ₹10/crore, stamp 0.003% on BUY,
IPFT 0.0005%, GST 18%). Exposed via DhanAdapter.charges_for, called
from fetch_trades when broker-reported fees total zero.
Tests: 7 new cases (22 total, all green). Fixtures use synthetic IDs
only. Verified against live account: today's 04-20 trade went from
fees=₹0.00 to ₹715.32 and underlying 'NIFTY-Apr' to 'NIFTY'.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Running the first sync against a live Dhan account yesterday surfaced four more shape differences between today's
/tradesand history/trades/{from}/{to}/{page}endpoints. This PR fixes all of them.Why
Observed on live data (04-20 trade):
tradingSymbolNIFTY-Apr2026-24300-PEcustomSymbolnullNIFTY 21 APR 24300 PUTinstrumentOPTIDXdrvOptionType"NA""PUT"Left unfixed, today's trades were being stored with
underlying="NIFTY-Apr",instrument_type=EQ,option_type=None, andfees=0. Round-trip grouping was broken (contracts inflated by 1) and net P&L was missing ~₹700 per scalp.Changes
mapper.py_underlying_from_symbol: stops at digit, hyphen, or whitespace — covers all three symbol formats (concat / space-sep / hyphenated)._option_type_from_symbol: new helper, parses-CE/-PE/CALL/PUTsuffix off the symbol._infer_instrument_type: new helper. Priority: explicitinstrument→ option markers → FNO segment → EQ._OPTION_TYPE: add"NA"→Noneso the map lookup gates cleanly into the fallback.fees.py(new): Indian F&O options fee formula — brokerage (Dhan ₹20 flat or 0.03%), STT (0.0625% SELL only), NSE txn (0.03503%), SEBI (₹10/cr), stamp (0.003% BUY only), IPFT, GST 18%. Rates documented inline with source notes.adapter.pycharges_for(execution)→ dispatches tofees.compute_fees. ReturnsNonefor non-options (futures/equity formulas differ, out of scope here).fetch_tradesrecomputes fees whenever the broker returns a zero-fee row.trades_today_unsettled.jsonmirrors today's no-fees/NA-option shape. 7 new test cases covering each fix and the happy-path non-regression.Verification
Against a live account:
Contracts count went 17 → 16 as the 04-20 trade now correctly groups with NIFTY underlying.
Checklist
uv run ruff check khata testscleanuv run ruff format khata testsappliedfees.pyTEST_*) — no real account data