Shop It Docs
TradingView UDF

GET /config

Server capabilities exposed to TradingView's Charting Library

/config advertises what the backend supports. TradingView's Charting Library calls this first when mounting a chart and uses the response to decide which UI features to enable (symbol search, server time sync, etc.).

  • Method: GET
  • Path: /api/nepse/tradingview/config
  • Content-Type: application/json
  • Query params: none

Response shape

{
  "supported_resolutions": ["1", "5", "15", "30", "60", "1D", "1W", "1M"],
  "supports_search": true,
  "supports_group_request": false,
  "supports_marks": false,
  "supports_timescale_marks": false,
  "supports_time": true,
  "exchanges": [
    { "value": "NEPSE", "name": "NEPSE", "desc": "Nepal Stock Exchange" }
  ],
  "symbols_types": [
    { "name": "All types", "value": "" },
    { "name": "Stock", "value": "stock" }
  ]
}
FieldTypeValueWhy
supported_resolutionsstring[]["1","5","15","30","60","1D","1W","1M"]Five intraday minute-buckets plus daily/weekly/monthly.
supports_searchbooleantrue/search endpoint is implemented.
supports_group_requestbooleanfalseWe don't support batch symbol resolution.
supports_marksbooleanfalseNo events/marks layer.
supports_timescale_marksbooleanfalseNo timescale marks.
supports_timebooleantrue/time endpoint is implemented. The library uses it to stay clock-synced with the server, which matters for real-time bar rollover.
exchangesExchange[]NEPSE onlySingle-exchange deployment.
symbols_typesSymbolType[]All types + StockNEPSE has only stock-type instruments in the UDF sense.

The payload is emitted at the root — no {message, data} envelope. Flat supports_* booleans. The TradingView library parses these directly; an envelope breaks symbol resolution entirely.

Why /time and /search are advertised

TradingView gates UI features on the booleans in /config:

  • supports_time: true → the library calls /time periodically and adjusts its internal clock.
  • supports_search: true → the symbol-search UI becomes active; it calls /search?query=… as the user types.

If either boolean is false, the corresponding feature is disabled in the chart regardless of whether the backend endpoint exists.

Performance

The response is a compile-time constant struct. The handler marshals it once per process using a sync.Once around a []byte, then writes that byte slice directly on every subsequent request — zero per-request allocation.

type configBytesCache struct {
    once  sync.Once
    bytes []byte
    err   error
}

func (c *configBytesCache) get(cfg *ConfigResponse) ([]byte, error) {
    c.once.Do(func() {
        c.bytes, c.err = json.Marshal(cfg)
    })
    return c.bytes, c.err
}

Three consecutive /config calls should return identical bytes (identical md5). Verify:

curl -s https://api.ranjanyadav.com.np/api/nepse/tradingview/config | md5sum
curl -s https://api.ranjanyadav.com.np/api/nepse/tradingview/config | md5sum
curl -s https://api.ranjanyadav.com.np/api/nepse/tradingview/config | md5sum

Because the payload is small and cacheable, Nginx is also configured to serve it with a 1-hour proxy_cache_valid.

Invalidation

The cached bytes live for the process lifetime — they're invalidated on deploy (the process restarts). There is no runtime invalidation hook, and there shouldn't need to be: changing the config implies changing the binary.

Errors

ConditionStatusBody
Marshal failure (should be impossible — struct is static)500{"s":"error","errmsg":"internal_error"}
Panic inside handler500{"s":"error","errmsg":"internal_error"} (from tradingview.Recoverer())

Verification

# Must have supports_time:true at the root
curl -s "$BASE/config" | jq '.supports_time, .supports_search'
# true
# true

# Must NOT have envelope keys
curl -s "$BASE/config" | jq 'if has("data") or has("message") then "LEAK" else "ok" end'
# "ok"

Implementation

  • Handler: internal/modules/nepse/tradingview/handler.go(*Handler).Config
  • Service: internal/modules/nepse/tradingview/service.go(*Service).GetConfig
  • Cache: internal/modules/nepse/tradingview/cache.goconfigBytesCache
  • Type: internal/modules/nepse/tradingview/types.goConfigResponse