Skip to content

Market Data

The Go SDK covers REST quotes, historical candles, instruments, option chain, Greeks, holidays, and the index list.

Quote Modes

REST quotes use InfoQuoteMode (not StreamMode).

Mode Code Description Data Included
LTP arrow.InfoQuoteLTP (ltp) Last Traded Price ltp, close, token
OHLCV arrow.InfoQuoteOHLCV (ohlcv) OHLC & Volume open, high, low, close, ltp, volume, ltt, oi, token
FULL arrow.InfoQuoteFull (full) Complete market depth OHLCV-style fields plus bids, asks, symbol, etc.

Price scaling

REST quote endpoints return prices as integers in paise (×100). Divide by 100 for rupees. See Instrument Quotes.

Argument order

GetQuote(exchange, symbol, mode) — exchange first. Python is get_quote(mode, symbol, exchange).

Single Instrument Quote

GetQuote returns map[string]any.

LTP Quote

quote, err := client.GetQuote(arrow.ExchangeNSE, "RELIANCE-EQ", arrow.InfoQuoteLTP)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("LTP: ₹%.2f\n", asFloat(quote["ltp"])/100)
fmt.Printf("Close: ₹%.2f\n", asFloat(quote["close"])/100)
fmt.Println("Token:", quote["token"])

OHLCV Quote

quote, err := client.GetQuote(arrow.ExchangeNSE, "RELIANCE-EQ", arrow.InfoQuoteOHLCV)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("O: %.2f H: %.2f L: %.2f C: %.2f vol=%v\n",
    asFloat(quote["open"])/100,
    asFloat(quote["high"])/100,
    asFloat(quote["low"])/100,
    asFloat(quote["close"])/100,
    quote["volume"],
)

Full Quote (Market Depth)

quote, err := client.GetQuote(arrow.ExchangeNSE, "RELIANCE-EQ", arrow.InfoQuoteFull)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("LTP: ₹%.2f\n", asFloat(quote["ltp"])/100)

bids, _ := quote["bids"].([]any)
asks, _ := quote["asks"].([]any)
if len(bids) > 0 {
    bid := bids[0].(map[string]any)
    fmt.Printf("Best bid: ₹%.2f x %v\n", asFloat(bid["price"])/100, bid["quantity"])
}
if len(asks) > 0 {
    ask := asks[0].(map[string]any)
    fmt.Printf("Best ask: ₹%.2f x %v\n", asFloat(ask["price"])/100, ask["quantity"])
}

JSON numbers decode as float64 in map[string]any. A small helper:

func asFloat(v any) float64 {
    switch n := v.(type) {
    case float64:
        return n
    case int:
        return float64(n)
    default:
        return 0
    }
}

Multiple Instrument Quotes

quotes, err := client.GetQuotes([]arrow.QuoteInstrument{
    {Exchange: string(arrow.ExchangeNSE), Symbol: "ADANIENT-EQ"},
    {Exchange: string(arrow.ExchangeMCXFO), Symbol: "GOLDPETAL31JUL26F"},
    {Exchange: string(arrow.ExchangeBSE), Symbol: "RELIANCE"},
}, arrow.InfoQuoteLTP)
if err != nil {
    log.Fatal(err)
}
for _, q := range quotes {
    fmt.Printf("Token %v LTP ₹%.2f\n", q["token"], asFloat(q["ltp"])/100)
}

Batch quote shape

GetQuotes returns rows with token, ltp, and close only for LTP mode. There is no symbol or exchange field in batch responses — match rows using token.

Greeks

GetGreeks POSTs { exchange, symbol } pairs (not raw token integers).

raw, err := client.GetGreeks([]arrow.GreeksInstrument{
    {Exchange: string(arrow.ExchangeNFO), Symbol: "NIFTY16JUN26C23150"},
})
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(raw))

Historical Candle Data

GetCandleData calls https://historical-api.arrow.trade/candle/{exchange}/{token}/{interval}. Success is a JSON array of rows (not the usual {data,status} envelope). ExchangeMCXFO is sent as mcx in the path.

Interval Code
1 Minute min
3 / 5 / 10 / 15 / 30 Minutes 3min, 5min, 10min, 15min, 30min
1 Hour hour
2 / 3 / 4 Hours 2hours, 3hours, 4hours
1 Day day
1 Week week
1 Month month

See Historical Data API. Use ISO datetimes (YYYY-MM-DDTHH:MM:SS). Set oi to true only for NFO (adds oi=1 and an extra field per row).

candles, err := client.GetCandleData(
    arrow.ExchangeNSE,
    "3045",
    "5min",
    "2024-01-15T09:15:00",
    "2024-01-15T15:30:00",
    false,
)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(candles))

Daily candles

end := time.Now()
start := end.AddDate(0, 0, -30)
candles, err := client.GetCandleData(
    arrow.ExchangeNSE,
    "3045",
    "day",
    start.Format("2006-01-02T15:04:05"),
    end.Format("2006-01-02T15:04:05"),
    false,
)

F&O candles with Open Interest

candles, err := client.GetCandleData(
    arrow.ExchangeNFO,
    "46799",
    "15min",
    "2024-01-15T09:15:00",
    "2024-01-15T15:30:00",
    true, // oi=1
)

Each candle is typically [timestamp, open, high, low, close, volume] with OI as a 7th element when requested. Prices are in paise.

Instruments

Download the instrument master as CSV. Unlike Python get_instruments() (always /all), Go takes a segment:

Constant Path
arrow.InstrumentSegmentAll /all
arrow.InstrumentSegmentNSE /nse
arrow.InstrumentSegmentBSE /bse
arrow.InstrumentSegmentMCX /mcx
arrow.InstrumentSegmentIndices /indices
csvText, err := client.GetInstrumentsCSV(arrow.InstrumentSegmentAll)
if err != nil {
    log.Fatal(err)
}

rows, err := client.GetInstruments(arrow.InstrumentSegmentMCX)
if err != nil {
    log.Fatal(err)
}
for _, row := range rows {
    fmt.Println(row)
}

See Symbols API for CSV column definitions. Refresh after 8:00 AM IST daily.

Option Chain

Option chain symbols

Returns { "equity": {...}, "indices": {...} } maps of underlyings to expiry lists.

symbols, err := client.GetAllOptionChainSymbols()
if err != nil {
    log.Fatal(err)
}
// symbols["equity"]["NSE:RELIANCE-EQ"] => []string{"26-MAY-2026", ...}
fmt.Println(symbols["indices"]["INDEX:NIFTY"])

Option chain

GetOptionChain returns json.RawMessage.

Index options — use ExchangeINDEX:

chain, err := client.GetOptionChain(arrow.OptionChainRequest{
    Underlying: "NIFTY",
    Exchange:   arrow.ExchangeINDEX,
    Count:      "10",
    Expiry:     "16-JUN-2026",
})

Equity options — use ExchangeNSE:

chain, err := client.GetOptionChain(arrow.OptionChainRequest{
    Underlying: "RELIANCE-EQ",
    Exchange:   arrow.ExchangeNSE,
    Count:      "20",
    Expiry:     "28-JUL-2026",
})

Option chain leg fields (live)

Field Description
symbol Contract symbol (e.g. NIFTY16JUN26C23150)
token Option instrument token
strikePrice Strike price string
optionType CE or PE
segment e.g. NSEFO
lotSize Lot size
tickSize Tick size
openingOI Opening open interest

Index List

indices, err := client.GetIndexList()
if err != nil {
    log.Fatal(err)
}
for _, idx := range indices {
    name := idx["name"]
    if name == nil {
        name = idx["indexName"]
    }
    fmt.Printf("%v: token %v\n", name, idx["token"])
}

Market Holidays

holidays, err := client.GetHolidays()
if err != nil {
    log.Fatal(err)
}
for date, name := range holidays.Holidays {
    fmt.Printf("  %s: %s\n", date, name)
}

HolidaysData also has SpecialTradingDays.

Example: Market Scanner

func marketScanner(client *arrow.Client, watchlist []struct {
    Symbol string
    Token  float64
}) {
    instruments := make([]arrow.QuoteInstrument, 0, len(watchlist))
    tokenToSymbol := map[float64]string{}
    for _, w := range watchlist {
        instruments = append(instruments, arrow.QuoteInstrument{
            Exchange: string(arrow.ExchangeNSE),
            Symbol:   w.Symbol,
        })
        tokenToSymbol[w.Token] = w.Symbol
    }

    quotes, err := client.GetQuotes(instruments, arrow.InfoQuoteOHLCV)
    if err != nil {
        log.Fatal(err)
    }
    for _, q := range quotes {
        token := asFloat(q["token"])
        symbol := tokenToSymbol[token]
        closePx := asFloat(q["close"])
        ltp := asFloat(q["ltp"])
        if closePx == 0 {
            continue
        }
        change := (ltp - closePx) / closePx * 100
        fmt.Printf("%s change %.2f%% volume %v\n", symbol, change, q["volume"])
    }
}

Quote Response Fields

LTP Mode Fields

Field Type Description
token number Instrument token
ltp number Last traded price (paise)
close number Previous close (paise)

OHLCV Mode Fields

Field Type Description
open / high / low / close number OHLC (paise)
ltp number Last traded price
volume number Traded volume

Full Mode Additional Fields

Field Type Description
oi number Open Interest
bids / asks array 5 depth levels
symbol string Trading symbol (full mode)