Shop It Docs
TradingView UDF

Reference Tables

Compact reference for all TV endpoints, fields, errors, cache keys, and database tables

Endpoint matrix

PathMethodQuery paramsContent-TypeRate-limitedgzippedCached
/configGETapplication/json✓ (60/min)In-process + nginx 1h
/timeGETtext/plainNever
/symbolsGETsymbolapplication/jsonRedis 5m + nginx 5m
/searchGETquery, limit, type?, exchange?application/json (bare array)Nginx 1m
/historyGETsymbol, resolution, from, to, countback?application/jsonNginx 5m

Base path: /api/nepse/tradingview. All endpoints are GET-only.

Symbol kinds

KindPrefixtypeResolverTable family
StockstockFindCompanyBySymbolcompany_idnepse_price_history, nepse_intraday_prices
Index^indexFindIndexByTVSymbolindex_idnepse_index_history, nepse_intraday_indices
Sector sub-index^indexFindSubIndexByTVSymbolsub_index_idnepse_sub_index_history, nepse_intraday_sub_indices

Symbol resolution strips an optional NEPSE: exchange prefix, case-normalizes, then:

  1. If the remaining symbol starts with ^, look up nepse_indices.tv_symbol = <rest>; on miss, fall back to nepse_sub_indices.tv_symbol = <rest>.
  2. Otherwise look up nepse_companies.symbol = <symbol>.

The master-table column tv_symbol is NOT NULL UNIQUE and backfilled by migration 000018_add_tv_symbol.

Supported resolutions

Same 8 resolutions apply to every kind; only the underlying table changes.

ResolutionPathStock tableIndex tableSub-index tableAggregationt convention
1intradaynepse_intraday_pricesnepse_intraday_indicesnepse_intraday_sub_indicesSQL bucket 60spolled_at
5intradaysamesamesameSQL bucket 300spolled_at
15intradaysamesamesameSQL bucket 900spolled_at
30intradaysamesamesameSQL bucket 1800spolled_at
60intradaysamesamesameSQL bucket 3600spolled_at
1Ddailynepse_price_historynepse_index_historynepse_sub_index_historynone (1 row per day)11:00 NPT
1Wweeklysamesamesamedate_trunc('week', …) (Mon-start)00:00 NPT Monday
1Mmonthlysamesamesamedate_trunc('month', …)00:00 NPT 1st

Response field reference

JSONGoDescription
supported_resolutions[]string["1","5","15","30","60","1D","1W","1M"]
supports_searchbooltrue
supports_group_requestboolfalse
supports_marksboolfalse
supports_timescale_marksboolfalse
supports_timebooltrue
exchanges[]Exchange[{value, name, desc}] — NEPSE only
symbols_types[]SymbolType[{name,value}] — All types + Stock + Index
JSONGoExample
namestringNABIL
tickerstringNABIL
full_namestringNEPSE:NABIL
descriptionstringNabil Bank Limited
typestringstock or index (same endpoints, kind-dependent)
sessionstring1100-1500:23456
timezonestringAsia/Kathmandu
exchangestringNEPSE
listed_exchangestringNEPSE
minmovint1
pricescaleint100
has_intradaybooltrue
intraday_multipliers[]string["1","5","15","30","60"]
has_dailybooltrue
has_weekly_and_monthlybooltrue
supported_resolutions[]stringsame 8
currency_codestringNPR
data_statusstringstreaming
volume_precisionint0
JSONGoExample
symbolstringNABIL / ^NEPSE (indices keep the ^)
full_namestringNEPSE:NABIL / NEPSE:^NEPSE
descriptionstringNabil Bank Limited / NEPSE Index / Banking
exchangestringNEPSE
tickerstringsame as symbol
typestringstock or index

Response is a bare array: [SearchResult, SearchResult, …]. Empty → [].

JSONGoNotes
sstringok / no_data / error
errmsgstringonly on s=error, omitempty
t[]int64Unix seconds; only on s=ok, omitempty
o[]float64only on s=ok, omitempty
h[]float64only on s=ok, omitempty
l[]float64only on s=ok, omitempty
c[]float64only on s=ok, omitempty
v[]int64JSON integers (no decimal point); only on s=ok
nextTime*int64only on s=no_data when older data exists; omitempty

Error codes

HTTPserrmsgSourceNotes
400errorsymbol is required/symbols, /historyMissing required param
400errorinvalid resolution/historyNot in whitelist
400errorfrom and to are required/history
400errorfrom must be a unix timestamp/historyParse failure
400errorto must be a unix timestamp/historyParse failure
400errorfrom must be <= to/history
400errortimestamps out of range/historyfrom < 2000-01-01 or to > now+48h
404errorunknown_symbol/symbolsNot in nepse_companies / nepse_indices / nepse_sub_indices, or status!='A'
429(envelope)rate limiterNot UDF-shaped — standard error envelope
500errorinternal_erroranyDB error or recovered panic
504errortimeout/symbols, /history5s context deadline exceeded

Cache keys

Key patternTTLLayerNotes
nepse:tv:symbol:<SYMBOL>5mRedisResolved SymbolResponse. 404s never cached.
(none — in-process)process lifetimeGo sync.Once/config marshaled bytes

Constants:

cache.PrefixNepseTVSymbol     // "nepse:tv:symbol:"
cache.NepseTVSymbolKey(sym)   // "nepse:tv:symbol:<SYMBOL>"
cache.TTLNepseTVSymbol()      // 5 * time.Minute

Database tables touched

TableEndpointsReadsWrites
nepse_companies/symbols, /searchFindCompanyBySymbol, SearchForTV— (scheduler/admin only)
nepse_indices/symbols, /searchFindIndexByTVSymbol, SearchForTV— (poller only)
nepse_sub_indices/symbols, /searchFindSubIndexByTVSymbol, SearchForTV— (poller only)
nepse_price_history/history stock 1D/1W/1MGetStockPriceHistory, GetStockWeeklyHistory, GetStockMonthlyHistory, GetNextDailyBarBefore— (EOD cron only)
nepse_index_history/history index 1D/1W/1MGetIndexHistory, GetIndexWeeklyHistory, GetIndexMonthlyHistory, GetNextIndexDailyBarBefore— (EOD cron only)
nepse_sub_index_history/history sub-index 1D/1W/1MGetSubIndexHistory, GetSubIndexWeeklyHistory, GetSubIndexMonthlyHistory, GetNextSubIndexDailyBarBefore— (EOD cron only)
nepse_intraday_prices/history stock 1/5/15/30/60GetIntradayStockCandles, GetNextIntradayBarBefore— (poller only)
nepse_intraday_indices/history index 1/5/15/30/60GetIntradayIndexCandles, GetNextIndexIntradayBarBefore— (poller only)
nepse_intraday_sub_indices/history sub-index 1/5/15/30/60GetIntradaySubIndexCandles, GetNextSubIndexIntradayBarBefore— (poller only)

The TV module never writes to any table. It is strictly read-side.

sqlc queries

All in internal/platform/database/queries/:

QueryFileReturns
FindCompanyBySymbolcompanies.sqlcompany row
FindIndexByTVSymbolcharts.sql(id, tv_symbol, index_name)
FindSubIndexByTVSymbolcharts.sql(id, tv_symbol, name)
SearchForTVcharts.sqlmerged (tv_symbol, description, kind) across all three masters
GetStockPriceHistorycharts.sqlstock daily OHLCV rows
GetIndexHistorycharts.sqlindex daily OHLCV rows
GetSubIndexHistorycharts.sqlsub-index daily OHLCV rows
GetStockWeeklyHistory / GetStockMonthlyHistorycharts.sqlstock Mon/month-bucketed OHLCV
GetIndexWeeklyHistory / GetIndexMonthlyHistorycharts.sqlindex Mon/month-bucketed OHLCV
GetSubIndexWeeklyHistory / GetSubIndexMonthlyHistorycharts.sqlsub-index Mon/month-bucketed OHLCV
GetIntradayStockCandlescharts.sqlstock intraday buckets
GetIntradayIndexCandlescharts.sqlindex intraday buckets
GetIntradaySubIndexCandlescharts.sqlsub-index intraday buckets
GetNextDailyBarBeforecharts.sqlstock — next daily trading_date before from
GetNextIndexDailyBarBeforecharts.sqlindex — next daily trade_date before from
GetNextSubIndexDailyBarBeforecharts.sqlsub-index — next daily trade_date before from
GetNextIntradayBarBeforecharts.sqlstock — next intraday polled_at before from
GetNextIndexIntradayBarBeforecharts.sqlindex — next intraday polled_at before from
GetNextSubIndexIntradayBarBeforecharts.sqlsub-index — next intraday polled_at before from

Middleware chain (TV group)

Order matters. Innermost last.

global:
  chimw.RequestID
  httpmiddleware.RealIP
  chimw.Recoverer            ← plaintext fallback
  httpmiddleware.RequestLogger
  cors.Handler
  httpmiddleware.BodyLimit
group /api/nepse/tradingview/*:
  rl60.Middleware            ← 60 req/min per IP
  tradingview.Recoverer()    ← JSON panic → UDF error
  chimw.Compress(5)          ← gzip response
endpoint-specific:
  tvContext(r)               ← 5s timeout (history, symbols)

Timing budget

StageTypical (warm)P99
/config< 1ms (bytes cache)< 5ms
/time< 1ms< 5ms
/symbols (Redis hit)< 2ms< 10ms
/symbols (DB)~5–20ms< 100ms
/search~10–50ms< 200ms
/history 1D (30 bars)~10–30ms< 150ms
/history 1D (1 year, ~250 bars)~30–80ms< 300ms
/history 1W (aggregation)~30–80ms< 300ms
/history intraday 1m (3 days)~50–150ms< 500ms

Hard ceiling via context.WithTimeout: 5 seconds, after which → 504 timeout.

Verification one-liners

BASE="https://api.ranjanyadav.com.np/api/nepse/tradingview"

# Envelope regression scan
for ep in "config" "symbols?symbol=NABIL" "history?symbol=NABIL&resolution=1D&from=1735689600&to=1736294400"; do
  curl -s "$BASE/$ep" | jq 'if has("data") and has("message") then "LEAK" else "ok" end'
done

# Bare array check
curl -s "$BASE/search?query=NAB" | jq 'type'   # "array"

# Plain text check
curl -sv "$BASE/time" 2>&1 | grep -i content-type   # text/plain

# Session mask check
curl -s "$BASE/symbols?symbol=NABIL" | jq '.session'   # "1100-1500:23456"

# Integer volume check
curl -s "$BASE/history?symbol=NABIL&resolution=1D&from=1735689600&to=1736294400" \
  | jq '.v[0] | type'   # "number" but without fractional part in the raw body

File map (by concern)

ConcernFile
HTTP handlersinternal/modules/nepse/tradingview/handler.go
Business logicinternal/modules/nepse/tradingview/service.go
UDF DTOsinternal/modules/nepse/tradingview/types.go
Envelope bypassinternal/modules/nepse/tradingview/write.go
/config bytes cacheinternal/modules/nepse/tradingview/cache.go
JSON panic recoveryinternal/modules/nepse/tradingview/recovery.go
Router wiringinternal/http/router/router.go (TV group)
Rate limiterinternal/http/middleware/ratelimit.go
Redis cache helpersinternal/platform/cache/cache.go, keys.go
SQL queriesinternal/platform/database/queries/companies.sql, charts.sql
sqlc-generated Gointernal/platform/database/sqlc/*.go
Swaggerapidocs/swagger.json
Deployment / nginxdocs/DEPLOYMENT.md
Full plan trackerdocs/TRADINGVIEW_UDF_PLAN.md