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 exchange explicitly, 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"])

Next: 023 — instrument_token vs tradingsymbol