Need help? Support
BITCOIN
Tether Dominance USDT.D
VIP Chart
Open the full TradingView chart with our VIP menu in fullscreen.
Sort
Star a market to add it to your watchlist.
*/","frozen":false,"visible":true}}],"study_template":{"template":[],"chart_layout":""},"snapshot_url":"/advanced-chart/shared-snapshots/sF7WUCcUPQ.png","static_snapshot_only":false,"has_vip_indicators":true,"viewer_is_logged_in":false,"viewer_is_vip":false}; window.CK_CHART_SHARE_CONFIG = { isLoggedIn: false, isVip: false, csrf: "", endpoint: '/advanced-chart/api/share-chart.php' };
' + '' + '
' + 'CoinsKid' + '

Having chart issues?

' + '
' + '

Our charts use Binance klines to provide fast, near-instant market updates. Binance market-data access may be unavailable or restricted in some countries or on some networks.

' + '
First, run the Supercharts Diagnostics Tool. Make sure you are logged in, run the full diagnostic test and copy the report. The report will help identify exactly what is failing. Then send the report to CoinsKid through Support so we can investigate the issue for you.
' + '
If the report points to a connection or Binance access issue: install NordVPN, connect to a different VPN region, then reload the chart. If you are already using a VPN, switch to another region and try again.
' + '
' + 'Run Diagnostics' + 'Install NordVPN' + '' + '
' + '
'; function closeHelp() { modal.classList.remove( 'ck-open' ); modal.setAttribute( 'aria-hidden', 'true' ); } modal.addEventListener( 'click', function ( event ) { if ( event.target === modal || event.target.closest( '.ck-help-close, .ck-help-dismiss' ) ) { closeHelp(); } } ); document.addEventListener( 'keydown', function ( event ) { if ( event.key === 'Escape' && modal.classList.contains( 'ck-open' ) ) { closeHelp(); } } ); var modalHost = ckGetChartHelpHost(); if ( modalHost ) { modalHost.appendChild( modal ); } else { document.body.appendChild( modal ); } return modal; } function ckOpenChartHelp() { var modal = ckEnsureChartHelpModal(); if ( !modal ) { return; } modal.removeAttribute( 'aria-hidden' ); modal.classList.add( 'ck-open' ); var closeButton = modal.querySelector( '.ck-help-close' ); if ( closeButton ) { try { closeButton.focus(); } catch (error) {} } } function ckCreateMobileMarketsHeaderButton() { /* * The Markets control is configurable per widget call: * ?ckmarkets=1 show * ?ckmarkets=0 hide * * Do not tie VIP / Trade / Help to this setting. */ if ( window.CK_SUPERCHARTS_CONFIG && window.CK_SUPERCHARTS_CONFIG.showMarkets === false ) { return null; } if ( !isMobileChart || !window.tvWidget || typeof window.tvWidget.createButton !== 'function' ) { return null; } if ( window.ckMobileMarketsHeaderButton && window.ckMobileMarketsHeaderButton.parentNode ) { return window.ckMobileMarketsHeaderButton; } try { var button = window.tvWidget.createButton({ align:'left', useTradingViewStyle:false }); if ( !button ) { return null; } window.ckMobileMarketsHeaderButton = button; button.setAttribute( 'title', 'Markets' ); button.setAttribute( 'aria-label', 'Markets' ); button.setAttribute( 'data-ck-mobile-markets', '1' ); button.innerHTML = '' + '' + 'Markets' + ''; button.addEventListener( 'click', function ( event ) { event.preventDefault(); event.stopPropagation(); /* * Profile / heatmap embeds use the existing desktop * market list as an off-canvas panel. */ if ( document.documentElement.classList.contains( 'ck-supercharts-heatmap-embed' ) ) { document.documentElement.classList.toggle( 'ck-embed-markets-open' ); return; } /* * Full Supercharts mobile uses the existing mobile * Markets panel. */ var panel = document.getElementById( 'ckMobileMarketsPanel' ); var backdrop = document.getElementById( 'ckMobileMarketsBackdrop' ); if ( !panel ) { return; } var open = !panel.classList.contains( 'is-open' ); panel.classList.toggle( 'is-open', open ); if ( backdrop ) { backdrop.classList.toggle( 'is-open', open ); } /* * Never leave the Markets and VIP mobile panels open * at the same time. */ if ( open ) { var vipPanel = document.getElementById( 'ckMobileVipPanel' ); var vipBackdrop = document.getElementById( 'ckMobileVipBackdrop' ); if ( vipPanel ) { vipPanel.classList.remove( 'is-open' ); } if ( vipBackdrop ) { vipBackdrop.classList.remove( 'is-open' ); } } } ); return button; } catch ( error ) { console.warn( '[CoinsKid] Mobile Markets button unavailable:', error ); return null; } } function ckCreateChartHelpButton() { if ( !window.tvWidget || typeof window.tvWidget.createButton !== 'function' ) { return null; } if ( window.ckChartHelpButton && window.ckChartHelpButton.parentNode ) { return window.ckChartHelpButton; } try { var button = window.tvWidget.createButton(); if ( !button ) { return null; } window.ckChartHelpButton = button; button.setAttribute( 'title', 'Chart help' ); button.setAttribute( 'aria-label', 'Chart help' ); button.setAttribute( 'data-ck-chart-help', '1' ); button.innerHTML = '' + 'Help'; button.style.display = 'inline-flex'; button.style.alignItems = 'center'; button.addEventListener( 'click', function ( event ) { event.preventDefault(); event.stopPropagation(); ckOpenChartHelp(); } ); return button; } catch ( error ) { console.warn( '[CoinsKid] Help button unavailable:', error ); return null; } } /* * Keep the exchanges with finished icons at the top in the same order * as the existing CoinsKid links menu. Exchanges that do not yet have * a proper icon stay underneath until their artwork is supplied. */ const CK_TRADE_EXCHANGE_ORDER = [ 'bybit', 'mexc', 'blofin', 'bingx', 'bitget', 'lbank', 'kucoin', 'binance', /* No finished icon yet - keep these at the bottom. */ 'okx', 'gateio', 'coinbase', 'kraken', 'weex', 'cryptocom', 'bitmart' ]; const CK_TRADE_EXCHANGES = { /*okx: { title: 'OKX', icon: null, buildUrl: function (pair) { return 'https://www.okx.com/en-gb/trade-spot/' + encodeURIComponent( ckTradePairDash(pair).toLowerCase() ); } },*/ bybit: { title: 'Bybit', icon: ckTradeImageIcon( 'https://cdn.coinskid.com/images/bybit-logo.png', 'BY' ), buildUrl: function (pair) { return 'https://www.bybit.com/trade/usdt/' + encodeURIComponent( ckTradePairCompact(pair) ) + '?affiliate_id=26857&group_id=0&group_type=1'; } }, /*gateio: { title: 'Gate.io', icon: null, buildUrl: function (pair) { return 'https://www.gate.com/en-us/futures/USDT/' + encodeURIComponent( ckTradePairUnderscore(pair) ); } },*/ /*coinbase: { title: 'Coinbase', icon: null, buildUrl: function (pair) { return 'https://www.coinbase.com/advanced-trade/spot/' + encodeURIComponent( ckTradePairDash(pair) ); } },*/ /* kraken: { title: 'Kraken', icon: null, buildUrl: function (pair) { return 'https://pro.kraken.com/app/trade/' + encodeURIComponent( ckTradePairDash(pair).toLowerCase() ); } },*/ blofin: { title: 'BloFin', icon: ckTradeImageIcon( 'https://s2.coinmarketcap.com/static/img/exchanges/64x64/6637.png', 'BF' ), buildUrl: function () { return 'https://blofin.com/invite/CoinsKid'; } }, bingx: { title: 'BingX', icon: ckTradeImageIcon( 'https://s2.coinmarketcap.com/static/img/exchanges/64x64/1064.png', 'BX' ), buildUrl: function (pair) { return 'https://bingx.com/en-us/spot/' + encodeURIComponent( ckTradePairCompact(pair) ) + '?ref=CoinsKid'; } }, lbank: { title: 'LBank', icon: ckTradeImageIcon( 'https://static.coinpaprika.com/exchanges/lbank/logo.png?rev=10659857', 'LB' ), buildUrl: function (pair) { return 'https://www.lbank.com/futures/' + encodeURIComponent( ckTradePairCompact(pair) ) + '?icode=4YJ2G'; } }, kucoin: { title: 'Kucoin', icon: ckTradeImageIcon( 'https://cdn.coinskid.com/images/kucoin-logo.png', 'KC' ), buildUrl: function (pair) { return 'https://www.kucoin.com/futures/trade/' + encodeURIComponent( ckTradePairCompact(pair) + 'M' ) + '?rcode=H1aga2&utm_source=rf'; } }, weex: { title: 'WEEX', icon: ckTradeImageIcon( 'https://cdn.coinskid.com/images/weex-logo.png', 'WX' ), buildUrl: function (pair) { return 'https://www.weex.com/futures/' + encodeURIComponent( ckTradePairDash(pair) ); } }, mexc: { title: 'MexC', icon: ckTradeImageIcon( 'https://cdn.coinskid.com/images/mexc.png', 'MX' ), buildUrl: function (pair) { return 'https://futures.mexc.com/exchange/' + encodeURIComponent( ckTradePairUnderscore(pair) ) + '?inviteCode=1apjB'; } }, /*cryptocom: { title: 'Crypto.com', icon: null, buildUrl: function (pair) { return 'https://crypto.com/exchange/trade/spot/' + encodeURIComponent( ckTradePairUnderscore(pair) ); } },*/ binance: { title: 'Binance', icon: ckTradeImageIcon( 'https://s2.coinmarketcap.com/static/img/exchanges/64x64/270.png', 'BN' ), buildUrl: function (pair) { return 'https://www.binance.com/en/futures/' + encodeURIComponent( ckTradePairCompact(pair) ) + '?ref=17133279'; } }, /*bitmart: { title: 'BitMart', icon: null, buildUrl: function (pair) { return 'https://www.bitmart.com/en-US/futures/' + encodeURIComponent( ckTradePairCompact(pair) ); } }, */ bitget: { title: 'Bitget', icon: ckTradeImageIcon( 'https://cdn.coinskid.com/images/bitget-logo-new.png', 'BG' ), buildUrl: function (pair) { return 'https://www.bitget.com/futures/usdt/' + encodeURIComponent( ckTradePairCompact(pair) ) + '?languageType=0&channelCode=CoinsKid&vipCode=xkrl'; } } }; function ckGetCurrentTradeMeta( chart ) { let symbol = window.ckCurrentSuperchartSymbol || firstSymbol || ''; try { if ( chart && typeof chart.symbol === 'function' ) { const chartSymbol = chart.symbol(); if ( chartSymbol ) { symbol = chartSymbol; } } } catch (error) {} const cleanSymbol = String(symbol || '') .replace('BINANCE:', '') .replace('COINSKID:', '') .replace(/[^A-Za-z0-9]/g, '') .toUpperCase(); return ( window.CoinsKidSymbolMeta && window.CoinsKidSymbolMeta[ cleanSymbol ] ) || null; } function ckBuildTradeMenuItems( chart ) { const meta = ckGetCurrentTradeMeta( chart ); if ( !meta ) { return [{ title: 'No trade links available', icon: ckTradeBadgeIcon('--'), onSelect: function () {} }]; } const tradeSymbols = meta.tradeSymbols && typeof meta.tradeSymbols === 'object' ? meta.tradeSymbols : {}; const items = []; CK_TRADE_EXCHANGE_ORDER.forEach( function ( exchangeKey ) { const pair = tradeSymbols[ exchangeKey ]; const exchange = CK_TRADE_EXCHANGES[ exchangeKey ]; if ( !pair || !exchange || typeof exchange.buildUrl !== 'function' ) { return; } const url = exchange.buildUrl( pair, meta ); if ( !url ) { return; } const tradeItem = { /* * Keep the menu visually clean. The exact DB pair is still * used inside buildUrl(), but does not need to be shown. */ title: exchange.title, onSelect: function () { ckTradeOpen( url ); } }; /* * Do not show a temporary badge for exchanges whose proper * icon has not been supplied yet. TradingView accepts menu * items without an icon, so those entries stay text-only. */ if ( exchange.icon ) { tradeItem.icon = exchange.icon; } items.push( tradeItem ); } ); /* * CoinsKid owner-only quick admin / setup links. * User ID 10 is deliberately the only account that sees these. */ const coinId = Number( meta.coinId || 0 ); if ( String(coinskidUserId) === CK_TRADE_OWNER_USER_ID && coinId > 0 ) { items.push({ title: 'Long setup', icon: ckTradeBadgeIcon('L'), onSelect: function () { ckTradeOpen( '/futures-crypto-blocks.html?tradetemplate=long&coin1=' + encodeURIComponent( String(coinId) ) ); } }); items.push({ title: 'Short setup', icon: ckTradeBadgeIcon('S'), onSelect: function () { ckTradeOpen( '/futures-crypto-blocks.html?tradetemplate=short&coin1=' + encodeURIComponent( String(coinId) ) ); } }); /*items.push({ title: 'Edit coin', icon: ckTradeBadgeIcon('E'), onSelect: function () { ckTradeOpen( '/?CoinIdEdit=' + encodeURIComponent( String(coinId) ) ); } });*/ } if ( items.length === 0 ) { items.push({ title: 'No trade links available', icon: ckTradeBadgeIcon('--'), onSelect: function () {} }); } return items; } function ckBuildTradeDropdownOptions( chart ) { const meta = ckGetCurrentTradeMeta( chart ); const coinLabel = meta && meta.baseCoin ? String(meta.baseCoin) : ''; return { title: 'Trade', tooltip: coinLabel !== '' ? 'Trade ' + coinLabel : 'Trade current market', icon: CK_TRADE_BUTTON_ICON, items: ckBuildTradeMenuItems( chart ) }; } function ckRefreshTradeDropdown( chart ) { if ( !window.ckTradeDropdown || typeof window.ckTradeDropdown.applyOptions !== 'function' ) { return; } try { window.ckTradeDropdown.applyOptions( ckBuildTradeDropdownOptions( chart ) ); } catch (error) { console.warn( '[CoinsKid] Could not refresh Trade dropdown:', error ); } } /* |-------------------------------------------------------------------------- | SYNC INITIAL MARKET HIGHLIGHT |-------------------------------------------------------------------------- | The PHP markup marks the first row active as a fallback. Once the | remembered ticker is known, immediately move the active state to the | actual ticker that TradingView is about to load. The mobile market | list is cloned later, so it inherits the correct active row too. */ document .querySelectorAll( '.ck-market-row' ) .forEach( function ( row ) { const rowSymbol = String( row.dataset.symbol || '' ) .replace( 'BINANCE:', '' ) .trim() .toUpperCase(); row .classList .toggle( 'is-active', rowSymbol === String(firstSymbol) .replace( 'BINANCE:', '' ) .trim() .toUpperCase() ); } ); /* |-------------------------------------------------------------------------- | KEEP ACTIVE MARKET VISIBLE |-------------------------------------------------------------------------- | Scroll ONLY the left Markets list so the selected ticker is brought | into view. This does not move the main page. */ function ckScrollActiveMarketIntoView() { const list = document.getElementById( 'lbList' ); if ( !list ) { return; } const activeRow = list.querySelector( '.ck-market-row.is-active' ); if ( !activeRow ) { return; } const targetTop = activeRow.offsetTop - ( list.clientHeight / 2 ) + ( activeRow.offsetHeight / 2 ); const maxScroll = Math.max( 0, list.scrollHeight - list.clientHeight ); list.scrollTop = Math.max( 0, Math.min( targetTop, maxScroll ) ); } /* * Run after the browser has painted the sidebar so its dimensions are * correct. A second short retry covers late fonts/images/layout. */ requestAnimationFrame( ckScrollActiveMarketIntoView ); setTimeout( ckScrollActiveMarketIntoView, 150 ); /* |-------------------------------------------------------------------------- | MARKET WATCHLIST |-------------------------------------------------------------------------- */ document .querySelectorAll( '#lbList .ck-market-watch-star' ) .forEach( ckWireMarketWatchStar ); document .querySelectorAll( '[data-ck-market-tab]' ) .forEach( function ( button ) { button.addEventListener( 'click', function ( event ) { event.preventDefault(); event.stopPropagation(); ckSetMarketListMode( button.dataset.ckMarketTab ); } ); } ); document .querySelectorAll( '[data-ck-market-sort]' ) .forEach( function ( button ) { button.addEventListener( 'click', function ( event ) { event.preventDefault(); event.stopPropagation(); ckSetMarketSortMode( button.dataset.ckMarketSort ); } ); } ); ckRefreshMarketWatchlistUI(); /* |-------------------------------------------------------------------------- | VIP ACTION |-------------------------------------------------------------------------- */ function requireVip() { if ( !isLoggedIn ) { window.location.href = "/login/login.html"; return false; } if ( !isVip ) { window.location.href = "/settings.html#premium"; return false; } return true; } /* * MOBILE MODE MUST BE WIDTH-BASED. * * The old max-height:600px rule incorrectly classified wide iPads, * split-screen browsers and shorter laptop windows as mobile. That * suppressed TradingView's desktop VIP Indicators dropdown even while * the page itself was using the desktop layout. */ const isMobileChart = window.matchMedia( '(max-width: 768px)' ).matches; /* * vip-loader.js exposes a Promise while the individual CoinsKid * indicator modules are loading. Wait for it before asking TradingView * for custom studies or building either VIP menu. Older cached loaders * without the Promise continue immediately for backwards compatibility. */ function ckWaitForVipIndicatorModules() { const pending = window.CoinsKidVIPModulesPromise; if ( pending && typeof pending.then === 'function' ) { return pending.catch( function ( error ) { console.warn( '[CoinsKid] VIP module wait warning:', error ); return null; } ); } return Promise.resolve( null ); } /* |-------------------------------------------------------------------------- | MOBILE CHART POSITION / SIZE |-------------------------------------------------------------------------- | Keep this deliberately simple. We only inspect normal site-header | selectors; we do NOT scan every fixed element on the page. */ function ckSizeMobileChart() { if ( !isMobileChart ) { return; } if ( document.body.classList.contains( 'ck-chart-fullscreen-mode' ) ) { return; } /* * PROFILE / HEATMAP MOBILE EMBEDS * * These pages already provide the iframe height. Do not apply the * old full-page mobile minimum-height/fullscreen-placeholder sizing * inside the iframe or the chart can overflow / leave a blank area. */ if ( document.documentElement.classList.contains( 'ck-supercharts-heatmap-embed' ) ) { const embedPane = document.getElementById( 'lbChartPane' ); const embedChartContainer = document.getElementById( 'tv_chart_container' ); if ( embedPane ) { embedPane.style.setProperty( 'height', '100%', 'important' ); embedPane.style.setProperty( 'min-height', '0', 'important' ); } if ( embedChartContainer ) { embedChartContainer.style.setProperty( 'height', '100%', 'important' ); embedChartContainer.style.setProperty( 'min-height', '0', 'important' ); embedChartContainer.style.setProperty( 'display', 'block', 'important' ); embedChartContainer.style.setProperty( 'visibility', 'visible', 'important' ); } return; } const headers = document.querySelectorAll( 'header, .header, #header, .navbar, .fixed-top, .navbar-fixed-top' ); let topOffset = 0; headers.forEach( function ( el ) { if ( !el ) { return; } const style = window.getComputedStyle( el ); const position = String( style.position || '' ).toLowerCase(); if ( position !== 'fixed' && position !== 'sticky' ) { return; } const rect = el.getBoundingClientRect(); if ( rect.top <= 10 && rect.bottom > 0 && rect.width > window.innerWidth * 0.5 ) { topOffset = Math.max( topOffset, Math.round( rect.bottom ) ); } } ); const section = document.querySelector( '.ck-advanced-section' ); if ( section ) { section.style.setProperty( 'padding-top', topOffset + 'px', 'important' ); } /* Leave a small safety gap at the bottom for the mobile browser UI / site footer so TradingView's bottom time axis is not cropped. */ const mobileBottomGap = 34; /* IMPORTANT: Do not overwrite --ck-header-bottom here. positionAdvancedChartBelowHeader() already measures the real CoinsKid navigation bottom, including non-fixed header wrappers. The mobile VIP menu uses that existing value. */ const chartHeight = Math.max( 500, window.innerHeight - topOffset - mobileBottomGap ); const chartContainer = document.getElementById( 'tv_chart_container' ); if ( chartContainer ) { chartContainer.style.setProperty( 'height', chartHeight + 'px', 'important' ); chartContainer.style.setProperty( 'min-height', chartHeight + 'px', 'important' ); chartContainer.style.setProperty( 'display', 'block', 'important' ); chartContainer.style.setProperty( 'visibility', 'visible', 'important' ); } } ckSizeMobileChart(); if ( isMobileChart ) { window.addEventListener( 'load', ckSizeMobileChart ); setTimeout( ckSizeMobileChart, 500 ); setTimeout( ckSizeMobileChart, 1500 ); } /* |-------------------------------------------------------------------------- | MOBILE FULLSCREEN CHART (BUTTON-TRIGGERED) |-------------------------------------------------------------------------- | The chart is NOT created on page load for mobile. Instead a | placeholder + button is shown. Tapping it: | 1) mounts the TradingView widget for the first time, | 2) requests real browser Fullscreen on #lbChartPane where | supported (this renders above EVERYTHING on the page, | including the site header, since it uses the browser's own | top layer rather than CSS z-index), | 3) falls back to a CSS fixed-viewport overlay (same visual | result) on browsers that don't support element Fullscreen | (notably iOS Safari), and also hides the header there as a | safety net. | Desktop is unaffected and still loads immediately, see | ckMountChart() below. */ function ckMobileViewportHeight() { if ( window.visualViewport && Number( window.visualViewport.height ) > 0 ) { return Math.round( window.visualViewport.height ); } return Math.round( window.innerHeight ); } function ckSizeFullscreenChart() { if ( !document.body.classList.contains( 'ck-chart-fullscreen-mode' ) ) { return; } const viewportHeight = ckMobileViewportHeight(); const pane = document.getElementById( 'lbChartPane' ); const chartContainer = document.getElementById( 'tv_chart_container' ); if ( pane ) { pane.style.setProperty( 'height', viewportHeight + 'px', 'important' ); pane.style.setProperty( 'min-height', '0px', 'important' ); } if ( chartContainer ) { chartContainer.style.setProperty( 'height', viewportHeight + 'px', 'important' ); chartContainer.style.setProperty( 'min-height', '0px', 'important' ); } /* TradingView autosize reacts to the resize event after layout has actually settled. */ setTimeout(function () { window.dispatchEvent(new Event('resize')); }, 80); setTimeout(function () { window.dispatchEvent(new Event('resize')); }, 300); } function ckRequestRealFullscreen(el) { const request = el.requestFullscreen || el.webkitRequestFullscreen || el.msRequestFullscreen; if ( !request ) { return false; } try { const result = request.call(el); if ( result && typeof result.catch === 'function' ) { result.catch(function () { /* CSS fallback is already applied either way. */ }); } return true; } catch (error) { return false; } } function ckExitRealFullscreen() { const exit = document.exitFullscreen || document.webkitExitFullscreen || document.msExitFullscreen; const activeFsEl = document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement; if ( exit && activeFsEl ) { try { exit.call(document); } catch (error) { /* nothing else to do */ } } } function enterChartFullscreen() { ckMountChart(); document.body.classList.add( 'ck-chart-fullscreen-mode' ); document.body.classList.add( 'ck-chart-loaded' ); const pane = document.getElementById( 'lbChartPane' ); if ( pane ) { ckRequestRealFullscreen(pane); } ckSizeFullscreenChart(); } function exitChartFullscreen() { document.body.classList.remove( 'ck-chart-fullscreen-mode' ); ckExitRealFullscreen(); const pane = document.getElementById( 'lbChartPane' ); const chartContainer = document.getElementById( 'tv_chart_container' ); if ( pane ) { pane.style.removeProperty('height'); pane.style.removeProperty('min-height'); } if ( chartContainer ) { chartContainer.style.removeProperty('height'); chartContainer.style.removeProperty('min-height'); } ckSizeMobileChart(); setTimeout(function () { window.dispatchEvent(new Event('resize')); }, 80); } if ( isMobileChart ) { const fullscreenBtn = document.getElementById( 'ckMobileFullscreenBtn' ); const fullscreenExitBtn = document.getElementById( 'ckChartFullscreenExit' ); if ( fullscreenBtn ) { fullscreenBtn.addEventListener( 'click', enterChartFullscreen ); } if ( fullscreenExitBtn ) { fullscreenExitBtn.addEventListener( 'click', exitChartFullscreen ); } /* Keep the immersive view correctly sized if the phone is rotated WHILE fullscreen is already open. This does not auto-enter or auto-exit fullscreen on its own. */ window.addEventListener( 'orientationchange', function () { setTimeout(ckSizeFullscreenChart, 120); } ); if ( window.visualViewport ) { window.visualViewport.addEventListener( 'resize', ckSizeFullscreenChart ); } /* If the user exits real Fullscreen using the browser/OS's own gesture (swipe, back button, etc.) rather than our exit button, make sure our CSS state stays in sync. */ function ckSyncRealFullscreenExit() { const stillFs = !!( document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement ); if ( !stillFs && document.body.classList.contains( 'ck-chart-fullscreen-mode' ) ) { exitChartFullscreen(); } } document.addEventListener( 'fullscreenchange', ckSyncRealFullscreenExit ); document.addEventListener( 'webkitfullscreenchange', ckSyncRealFullscreenExit ); } /* |-------------------------------------------------------------------------- | PER-TICKER DISABLED INDICATORS |-------------------------------------------------------------------------- | | Add more rules here at any time. | | Example: | | 'USDT': [ | 'CoinsKid Coinbase Premium Index', | 'Another Indicator' | ], | |-------------------------------------------------------------------------- */ const CK_DISABLED_INDICATORS_BY_SYMBOL = { 'USDT': [ 'CoinsKid Coinbase Premium Index' ] }; /* * Keep track of the symbol TradingView has actually resolved. */ window.ckCurrentSuperchartSymbol = String( firstSymbol || '' ) .replace( 'BINANCE:', '' ) .replace( 'COINSKID:', '' ) .trim() .toUpperCase(); function ckIndicatorRuleSymbolKey( symbol ) { let value = String( symbol || '' ) .replace( 'BINANCE:', '' ) .replace( 'COINSKID:', '' ) .trim() .toUpperCase(); /* * USDT Dominance aliases all map to one rule key. */ if ( value === 'USDT.D' || value === 'CRYPTOCAP:USDT.D' || value === 'USDTDOM' || value === 'USDTDOMINANCE' ) { value = 'USDT'; } return value; } function ckNormaliseIndicatorName( value ) { return String( value || '' ) .toLowerCase() .replace( /[^a-z0-9]+/g, ' ' ) .replace( /\s+/g, ' ' ) .trim(); } function ckIndicatorNameCandidates( item ) { const output = []; function add( value ) { if ( value === undefined || value === null ) { return; } const text = String( value ) .trim(); if ( text !== '' ) { output.push( text ); } } if ( typeof item === 'string' ) { add( item ); return output; } if ( !item || typeof item !== 'object' ) { return output; } add( item.name ); add( item.title ); add( item.text ); add( item.label ); add( item.description ); add( item.shortDescription ); if ( item.metainfo && typeof item.metainfo === 'object' ) { add( item.metainfo.id ); add( item.metainfo.name ); add( item.metainfo.description ); add( item.metainfo.shortDescription ); add( item.metainfo.scriptIdPart ); } return output; } function ckIsIndicatorDisabledForSymbol( item, symbol ) { const key = ckIndicatorRuleSymbolKey( symbol ); const disabled = CK_DISABLED_INDICATORS_BY_SYMBOL[ key ] || []; if ( !disabled.length ) { return false; } const candidates = ckIndicatorNameCandidates( item ); if ( !candidates.length ) { return false; } return disabled.some( function ( blockedName ) { const blocked = ckNormaliseIndicatorName( blockedName ); return candidates.some( function ( candidate ) { const candidateName = ckNormaliseIndicatorName( candidate ); return ( candidateName === blocked || candidateName.indexOf( blocked ) !== -1 ); } ); } ); } function ckGetActiveIndicatorRuleSymbol( chart ) { try { if ( chart && typeof chart.symbol === 'function' ) { const symbol = chart.symbol(); if ( symbol ) { return ckIndicatorRuleSymbolKey( symbol ); } } } catch ( error ) {} return ckIndicatorRuleSymbolKey( window.ckCurrentSuperchartSymbol || firstSymbol ); } function ckFilterDisabledIndicators( items, symbol ) { if ( !Array.isArray( items ) ) { return items; } return items.filter( function ( item ) { return !ckIsIndicatorDisabledForSymbol( item, symbol ); } ); } function ckFilterDisabledVipMenuItems( items, chart ) { if ( !Array.isArray( items ) ) { return items; } const symbol = ckGetActiveIndicatorRuleSymbol( chart ); return items .filter( function ( item ) { return !ckIsIndicatorDisabledForSymbol( item, symbol ); } ) .map( function ( item ) { /* * Also recurse through grouped/submenu items if a future * VIP menu uses them. */ if ( item && typeof item === 'object' && Array.isArray( item.items ) ) { const copy = Object.assign( {}, item ); copy.items = ckFilterDisabledVipMenuItems( item.items, chart ); return copy; } return item; } ); } function ckEnforceDisabledIndicators( chart ) { if ( !chart || typeof chart.getAllStudies !== 'function' || typeof chart.removeEntity !== 'function' ) { return; } const symbol = ckGetActiveIndicatorRuleSymbol( chart ); let studies = []; try { studies = chart.getAllStudies() || []; } catch ( error ) { return; } studies.forEach( function ( study ) { if ( !ckIsIndicatorDisabledForSymbol( study, symbol ) ) { return; } const id = study && ( study.id || study.entityId ); if ( !id ) { return; } try { chart.removeEntity( id ); console.log( '[CoinsKid] Disabled indicator removed for ' + symbol + ':', ckIndicatorNameCandidates( study )[0] || id ); } catch ( error ) { console.warn( '[CoinsKid] Could not remove disabled indicator:', error ); } } ); } function ckInstallDisabledIndicatorCreateStudyGuard( chart ) { if ( !chart || typeof chart.createStudy !== 'function' || chart.__ckDisabledIndicatorGuard ) { return; } const originalCreateStudy = chart.createStudy.bind( chart ); chart.createStudy = function ( studyName ) { const symbol = ckGetActiveIndicatorRuleSymbol( chart ); if ( ckIsIndicatorDisabledForSymbol( studyName, symbol ) ) { console.warn( '[CoinsKid] Indicator unavailable for ' + symbol + ': ' + studyName ); /* * TradingView createStudy() normally returns a Promise. * Resolve cleanly instead of throwing and breaking a * caller/VIP menu. */ return Promise.resolve( null ); } return originalCreateStudy.apply( chart, arguments ); }; chart.__ckDisabledIndicatorGuard = true; } function ckRefreshVipIndicatorDropdown( chart, refitFn ) { if ( !window.ckVipIndicatorsDropdown || typeof window.ckVipIndicatorsDropdown.applyOptions !== 'function' || !window.CoinsKidVIP || typeof window.CoinsKidVIP.getMenuItems !== 'function' ) { return; } try { const items = window.CoinsKidVIP .getMenuItems( chart, requireVip, typeof refitFn === 'function' ? refitFn : function () {} ); window.ckVipIndicatorsDropdown .applyOptions({ items: ckFilterDisabledVipMenuItems( items, chart ) }); } catch ( error ) { console.warn( '[CoinsKid] Could not refresh VIP indicator availability:', error ); } } /* |-------------------------------------------------------------------------- | MOUNT CHART (desktop: called immediately below. mobile: called once, | from enterChartFullscreen() above, on first button tap.) |-------------------------------------------------------------------------- */ let ckChartMounted = false; function ckMountChart() { if ( ckChartMounted ) { return; } /* |------------------------------------------------------------------ | NON-VIP SHARED VIEW = STATIC PNG ONLY |------------------------------------------------------------------ | Do not construct a live TradingView widget behind the snapshot. | VIP viewers never enter this branch. |------------------------------------------------------------------ */ if ( window.CK_SHARED_CHART && window.CK_SHARED_CHART.static_snapshot_only === true ) { ckChartMounted = true; document.body.classList.add( 'ck-chart-loaded' ); return; } ckChartMounted = true; document.body.classList.add('ck-chart-loaded'); /* |-------------------------------------------------------------------------- | OPTIONAL PARENT TIMEFRAME NOTIFIER |-------------------------------------------------------------------------- | Full Supercharts has no parent consumer, so this is a no-op there. | Profile embeds use it instead of polling the iframe. |-------------------------------------------------------------------------- */ function ckNotifyParentChartTimeframe( chart, suppliedResolution ) { if ( !window.parent || window.parent === window ) { return; } var currentResolution = suppliedResolution; try { if ( ( currentResolution === undefined || currentResolution === null || currentResolution === '' ) && chart && typeof chart.resolution === 'function' ) { currentResolution = chart.resolution(); } } catch (error) { currentResolution = ''; } if ( currentResolution && typeof currentResolution === 'object' ) { currentResolution = currentResolution.resolution || currentResolution.interval || currentResolution.timeframe || ''; } var rawResolution = String( currentResolution || '' ) .trim() .toUpperCase(); var tfMap = { '5':'5m', '5M':'5m', '15':'15m', '15M':'15m', '60':'1h', '1H':'1h', '240':'4h', '4H':'4h', 'D':'1d', '1D':'1d', '5D':'5d', 'W':'1w', '1W':'1w', '1M':'1mo', '1MO':'1mo' }; var profileTf = tfMap[ rawResolution ] || ''; if (!profileTf) { return; } try { if ( typeof window.parent .ckProfileTechnicalSummarySync === 'function' ) { window.parent .ckProfileTechnicalSummarySync( profileTf ); } } catch (directError) { } try { window.parent.postMessage( { type: 'ck-supercharts-timeframe-change', tf: profileTf, resolution: rawResolution }, window.location.origin ); } catch (messageError) { } } /* |-------------------------------------------------------------------------- | WIDGET OPTIONS |-------------------------------------------------------------------------- */ /* |-------------------------------------------------------------------------- | LIGHTWEIGHT EMBED BOOT |-------------------------------------------------------------------------- | | Full Supercharts intentionally restores the user's last saved chart. | Profile / heatmap / compact embeds must NOT do that. | | Restoring the full saved chart inside an iframe causes: | 1) saved timeframe loads first (often 1W) | 2) saved studies request deep history | 3) chart storage/autosave starts | 4) embed then switches to ckinterval (for example 4h) | 5) a second complete history load happens | | Start embeds directly on their requested timeframe instead. |-------------------------------------------------------------------------- */ const ckIsEmbeddedSuperchartsMode = false; const ckRequestedEmbedInterval = "240"; const widgetOptions = { container: "tv_chart_container", library_path: "https://cdn.coinskid.com/advanced-chart/charting_library-32.1.0/charting_library/", datafeed: CoinsKidDatafeed, symbol: firstSymbol, interval: ( ckIsSharedChart && window.CK_SHARED_CHART.timeframe ) ? String( window.CK_SHARED_CHART.timeframe ) : ( ckIsEmbeddedSuperchartsMode ? ckRequestedEmbedInterval : "240" ), locale: "en", timezone: "Etc/UTC", theme: ckGetSiteTheme(), autosize: true, fullscreen: false, debug: false, /* |-------------------------------------------------------------------------- | ACCOUNT-SYNCED USER SETTINGS |-------------------------------------------------------------------------- | TradingView drawing-tool defaults (last colour, line width, style, | favourites, etc.) live in user settings, not in saved drawings. | Logged-in users use MySQL instead of device-local localStorage. */ settings_adapter: ( isLoggedIn && !ckIsSharedChart ) ? { initialSettings: ckGetTradingViewInitialSettings(), setValue: function ( key, value ) { ckTvUserSettings[ key ] = value; ckSaveTradingViewUserSettings(); }, removeValue: function ( key ) { delete ckTvUserSettings[ key ]; ckSaveTradingViewUserSettings(); } } : undefined, /* |-------------------------------------------------------------------------- | FEATURES |-------------------------------------------------------------------------- */ enabled_features: [ "use_localstorage_for_settings", "save_chart_properties_to_local_storage", /* Turns on the star/favourite icon in the interval (timeframe) and indicator dialogs/toolbars. Without this, the toolbar shows but there is no way to actually star a timeframe. */ "items_favoriting", /* Show richer symbol info in the top-left TradingView legend, including symbol logos when the datafeed supplies logo_urls. */ "show_symbol_logos", "show_symbol_logo_in_legend", "symbol_info_long_description" ], disabled_features: isMobileChart ? [ "header_compare", "edit_buttons_in_legend", "context_menus", "control_bar", "border_around_the_chart" ] : [ "header_compare", ], /* |-------------------------------------------------------------------------- | VIP CUSTOM INDICATORS |-------------------------------------------------------------------------- */ custom_indicators_getter: function ( PineJS ) { return ckWaitForVipIndicatorModules() .then( function () { try { if ( typeof window.CoinsKidVIPIndicators !== "function" ) { console.error( "CoinsKidVIPIndicators loader missing" ); return []; } const indicators = window .CoinsKidVIPIndicators( PineJS ); return ckFilterDisabledIndicators( indicators, window.ckCurrentSuperchartSymbol ); } catch ( error ) { console.error( "VIP indicator loader failed:", error ); return []; } } ); }, /* |-------------------------------------------------------------------------- | CHART STYLE |-------------------------------------------------------------------------- */ overrides: { "paneProperties.background": ckGetSiteTheme() === "light" ? "#ffffff" : "#0f0f10", "paneProperties.backgroundType": "solid", "paneProperties.vertGridProperties.color": ckGetSiteTheme() === "light" ? "#e6e9ef" : "#1d1d20", "paneProperties.horzGridProperties.color": ckGetSiteTheme() === "light" ? "#e6e9ef" : "#1d1d20", /* Without this, the lines separating the price pane from indicator panes below it (RSI, Fear & Greed, etc.) fall back to TradingView's default light grey, which stands out sharply against this dark theme. */ "paneProperties.separatorColor": ckGetSiteTheme() === "light" ? "#d8dde6" : "#232326", "scalesProperties.textColor": ckGetSiteTheme() === "light" ? "#5f6878" : "#a9a9b2", /* Candles */ "mainSeriesProperties.candleStyle.upColor": "#26a69a", "mainSeriesProperties.candleStyle.downColor": "#ef5350", "mainSeriesProperties.candleStyle.borderUpColor": "#26a69a", "mainSeriesProperties.candleStyle.borderDownColor": "#ef5350", "mainSeriesProperties.candleStyle.wickUpColor": "#26a69a", "mainSeriesProperties.candleStyle.wickDownColor": "#ef5350", /* TradingView v32.1.0 fixes the v32.0.0 countdown repaint bug. Keep the native bar-close countdown explicitly enabled. */ "mainSeriesProperties.showCountdown": true, 'scalesProperties.showPriceScaleCrosshairLabel': true, 'scalesProperties.showTimeScaleCrosshairLabel': true, } }; /* |-------------------------------------------------------------------------- | CRYPTO PROFILE EMBED - HIDE SYMBOL SEARCH ONLY |-------------------------------------------------------------------------- | | The crypto profile already fixes the coin being viewed, so the | TradingView symbol/search control at the far left is unnecessary. | | ONLY applies when supercharts-widget.php was loaded with: | | ckembed=embed | | Full Supercharts, heatmap, compact and shared-chart behaviour remain | unchanged. |-------------------------------------------------------------------------- */ const ckIsCryptoProfileEmbed = false; if ( ckIsCryptoProfileEmbed ) { [ "header_symbol_search", "header_quick_search", "symbol_search_hot_key" ].forEach( function ( feature ) { if ( widgetOptions.disabled_features.indexOf( feature ) === -1 ) { widgetOptions.disabled_features.push( feature ); } } ); } /* Logged-in users must not fall back to per-device TradingView settings. The settings_adapter above is the source of truth for both desktop/mobile. */ if ( isLoggedIn ) { widgetOptions.disabled_features.push( "use_localstorage_for_settings" ); widgetOptions.disabled_features.push( "save_chart_properties_to_local_storage" ); widgetOptions.enabled_features = widgetOptions.enabled_features.filter( function ( feature ) { return ( feature !== "use_localstorage_for_settings" && feature !== "save_chart_properties_to_local_storage" ); } ); } /* |-------------------------------------------------------------------------- | SHARED CHART = VIEW-ONLY |-------------------------------------------------------------------------- | A shared URL is a clean presentation of the saved share. | Never let the viewer mix their own studies/drawings/layout into it. | | Pan/zoom remains available, but editing/personalisation controls are | removed. The shared symbol/timeframe and shared studies/drawings are | restored by chart-share.js. |-------------------------------------------------------------------------- */ if ( ckIsSharedChart ) { /* * Shared chart = clean presentation. * Hide TradingView's whole top-left legend/status block so: * - indicator names/values are not exposed * - the +/- collapse/dropdown arrow is not shown * - viewers cannot interact with studies through the legend */ widgetOptions.overrides[ "paneProperties.legendProperties.showLegend" ] = false; [ "left_toolbar", "header_indicators", "header_compare", "header_symbol_search", "header_resolutions", "header_saveload", "header_undo_redo", "header_settings", "symbol_search_hot_key", "context_menus", "property_pages", "show_object_tree", "edit_buttons_in_legend", "delete_button_in_legend", "show_hide_button_in_legend", "legend_inplace_edit", "legend_context_menu", /* * Shared charts are presentation-only, so suppress * TradingView's blue onboarding/help bubbles. */ "popup_hints" ].forEach( function ( feature ) { if ( widgetOptions.disabled_features.indexOf( feature ) === -1 ) { widgetOptions.disabled_features.push( feature ); } } ); /* * Do not let an enabled feature re-enable something above. */ widgetOptions.enabled_features = widgetOptions.enabled_features.filter( function ( feature ) { return ( widgetOptions.disabled_features.indexOf( feature ) === -1 ); } ); } /* |-------------------------------------------------------------------------- | SERVER STORAGE |-------------------------------------------------------------------------- */ if ( isLoggedIn && !ckIsSharedChart ) { widgetOptions.charts_storage_url = "https://www.coinskid.com/advanced-chart/storage"; widgetOptions.charts_storage_api_version = "1.1"; widgetOptions.client_id = "coinskid.com"; widgetOptions.user_id = coinskidUserId; /* * SAME SAVED "MY CHART" LAYOUT IN EVERY MODE * * Full Supercharts and embedded profile/heatmap charts must all * restore the same saved chart layout so the user's indicators, * panes and drawings are present everywhere. * * The embed context (coin + requested timeframe) is applied once * AFTER TradingView has restored that saved layout. */ widgetOptions.load_last_chart = true; widgetOptions.auto_save_delay = 2; /* * IMPORTANT: * Keep drawings inside the normal chart layout. * * The separate /drawings REST endpoint is intentionally NOT * enabled here. TradingView includes drawings in the saved chart * layout by default, which avoids the separate-drawings JSON * endpoint entirely and keeps drawings tied to the saved layout. */ widgetOptions.enabled_features = widgetOptions.enabled_features.filter( function ( feature ) { return ( feature !== "saveload_separate_drawings_storage" ); } ); widgetOptions.enabled_features.push( "study_templates" ); } /* |-------------------------------------------------------------------------- | APPLY EMBED CONTEXT AFTER SAVED CHART RESTORE |-------------------------------------------------------------------------- | | load_last_chart=true restores the exact same My Chart layout as the | full Supercharts page. Embedded pages then need only two contextual | overrides: | | 1) requested coin / market | 2) requested timeframe | | Do NOT recreate studies or load a clean chart here. |-------------------------------------------------------------------------- */ function ckNormaliseChartContextSymbol( value ) { return String( value || '' ) .replace( 'BINANCE:', '' ) .replace( 'COINSKID:', '' ) .replace( /[^A-Za-z0-9]/g, '' ) .trim() .toUpperCase(); } function ckApplyEmbeddedChartContext( chart ) { if ( !ckIsEmbeddedSuperchartsMode || !chart ) { return; } const requestedSymbol = ckNormaliseChartContextSymbol( firstSymbol ); const requestedResolution = String( ckRequestedEmbedInterval || '' ) .trim() .toUpperCase(); let currentSymbol = ''; let currentResolution = ''; try { if ( typeof chart.symbol === 'function' ) { currentSymbol = ckNormaliseChartContextSymbol( chart.symbol() ); } } catch ( symbolReadError ) {} try { if ( typeof chart.resolution === 'function' ) { currentResolution = String( chart.resolution() || '' ) .trim() .toUpperCase(); } } catch ( resolutionReadError ) {} console.info( '[CoinsKid] Embedded My Chart restored:', { savedSymbol: currentSymbol, requestedSymbol: requestedSymbol, savedResolution: currentResolution, requestedResolution: requestedResolution } ); function applyRequestedResolution() { if ( !requestedResolution ) { return; } let liveResolution = ''; try { if ( typeof chart.resolution === 'function' ) { liveResolution = String( chart.resolution() || '' ) .trim() .toUpperCase(); } } catch ( resolutionError ) {} if ( liveResolution === requestedResolution ) { return; } try { if ( typeof chart.setResolution === 'function' ) { chart.setResolution( requestedResolution ); } } catch ( setResolutionError ) { console.warn( '[CoinsKid] Embed timeframe apply failed:', setResolutionError ); } } /* * Apply the requested symbol only when the saved chart currently * points at a different market. The callback then applies the * requested timeframe after TradingView has committed the symbol. */ if ( requestedSymbol && currentSymbol !== requestedSymbol && typeof chart.setSymbol === 'function' ) { let callbackRan = false; try { chart.setSymbol( requestedSymbol, function () { callbackRan = true; applyRequestedResolution(); ckNotifyParentChartTimeframe( chart, null ); } ); /* * Charting Library builds differ slightly in callback * behaviour. This fallback does not create another symbol * change; it only finishes the timeframe step if needed. */ window.setTimeout( function () { if ( !callbackRan ) { applyRequestedResolution(); ckNotifyParentChartTimeframe( chart, null ); } }, 150 ); } catch ( setSymbolError ) { console.warn( '[CoinsKid] Embed symbol apply failed:', setSymbolError ); applyRequestedResolution(); } return; } /* * Saved chart is already on the requested symbol. */ applyRequestedResolution(); window.setTimeout( function () { ckNotifyParentChartTimeframe( chart, null ); }, 0 ); } /* |-------------------------------------------------------------------------- | CREATE CHART |-------------------------------------------------------------------------- */ window.tvWidget = new TradingView.widget( widgetOptions ); /* |-------------------------------------------------------------------------- | CHART READY |-------------------------------------------------------------------------- */ window.tvWidget.chartReady().then( function () { const chart = window.tvWidget .activeChart(); /* * Full Supercharts is already in its saved-chart context. * * Embeds restore that SAME saved layout first, then apply only * their requested coin/timeframe so saved indicators are not * wiped. */ if ( ckIsEmbeddedSuperchartsMode ) { ckApplyEmbeddedChartContext( chart ); } else { window.setTimeout( function () { ckNotifyParentChartTimeframe( chart, null ); }, 0 ); } /* |-------------------------------------------------------------------------- | DISABLED INDICATOR RULES |-------------------------------------------------------------------------- */ ckInstallDisabledIndicatorCreateStudyGuard( chart ); /* * Catch indicators restored internally by TradingView's saved * layout/indicator dialog, which can bypass public createStudy(). */ ckEnforceDisabledIndicators( chart ); window.ckDisabledIndicatorEnforceTimer = window.setInterval( function () { if ( ckGetActiveIndicatorRuleSymbol( chart ) === 'USDT' ) { ckEnforceDisabledIndicators( chart ); } }, 1000 ); /* |-------------------------------------------------------------------------- | RESTORE CURRENT THEME AFTER SAVED SETTINGS LOAD |-------------------------------------------------------------------------- | | The widget was already CREATED in the correct light/dark theme. | Only re-assert the pane/grid colours here. Do NOT call | changeTheme() on chart load because that causes a full TradingView | UI rebuild and was responsible for the lag/freezing. |-------------------------------------------------------------------------- */ ckApplyTradingViewOverridesOnly( ckGetSiteTheme() ); /* |-------------------------------------------------------------------------- | VIP INDICATORS MENU |-------------------------------------------------------------------------- */ if ( !ckIsSharedChart ) { ckWaitForVipIndicatorModules() .then( function () { return window.tvWidget .headerReady(); } ) .then( function () { if ( !window.CoinsKidVIP || typeof window.CoinsKidVIP.getMenuItems !== 'function' ) { throw new Error( 'CoinsKid VIP menu registry missing' ); } const vipMenuItems = window.CoinsKidVIP .getMenuItems( chart, requireVip, refitChart ); /* * VIP MENU DISPLAY NAMES * * Keep the real studyName / TradingView study IDs * unchanged for saved layouts and createStudy(). * Only remove the leading "CoinsKid " branding * from what the user sees in this dropdown. */ const displayVipMenuItems = ckFilterDisabledVipMenuItems( vipMenuItems, chart ); displayVipMenuItems.forEach( function ( item ) { if ( item && typeof item.title === 'string' ) { item.title = item.title.replace( /^CoinsKid\s+/i, '' ); } } ); /* * Mobile TradingView header: * Markets | VIP | Trade | Help */ if ( isMobileChart ) { ckCreateMobileMarketsHeaderButton(); } Promise.resolve( window.tvWidget .createDropdown({ title: isMobileChart ? "\u2B50 VIP" : "\u2B50 VIP Indicators", tooltip: "CoinsKid VIP Indicators", items: displayVipMenuItems }) ) .then( function ( dropdownApi ) { window.ckVipIndicatorsDropdown = dropdownApi || null; } ) .catch( function ( error ) { console.warn( '[CoinsKid] VIP dropdown API unavailable:', error ); } ); /* * Trade menu is deliberately created immediately AFTER * VIP Indicators so the two controls sit together. */ Promise.resolve( window.tvWidget .createDropdown( ckBuildTradeDropdownOptions( chart ) ) ) .then( function ( dropdownApi ) { window.ckTradeDropdown = dropdownApi || null; } ) .catch( function ( error ) { console.warn( '[CoinsKid] Trade dropdown API unavailable:', error ); } ); /* * Restore the native in-chart Help control beside Trade. * This does not create the floating Support/ticket button. */ ckCreateChartHelpButton(); } ) .catch( function ( error ) { console.error( "VIP menu failed:", error ); } ); } /* |-------------------------------------------------------------------------- | MOBILE MARKETS MENU |-------------------------------------------------------------------------- | Clones the existing desktop market rows into a touch-friendly | mobile panel. Selecting a row changes the same TradingView chart. */ if ( isMobileChart ) { const mobileMarketsTrigger = document.getElementById( 'ckMobileMarketsTrigger' ); const mobileMarketsPanel = document.getElementById( 'ckMobileMarketsPanel' ); const mobileMarketsBackdrop = document.getElementById( 'ckMobileMarketsBackdrop' ); const mobileMarketsList = document.getElementById( 'ckMobileMarketsList' ); const mobileMarketsSearch = document.getElementById( 'ckMobileMarketsSearch' ); function setMobileMarketsOpen( open ) { if ( mobileMarketsPanel ) { mobileMarketsPanel.classList.toggle( 'is-open', !!open ); } if ( mobileMarketsBackdrop ) { mobileMarketsBackdrop.classList.toggle( 'is-open', !!open ); } /* Never leave both mobile menus open together. */ if ( open ) { const vipPanel = document.getElementById( 'ckMobileVipPanel' ); const vipBackdrop = document.getElementById( 'ckMobileVipBackdrop' ); if (vipPanel) { vipPanel.classList.remove( 'is-open' ); } if (vipBackdrop) { vipBackdrop.classList.remove( 'is-open' ); } } } function buildMobileMarketsList() { if ( !mobileMarketsList ) { return; } mobileMarketsList.innerHTML = ''; document .querySelectorAll( '#lbList .ck-market-row' ) .forEach( function ( sourceRow ) { const row = sourceRow.cloneNode( true ); row.classList.remove( 'is-mobile-hidden' ); ckWireMarketWatchStar( row.querySelector( '.ck-market-watch-star' ) ); row.addEventListener( 'click', function () { const symbol = row.dataset.symbol; if ( !symbol ) { return; } /* * A ticker selected from a shared * chart exits view mode completely. */ if ( ckExitSharedViewToTicker( symbol ) ) { return; } document .querySelectorAll( '.ck-market-row' ) .forEach( function ( marketRow ) { marketRow.classList.remove( 'is-active' ); } ); /* Keep the source desktop row and cloned mobile row highlighted together. */ document .querySelectorAll( '.ck-market-row[data-symbol="' + CSS.escape(symbol) + '"]' ) .forEach( function ( marketRow ) { marketRow.classList.add( 'is-active' ); } ); try { window.tvWidget .activeChart() .setSymbol( symbol ); } catch ( error ) { console.error( 'Mobile symbol change failed:', error ); } setMobileMarketsOpen( false ); } ); mobileMarketsList.appendChild( row ); } ); } buildMobileMarketsList(); ckApplyMarketSort(); ckRefreshMarketWatchlistUI(); if ( mobileMarketsTrigger && mobileMarketsPanel ) { mobileMarketsTrigger.addEventListener( 'click', function () { setMobileMarketsOpen( !mobileMarketsPanel.classList.contains( 'is-open' ) ); } ); } if ( mobileMarketsBackdrop ) { mobileMarketsBackdrop.addEventListener( 'click', function () { setMobileMarketsOpen( false ); } ); } if ( mobileMarketsSearch ) { mobileMarketsSearch.addEventListener( 'input', function () { ckApplyMobileMarketFilter(); } ); } } /* |-------------------------------------------------------------------------- | MOBILE VIP MENU |-------------------------------------------------------------------------- | Do not use TradingView's native dropdown on phones. Its popup | can open too low in the viewport and is awkward to scroll. | This uses the same CoinsKidVIP registry as desktop but renders | it in a fixed, touch-scrollable panel below the site nav. */ if ( isMobileChart ) { const mobileVipTrigger = document.getElementById( 'ckMobileVipTrigger' ); const mobileVipPanel = document.getElementById( 'ckMobileVipPanel' ); const mobileVipBackdrop = document.getElementById( 'ckMobileVipBackdrop' ); function setMobileVipOpen( open ) { if ( open ) { const marketsPanel = document.getElementById( 'ckMobileMarketsPanel' ); const marketsBackdrop = document.getElementById( 'ckMobileMarketsBackdrop' ); if (marketsPanel) { marketsPanel.classList.remove( 'is-open' ); } if (marketsBackdrop) { marketsBackdrop.classList.remove( 'is-open' ); } } if ( mobileVipPanel ) { mobileVipPanel.classList.toggle( 'is-open', !!open ); } if ( mobileVipBackdrop ) { mobileVipBackdrop.classList.toggle( 'is-open', !!open ); } } if ( mobileVipTrigger && mobileVipPanel ) { ckWaitForVipIndicatorModules() .then( function () { try { const mobileVipItems = window.CoinsKidVIP.getMenuItems( chart, requireVip, refitChart ) || []; mobileVipPanel.innerHTML = ''; mobileVipItems.forEach( function ( item ) { if ( !item || !item.title ) { return; } const button = document.createElement( 'button' ); button.type = 'button'; button.textContent = item.title; button.addEventListener( 'click', function () { setMobileVipOpen( false ); if ( typeof item.onSelect === 'function' ) { item.onSelect(); } } ); mobileVipPanel.appendChild( button ); } ); mobileVipTrigger.addEventListener( 'click', function () { setMobileVipOpen( !mobileVipPanel.classList.contains( 'is-open' ) ); } ); if ( mobileVipBackdrop ) { mobileVipBackdrop.addEventListener( 'click', function () { setMobileVipOpen( false ); } ); } } catch ( error ) { console.error( 'Mobile VIP menu failed:', error ); } } ) .catch( function ( error ) { console.error( 'Mobile VIP module wait failed:', error ); } ); } } /* |-------------------------------------------------------------------------- | AUTO FIT / "A" MODE |-------------------------------------------------------------------------- */ function forceAutoFit() { try { const activeChart = window.tvWidget .activeChart(); if ( !activeChart || typeof activeChart.getPanes !== "function" ) { return; } const panes = activeChart .getPanes(); if ( !panes || !panes.length ) { return; } const mainPane = panes[0]; if ( !mainPane || typeof mainPane.getMainSourcePriceScale !== "function" ) { return; } const priceScale = mainPane .getMainSourcePriceScale(); if ( !priceScale || typeof priceScale.setAutoScale !== "function" ) { return; } priceScale .setAutoScale( true ); } catch ( error ) { console.log( "Auto fit skipped:", error ); } } /* |-------------------------------------------------------------------------- | AUTO FIT RETRIES |-------------------------------------------------------------------------- */ function refitChart() { forceAutoFit(); setTimeout( forceAutoFit, 100 ); setTimeout( forceAutoFit, 300 ); setTimeout( forceAutoFit, 700 ); setTimeout( forceAutoFit, 1500 ); } /* |-------------------------------------------------------------------------- | INITIAL FIT |-------------------------------------------------------------------------- */ refitChart(); setTimeout( refitChart, 2500 ); /* |-------------------------------------------------------------------------- | AUTOSAVE |-------------------------------------------------------------------------- | A shared snapshot is view-only with respect to the viewer's | private saved layout. It must not overwrite their last chart. */ if ( isLoggedIn && !ckIsSharedChart ) { /* * One shared, debounced save queue for normal TradingView * autosave events and drawing changes. * * Because separate drawing storage is disabled above, * saveChartToServer() includes drawings in the chart layout. */ let ckChartSaveTimer = null; let ckChartSaveRunning = false; let ckChartSaveAgain = false; async function ckSaveChartNow() { if ( ckChartSaveRunning ) { ckChartSaveAgain = true; return; } ckChartSaveRunning = true; try { await window.tvWidget .saveChartToServer({ defaultChartName: "My Chart" }); } catch ( error ) { console.error( "Chart save failed:", error ); } finally { ckChartSaveRunning = false; if ( ckChartSaveAgain ) { ckChartSaveAgain = false; ckQueueChartSave( 250 ); } } } function ckQueueChartSave( delay ) { clearTimeout( ckChartSaveTimer ); ckChartSaveTimer = setTimeout( ckSaveChartNow, typeof delay === "number" ? delay : 650 ); } window.tvWidget .subscribe( "onAutoSaveNeeded", function () { ckQueueChartSave( 250 ); } ); /* * Explicit drawing events make drawing persistence * immediate and independent of TradingView's autosave * debounce. Covers create/select actions plus move, * properties, hide/show and delete actions. */ window.tvWidget .subscribe( "drawing", function () { ckQueueChartSave( 650 ); } ); window.tvWidget .subscribe( "drawing_event", function () { ckQueueChartSave( 650 ); } ); } /* |-------------------------------------------------------------------------- | SYMBOL CHANGE |-------------------------------------------------------------------------- */ chart .onSymbolChanged() .subscribe( null, function ( symbolInfo ) { let current = symbolInfo.ticker || symbolInfo.name || ''; current = current .replace( 'BINANCE:', '' ) .replace( 'COINSKID:', '' ) .trim() .toUpperCase(); window.ckCurrentSuperchartSymbol = current; /* * Apply the hard-coded per-ticker availability * rules immediately after TradingView resolves the * new symbol. */ window.setTimeout( function () { ckEnforceDisabledIndicators( chart ); ckRefreshVipIndicatorDropdown( chart, refitChart ); ckRefreshTradeDropdown( chart ); }, 0 ); /* * Keep the visible URL tied to the exact ticker * TradingView successfully switched to. */ ckUpdateSuperchartCleanUrl( current ); /* * Remember the last ticker against the logged-in * CoinsKid account so the same ticker opens on * desktop and mobile. */ if ( isLoggedIn && current !== '' && ckTvUserSettings[ CK_LAST_SYMBOL_KEY ] !== current ) { ckTvUserSettings[ CK_LAST_SYMBOL_KEY ] = current; ckSaveTradingViewUserSettings(); } document .querySelectorAll( '.ck-market-row' ) .forEach( function ( row ) { row .classList .toggle( 'is-active', row.dataset.symbol .toUpperCase() === current ); } ); /* * Keep the selected ticker visible in the left * Markets list whenever TradingView changes symbol. */ requestAnimationFrame( ckScrollActiveMarketIntoView ); refitChart(); } ); /* |-------------------------------------------------------------------------- | TIMEFRAME CHANGE |-------------------------------------------------------------------------- */ chart .onIntervalChanged() .subscribe( null, function ( resolution ) { refitChart(); ckNotifyParentChartTimeframe( chart, resolution ); } ); /* |-------------------------------------------------------------------------- | WINDOW RESIZE |-------------------------------------------------------------------------- */ window.addEventListener( 'resize', function () { positionAdvancedChartBelowHeader(); if ( !document.body.classList.contains( 'ck-chart-fullscreen-mode' ) ) { ckSizeMobileChart(); } setTimeout( refitChart, 100 ); } ); } ); } // end ckMountChart() if ( !isMobileChart || document.documentElement.classList.contains( 'ck-supercharts-heatmap-embed' ) ) { /* * Full Supercharts keeps its existing mobile fullscreen launcher. * * Profile / heatmap / compact embeds are marked with * ck-supercharts-heatmap-embed BEFORE this runtime executes, so * they mount TradingView immediately on mobile. * * IMPORTANT: * Do not reference ckIsEmbeddedSuperchartsMode here because that * constant belongs to ckMountChart() scope. */ ckMountChart(); } /* |-------------------------------------------------------------------------- | MARKET CLICK |-------------------------------------------------------------------------- */ document .querySelectorAll( '.ck-market-row' ) .forEach( function ( row ) { row .addEventListener( 'click', function () { const symbol = this.dataset.symbol; if ( !symbol ) { return; } /* * SHARED VIEW: * Clicking another ticker exits the shared * snapshot completely and opens that ticker's * normal Supercharts page. */ if ( ckExitSharedViewToTicker( symbol ) ) { return; } /* Clear active market */ document .querySelectorAll( '.ck-market-row' ) .forEach( function ( marketRow ) { marketRow .classList .remove( 'is-active' ); } ); /* Activate selected market */ this .classList .add( 'is-active' ); /* Change chart */ try { window.tvWidget .activeChart() .setSymbol( symbol ); } catch ( error ) { console.error( "Symbol change failed:", error ); } } ); } ); /* |-------------------------------------------------------------------------- | SEARCH CLEAR BUTTONS |-------------------------------------------------------------------------- */ document .querySelectorAll( '.ck-market-search-clear' ) .forEach( function ( button ) { button.addEventListener( 'click', function ( event ) { event.preventDefault(); event.stopPropagation(); const targetId = button.getAttribute( 'data-search-target' ); const input = targetId ? document.getElementById( targetId ) : null; if ( !input ) { return; } input.value = ''; input.dispatchEvent( new Event( 'input', { bubbles: true } ) ); input.focus(); } ); } ); /* |-------------------------------------------------------------------------- | MARKET SEARCH |-------------------------------------------------------------------------- */ const marketSearch = document.getElementById( 'lbSearch' ); if ( marketSearch ) { marketSearch .addEventListener( 'input', function () { ckApplyDesktopMarketFilter(); } ); } } );

Top