Skip to content

fix: resolve exchange from trading symbol in doOrder (SENSEX AB4046) - #104

Merged
kunalrbhatia merged 5 commits into
developmentfrom
fix/sensex-order-exchange
Aug 20, 2026
Merged

fix: resolve exchange from trading symbol in doOrder (SENSEX AB4046)#104
kunalrbhatia merged 5 commits into
developmentfrom
fix/sensex-order-exchange

Conversation

@kunalrbhatia

Copy link
Copy Markdown
Owner

Problem

SENSEX orders were failing with AB4046 Symbol token not found in scrip master cache for the given exchange on the first SENSEX expiry day (20-Aug-2026). The algo identified the right ATM/hedge strikes, fetched correct LTPs (BFO), but every placeOrder was rejected.

Root cause

doOrder (src/helpers/apiService/orders.ts) defaulted to exchange = 'NFO' and most call sites (doOrderByStrike, shortStraddle, closeTrade, placeStopLossOrder) never passed exchange. NIFTY trades on NFO so the bug was invisible; SENSEX trades on BFO so every order went to the wrong exchange segment → AB4046.

Fix

  • doOrder now resolves the exchange from the trading symbol when not explicitly provided: exchange || getExchangeForIndex(getIndexFromSymbol(tradingsymbol)) → NIFTY→NFO, SENSEX→BFO
  • Removed the hardcoded exchange: 'NFO' in placeStoplossForAllSells
  • All 3 internal usages of exchange in doOrder now use resolvedExchange

Verification (live, 20-Aug 10:50 IST)

After the hotfix + dist rebuild:

  • ✅ BUY hedge CE SENSEX2682078900CE (100 qty) → status: true SUCCESS
  • ✅ BUY hedge PE SENSEX2682075900PE (100 qty) → status: true
  • ✅ SELL straddle CE SENSEX2682077400CE (20 qty) → status: true
  • ✅ SELL straddle PE SENSEX2682077400PE (20 qty) → status: true
  • ✅ 2 open sell positions → SL orders placed

First live SENSEX short straddle executed: ATM 77400, hedges ±1500, lot 20.

Note

Hotfixed directly on the VPS during market hours (user-approved) — this PR formalizes it.

Kunal Bhatia added 5 commits August 20, 2026 10:52
SENSEX orders were failing with AB4046 'Symbol token not found in scrip
master cache for the given exchange' because doOrder defaulted to 'NFO'.
SENSEX trades on BFO. Derive exchange from the symbol via
getIndexFromSymbol/getExchangeForIndex when not explicitly provided, and
remove the hardcoded 'NFO' in placeStoplossForAllSells.
SENSEX symbols use a different date format (SENSEX2682077400CE, numeric
YYMDD) than NIFTY (NIFTY26AUG24200CE, DDMMMYY), and some SENSEX expiries
even use SENSEX26AUG76800PE. The old anchored regex only matched NIFTY
format, so SENSEX strikeprice fell back to '0' — which made the roll
logic (|ATM - prevStrike| >= strikeDiff) fire every tick and duplicate
the straddle at the same strike (20-Aug live incident: 77400 sold twice).

Strike is always the last 5 digits before CE/PE in both formats, so the
regex is now /(\d{5})([CP]E)$/ in positions.ts and paperTrade.ts.
Previously setStraddleOpenedToday ran unconditionally after the SELL
attempts, even when both orders were rejected (e.g. AB4046). The next
tick then skipped the entry ('Straddle already opened once in this
session') while positions.json was empty — no position, but the flag
blocked retries. Now capture both doOrderByStrike results and only set
the flag when ceSell.status && peSell.status are both true; otherwise
log and leave the flag false so the next tick retries.

31 strategy tests pass, tsc clean.
doOrderByStrike returns OrderData | boolean | undefined (boolean when
hedge LTP>3 skip, undefined under mocks). Only treat a real object with
status===true as filled. tsc clean, 31/31 strategy tests pass.
@kunalrbhatia
kunalrbhatia merged commit f395f7a into development Aug 20, 2026
14 checks passed
@kunalrbhatia
kunalrbhatia deleted the fix/sensex-order-exchange branch August 20, 2026 05:55
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