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) |