Search an instrument by symbol
With the instrument master cached (chapter 21), resolve a tradingsymbol to its full row (and instrument_token) locally — no API call needed.
def find_instrument(df, exchange: str, tradingsymbol: str) -> dict:
match = df[(df.exchange == exchange) & (df.tradingsymbol == tradingsymbol)]
if match.empty:
raise ValueError(f"No instrument found: {exchange}:{tradingsymbol}")
return match.iloc[0].to_dict()
infy = find_instrument(nse_df, "NSE", "INFY")
print(infy["instrument_token"], infy["lot_size"], infy["tick_size"])
Fuzzy search by name (when you don't know the exact symbol)
def search_by_name(df, exchange: str, query: str, limit: int = 10) -> list[dict]:
matches = df[
(df.exchange == exchange) &
(df.name.str.contains(query, case=False, na=False))
]
return matches.head(limit).to_dict("records")
search_by_name(nse_df, "NSE", "infosys")
Symbol format gotchas
- Equity: plain symbol, e.g.
INFY,RELIANCE. - Futures:
NIFTY24DECFUT— index/underlying + expiry month +FUT. - Options:
NIFTY24D2624500CE— underlying + expiry + strike +CE/PE. Exact format varies by expiry type (monthly vs weekly) — always resolve via the instrument master rather than constructing the string yourself; expiry-code conventions have changed historically and differ slightly across index vs stock options. - BSE and NSE can list the same company under different tokens — always filter by
exchangeexplicitly, never assume NSE is the only match.
def safe_lookup(df, exchange: str, symbol: str) -> int:
"""Returns instrument_token, raising loudly on ambiguity or absence."""
rows = df[(df.exchange == exchange) & (df.tradingsymbol == symbol)]
if len(rows) != 1:
raise ValueError(f"Expected exactly 1 match for {exchange}:{symbol}, got {len(rows)}")
return int(rows.iloc[0]["instrument_token"])