F&O instrument fields: expiry, lot size, strike

F&O rows in the instrument master (chapter 21) carry fields equity rows leave empty/zero.

nfo_df = kite.instruments("NFO")
option_row = nfo_df[
    (nfo_df.name == "NIFTY") &
    (nfo_df.instrument_type == "CE") &
    (nfo_df.strike == 24500)
].sort_values("expiry").iloc[0]

print(option_row[["tradingsymbol", "expiry", "strike", "lot_size", "tick_size"]])
{
  "tradingsymbol": "NIFTY26D2624500CE",
  "expiry": "2026-12-26",
  "strike": 24500.0,
  "lot_size": 65,        # you can only trade in multiples of this — current NIFTY lot size, see note below
  "tick_size": 0.05,     # minimum price increment
}

lot_size — quantity must always be a multiple of it

def validate_quantity(qty: int, lot_size: int):
    if qty % lot_size != 0:
        raise ValueError(f"Quantity {qty} is not a multiple of lot_size {lot_size}")

Placing an order with quantity=100 on an instrument with lot_size=65 is rejected outright — the exchange only accepts whole-lot orders on F&O. Equity has lot_size=1 (any integer quantity is valid).

tick_size — price must align to it

def round_to_tick(price: float, tick_size: float) -> float:
    return round(price / tick_size) * tick_size

A limit order priced at ₹182.53 on an instrument with tick_size=0.05 gets rejected — round every computed limit price to the nearest valid tick before sending it.

instrument_type values you'll see in NFO/BFO

FUT (future), CE (call option), PE (put option). Combine with name (underlying, e.g. NIFTY, RELIANCE) and expiry to fully identify a contract.

Lot size changes periodically — and just did, again

NSE revised index F&O lot sizes effective the January 2026 expiry series: NIFTY 50 moved from 75 to 65, BANKNIFTY from 35 to 30. This is not a one-time historical event — NSE reviews and adjusts lot sizes periodically (roughly tracking index value, per SEBI's minimum-contract-value guidelines), and has done so multiple times. Never hardcode a lot size in your strategy code — always read it fresh from the instrument master for the specific contract you're about to trade, exactly as option_row["lot_size"] does above. Any code, tutorial, or forum post you find quoting a specific lot size number should be treated as a snapshot in time, not a constant.

Next: 033 — Build an option chain