This file explains the project internals: which APIs are used, how data moves through the app, and where the TradingView-specific pieces live.
index.html: loads Advanced Charts assets andsrc/main.js.trading.html: loads Trading Platform assets andsrc/trading.js.src/main.js: minimal Advanced Charts bootstrap.src/trading.js: Trading Platform bootstrap, broker sample setup, alerts, toolbar, save/load, and chart-ready subscription area.src/widget-options.js: shared widget options plus route-specific AC/TP option builders. The AC builder removes quote and DOM methods from the exposed datafeed.src/datafeed.js: TradingView datafeed implementation.src/streaming.js: realtime candle streams.src/quotes.js: realtime quote streams used by Trading Platform widgetbar/details/watchlist UI.src/helpers.js: Binance request helpers, symbol parsing, and resolution mapping.server.mjs: static server and same-origin CoinDesk RSS proxy.
npm run tv:install:ac and npm run tv:install:tp use npm to install
TradingView GitHub repositories into a temporary folder and copy the runtimes
directly into vendor/tradingview/.
tv:install:acinstalls only Advanced Charts.tv:install:tpinstalls Advanced Charts and Trading Platform, so both/and/tradinghave runtime assets.
npm run tv:sync copies whichever local TradingView package folders exist:
charting_library-master/charting_librarytovendor/tradingview/advanced_charts.trading_platform-master/charting_librarytovendor/tradingview/trading_platform.
The generated vendor/tradingview/ folder is ignored by git.
The Trading Platform install helper also installs
broker-sample/dist/bundle.js into
third_party/tradingview/broker-sample/dist/bundle.js. It first checks the
installed package, then falls back to fetching the file from the Trading
Platform repository using the same version or git ref.
Base URL:
https://api.binance.com/
Used endpoints:
api/v3/exchangeInfo: loads Binance spot symbols forsearchSymbolsandresolveSymbol.api/v3/time: synchronizes the library's bar-close countdown with Binance server time.api/v3/klines: loads historical OHLCV bars forgetBars.api/v3/ticker/24hr: seeds Trading Platform quote fields such as last price, bid/ask, daily high/low, volume, and daily change.api/v3/ticker?windowSize=1h: seeds Trading Platform rolling 1-hour quote change fields.
No Binance API key is required.
The chart's datafeed advertises supports_time: true, so the library calls
getServerTime(callback) when it needs an authoritative clock for the
bar-close countdown.
getServerTime requests Binance's api/v3/time endpoint through the shared
makeApiRequest helper. Binance responds with an object such as
{ "serverTime": 1784719101174 }, where serverTime is Unix time in
milliseconds. The datafeed converts it to the seconds value expected by the
Charting Library before calling the callback:
callback(Math.floor(serverTime / 1000));The callback is invoked exactly once for each request. If Binance cannot be reached or returns an invalid value, the datafeed logs a warning and falls back to the browser clock so the chart remains usable; its countdown may then differ from Binance time.
The server-time method provides the value only. The price-scale display is
enabled independently with the mainSeriesProperties.showCountdown chart
override in src/theme.js, for both light and dark themes.
Base URL:
wss://stream.binance.com:9443/ws
Used streams:
<symbol>@kline_<interval>: native Binance intervals such as1m,5m,1h,1d.<symbol>@trade: tick stream used to rebuild custom intervals such as2,4,10,90, and180.<symbol>@ticker: realtime 24-hour quote updates for Trading Platform quote UI.<symbol>@ticker_1h: realtime rolling 1-hour quote updates for Trading Platform quote UI.<symbol>@depth20@100ms: Trading Platform DOM depth for Binance spot symbols.
The stream modules share sockets, reference-count subscriptions, debounce startup churn, and reconnect only while active subscribers exist.
src/datafeed.js implements the TradingView methods used by the widgets:
onReadygetServerTimesearchSymbolsresolveSymbolgetBarssubscribeBarsunsubscribeBarsgetMarksgetTimescaleMarksgetQuotessubscribeQuotesunsubscribeQuotessubscribeDepthunsubscribeDepth
The Advanced Charts route exposes only chart/search/history/realtime bar
methods. getQuotes, subscribeQuotes, unsubscribeQuotes, subscribeDepth,
and unsubscribeDepth are exposed only to the Trading Platform route.
subscribeDepth is Trading Platform-specific. It uses live Binance depth first
and only generates synthetic levels while live depth is unavailable.
src/symbol-status.js adds a custom item to the Market Status popup in the chart
header describing where the loaded symbol's data comes from and how fresh it is:
a hover tooltip (Real-time · Binance) plus a drop-down section with the raw
Binance feed symbol, the exchange, the session, and a link to the Binance API
docs.
The module exposes two functions:
setSymbolStatus(symbolInfo, providerSymbol)— called fromresolveSymbol.installSymbolStatus(widget)— called from both page bootstraps.
The status is published from resolveSymbol rather than from a chartReady()
block subscribed to onSymbolChanged. ICustomSymbolStatusApi.symbol() keys
each status on a symbolId that must match the resolved symbol exactly — the
full ticker Binance:BTC/USDT, never the short BTC/USDT name — and
resolveSymbol is the one place that value is known for certain. Driving it
from onSymbolChanged works too, but only by reading symbolInfo.ticker and
deferring the call with a timeout, because the header applies the status after
the event fires.
widget.customSymbolStatus() is only available once the chart exists, so
installSymbolStatus resolves it inside headerReady(). The first
resolveSymbol can land before that promise settles, so statuses derived in the
meantime are queued in a Map keyed by symbol id and replayed on connect
instead of being dropped.
CustomStatusDropDownContent.content strings are interpreted as HTML markup.
Everything interpolated into them comes from the Binance exchangeInfo
response, so the module escapes those values before building the section.
describeFeed derives the wording from the symbol info instead of hardcoding
it: a delay above zero produces the amber "delayed" variant, anything else
produces the teal real-time variant. Binance spot is real-time and this datafeed
never sets delay, so the delayed branch is the path to reuse when pointing the
app at a feed that reports one.
[
'1',
'2',
'3',
'4',
'5',
'10',
'15',
'30',
'60',
'90',
'120',
'180',
'240',
'360',
'480',
'720',
'1D',
'3D',
'1W',
'1M',
];Raw intervals Binance serves natively, declared in BINANCE_INTERVALS
(src/datafeed/helpers.js) and in the symbol's *_multipliers:
1S,1,3,5,15,30,60,120,240,360,480,720,1D,3D,1W,1M— matching Binance's1s…1Mkline intervals.
Intervals the library builds by aggregating those raw bars:
5S,15S,30S,2,4,10,90,180.
The split matters, because it decides what the datafeed must implement. A
*_multipliers array declares the resolutions the datafeed can serve itself;
supported_resolutions may list more, and the library rebuilds the difference.
So the library never calls getBars with 2 — it requests 1 and aggregates.
The mapping it picks is the largest multiplier that divides the target evenly:
| Selected in the UI | Requested from getBars |
|---|---|
5S, 15S, 30S |
1S |
2, 4 |
1 |
10 |
5 |
90 |
30 |
180 |
60 |
That is why this datafeed contains no bar-aggregation code: writing any would
duplicate the library and never run. The only rule to honour is that every entry
in a *_multipliers array must be an interval the provider actually returns.
Note the library cannot build daily, weekly, or monthly bars out of intraday
data, which is why 1D, 3D, 1W, and 1M are all declared as raw intervals.
Seconds need one extra step beyond the multiplier rule, because they are gated by a featureset as well as by symbol info:
seconds_resolutionis enabled inSHARED_ENABLED_FEATURES(src/widget-options.js). Without it the resolutions never appear in the UI, no matter what the datafeed declares.has_seconds: trueandseconds_multipliers: ['1']are returned fromresolveSymbol. Binance publishes only the1skline, so['1']is the honest declaration; the library builds5S,15S, and30Sfrom it.
Realtime uses the <symbol>@kline_1s websocket stream, the same code path as
every other interval. Note that a 15S chart makes the library request 1S
bars at 15× the bar count — a single screen is roughly 4600 klines, so the
paging loop in fetchKlinesBefore runs several times per load.
One library limitation to expect: the price-scale countdown is documented for
intraday resolutions, with daily/weekly/monthly added in v32. Seconds fall
outside that scope and the readout is unreliable — at 15S it counts down from
values well past the bar length, while 30S happens to look plausible. The bars
themselves are correct; only the countdown does not apply.
getBars is driven by periodParams.countBack, not by from. countBack is
the exact number of bars the library needs, and it outranks the time range: if a
response contains fewer bars, the library immediately issues another getBars
call for the shortfall, so an off-by-one costs a round trip on every load.
fetchKlinesBefore therefore asks Binance for countBack bars ending at to
rather than for a time window. Binance returns the most recent klines at or
before endTime, which maps onto that contract directly. Requests above the
1000-kline limit page backwards with endTime = firstOpenTime - 1, an exclusive
bound that cannot repeat the bar already read.
Two boundary rules come out of the docs:
- The bar opening exactly on
tobelongs to the previous response and is filtered out, otherwise the library reports duplicate bar times. - When the provider runs out of history, the response must set
{ noData: true }. Without it the library keeps requesting older data forever.ETH/USDTat1Mhits this after ~109 bars.
The Trading Platform widgetbar uses CoinDesk RSS through this local route:
/api/news/coindesk-rss
CoinDesk does not provide browser CORS headers for local development, so
server.mjs fetches the RSS feed server-side, returns it same-origin, and
strips HTML tags from RSS titles/descriptions before TradingView displays the
items. The free Advanced Charts route does not configure rss_news_feed.
The /trading route adds:
- BrokerDemo runtime from
third_party/tradingview/broker-sample/dist/bundle.js. broker_factoryandbroker_config.- Trading Platform DOM via
subscribeDepth. - LocalStorage-backed save/load adapter.
- Custom alert demo using chart shapes plus broker notifications.
- Account manager, watchlist, details, quote data, data window, news, and toolbar controls.
The BrokerDemo bundle source is: broker-sample/dist/bundle.js.
TradingView internal settings localStorage is disabled through
disabled_features so tutorial defaults are deterministic across localhost
and 127.0.0.1.
The Trading Platform save/load adapter still stores charts, drawings, templates,
and study templates in browser localStorage.
- Binance public endpoint availability can vary by jurisdiction or network.
- Trading Platform CoinDesk news depends on the local server route, so use
npm run start. - Chart marks and timescale marks are demo data.
- Non-Binance symbols cannot use live Binance DOM depth and will fall back to generated DOM levels.