GET /symbols
Resolve a NEPSE ticker into full TradingView symbol metadata
/symbols turns a ticker into the full metadata payload the Charting Library needs to render a chart — session window, pricescale, timezone, supported resolutions, etc.
- Method:
GET - Path:
/api/nepse/tradingview/symbols - Content-Type:
application/json
Query parameters
| Param | Required | Type | Notes |
|---|---|---|---|
symbol | ✓ | string | Ticker, optionally prefixed with NEPSE:. Case-insensitive. Prefix with ^ to address an index or sector sub-index (e.g. ^NEPSE, ^BANKING). |
Input normalization:
- Trim whitespace.
- If a colon is present, keep only the portion after it (
NEPSE:NABIL→NABIL,NEPSE:^NEPSE→^NEPSE). - Upper-case the remainder. The
^prefix survives both steps.
Symbol namespace
| Kind | Sent by client | full_name | type |
|---|---|---|---|
| Stock | NABIL | NEPSE:NABIL | stock |
| Top-level index | ^NEPSE, ^SENSITIVE, ^FLOAT, ^SFLOAT | NEPSE:^NEPSE | index |
| Sector sub-index | ^BANKING, ^DEVBANK, ^FINANCE, ^HOTELS, ^HYDRO, ^INVEST, ^LIFEINS, ^MFG, ^MICROFIN, ^MUTUAL, ^NONLIFE, ^OTHERS, ^TRADING | NEPSE:^BANKING | index |
The ^ prefix is a finance-industry convention (Yahoo ^GSPC, ^IXIC) that can never collide with NEPSE company tickers because NEPSE tickers are uppercase letters/digits only. The backend stores the bare ticker in the nepse_indices.tv_symbol / nepse_sub_indices.tv_symbol columns; the ^ is reattached in every /symbols, /search, and /history round trip.
Both top-level and sector indices come back with type: "index" — the frontend can infer sector-ness from the symbol list if it cares, but the Charting Library treats them identically.
Success response
{
"name": "NABIL",
"ticker": "NABIL",
"full_name": "NEPSE:NABIL",
"description": "Nabil Bank Limited",
"type": "stock",
"session": "1100-1500:23456",
"timezone": "Asia/Kathmandu",
"exchange": "NEPSE",
"listed_exchange": "NEPSE",
"minmov": 1,
"pricescale": 100,
"has_intraday": true,
"intraday_multipliers": ["1", "5", "15", "30", "60"],
"has_daily": true,
"has_weekly_and_monthly": true,
"supported_resolutions": ["1", "5", "15", "30", "60", "1D", "1W", "1M"],
"currency_code": "NPR",
"data_status": "streaming",
"volume_precision": 0
}| Field | Value | Notes |
|---|---|---|
name | NABIL | Display name. |
ticker | NABIL | Internal identifier — stable across chart session. |
full_name | NEPSE:NABIL | Exchange-qualified name. Used in URL bar and save-state. |
description | Nabil Bank Limited | Company name from nepse_companies.name. |
type | stock | NEPSE has only stock-type instruments in UDF terms. |
session | 1100-1500:23456 | NEPSE trading hours + day-of-week mask. See Session format. |
timezone | Asia/Kathmandu | IANA zone the session is expressed in. |
exchange | NEPSE | |
listed_exchange | NEPSE | TV spec requires both; kept identical. |
minmov | 1 | Smallest price increment, scaled. |
pricescale | 100 | Divisor. Together with minmov: minimum tick = 1/100 = 0.01 NPR. |
has_intraday | true | Intraday bars are served. |
intraday_multipliers | ["1","5","15","30","60"] | Minute resolutions the backend can aggregate. |
has_daily | true | |
has_weekly_and_monthly | true | |
supported_resolutions | same 8 as /config | Per-symbol override of supported resolutions. |
currency_code | NPR | |
data_status | streaming | Tells the library the data is live (as opposed to delayed / endofday). |
volume_precision | 0 | NEPSE volume is whole shares. Response serializes v as JSON integers. |
Session format
The session field encodes both trading hours and active weekdays.
"1100-1500:23456"
│ │
│ └─── day mask, UDF encoding: 1=Sun, 2=Mon, 3=Tue, 4=Wed, 5=Thu, 6=Fri, 7=Sat
└──────────── HHMM-HHMM window- NEPSE trades Monday–Friday, 11:00–15:00 NPT →
1100-1500:23456. - If NEPSE had a pre-open slot you wanted visible on the chart, you'd use multi-segment form:
"1030-1100,1100-1500:23456". - The
timezonefield controls how the library interprets theHHMMvalues — so1100-1500here is 11:00 Asia/Kathmandu, not UTC.
The day mask uses UDF's own 1=Sun…7=Sat convention, which is different from both ISO (1=Mon) and time.Weekday (0=Sun). 23456 = Mon through Fri in that encoding.
Caching
Resolved symbols are cached in Redis for 5 minutes:
- Key:
nepse:tv:symbol:<UPPER_SYMBOL>(constant +cache.NepseTVSymbolKey) - TTL:
cache.TTLNepseTVSymbol()= 5 minutes - 404 responses are never cached — a company added later must resolve on next call.
Redis failure (read or write) is non-fatal — the service logs a warning and falls through to the DB. This means a Redis outage degrades latency, not availability.
Error responses
All errors follow the UDF shape {"s":"error","errmsg":"..."} — never an envelope, never HTML.
| Condition | Status | errmsg |
|---|---|---|
symbol param missing or empty after trim | 400 | symbol is required |
| Unknown / delisted symbol | 404 | unknown_symbol |
| Request timed out (5s budget) | 504 | timeout |
| Any other backend error | 500 | internal_error |
| Panic | 500 | internal_error (via Recoverer) |
The 404 body still uses UDF error shape. Some UDF implementations return an empty SymbolInfo on unknown — we prefer the explicit error so the library's console reports unknown_symbol rather than silently attempting to render a symbol with blank metadata.
Prefix-stripping examples
| Request | Resolved | Type |
|---|---|---|
?symbol=NABIL | NABIL | stock |
?symbol=nabil | NABIL (upper-cased) | stock |
?symbol=NEPSE:NABIL | NABIL (prefix stripped) | stock |
?symbol=nepse:nabil | NABIL (both) | stock |
?symbol= NABIL | NABIL (trimmed) | stock |
?symbol=^NEPSE | ^NEPSE | index |
?symbol=^nepse | ^NEPSE (case normalized) | index |
?symbol=NEPSE:^NEPSE | ^NEPSE (exchange prefix stripped, ^ preserved) | index |
?symbol=^BANKING | ^BANKING | index |
?symbol= | 400 symbol is required | — |
?symbol=ZZZZZ | 404 unknown_symbol | — |
?symbol=^XXX | 404 unknown_symbol | — |
Verification
# Full payload — verify new fields are present
curl -s "$BASE/symbols?symbol=NABIL" | jq \
'{full_name, listed_exchange, session, intraday_multipliers, volume_precision}'
# Prefix stripping
curl -s "$BASE/symbols?symbol=NEPSE:NABIL" | jq '.ticker'
# "NABIL"
# Unknown
curl -sw "\n%{http_code}\n" "$BASE/symbols?symbol=ZZZZZ"
# {"errmsg":"unknown_symbol","s":"error"}
# 404Implementation
- Handler:
internal/modules/nepse/tradingview/handler.go→(*Handler).Symbols - Service:
internal/modules/nepse/tradingview/service.go→(*Service).ResolveSymbol,(*Service).resolve - Type:
internal/modules/nepse/tradingview/types.go→SymbolResponse - sqlc:
FindCompanyBySymbol(companies.sql),FindIndexByTVSymbol/FindSubIndexByTVSymbol(charts.sql) - Cache key helpers:
internal/platform/cache/keys.go→NepseTVSymbolKey,TTLNepseTVSymbol