CINXE.COM
Writing / Debugging
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><script> const url = window.location.href; const expectedUrl = url.replace( /^https:\/\/(?!beta)(\w+\.)?tradingview\.com/, 'https://www.tradingview.com', ); if (url !== expectedUrl) { window.location.replace(expectedUrl); } </script><meta name="astro-view-transitions-enabled" content="true"><meta name="astro-view-transitions-fallback" content="none"><link rel="icon" href="https://static.tradingview.com/static/images/favicon.ico"><link rel="icon" type="image/svg+xml" href="/pine-script-docs/favicon.svg"><title>Writing / Debugging</title><meta name="og:title" content="Writing / Debugging"><meta name="twitter:title" content="Writing / Debugging"><meta name="description" content="Everything you need to know about Pine Script™."><meta name="og:description" content="Everything you need to know about Pine Script™."><meta name="twitter:description" content="Everything you need to know about Pine Script™."><meta name="keywords" content="tradingview, pine, script, indicators, strategies"><meta name="og:image" content="/pine-script-docs/meta-image.png"><meta name="twitter:image" content="/pine-script-docs/meta-image.png"><meta name="og:image:width" content="1200"><meta name="og:image:height" content="630"><meta name="og:url" content="https://www.tradingview.com/pine-script-docs/writing/debugging/"><meta name="twitter:url" content="https://www.tradingview.com/pine-script-docs/writing/debugging/"><meta name="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:site" content="@TradingView"><link rel="canonical" href="https://www.tradingview.com/pine-script-docs/writing/debugging/"><link rel="sitemap" href="/pine-script-docs/sitemap-index.xml"><link rel="stylesheet" href="/pine-script-docs/_astro/index.CI8A0IeF.css"> <link rel="stylesheet" href="/pine-script-docs/_astro/index.BL2bgAvq.css"> <style>.tv-spinner{display:none;position:absolute;margin:0 auto;border:0 solid rgb(149 152 161 / 20%);border-radius:50%;border-top-color:var(--tv-spinner-color, #2962ff);border-left-color:var(--tv-spinner-color, #2962ff);animation:tv-spinner-container-rotate .9s linear infinite}.tv-spinner-shown{display:block}.tv-spinner-size-large{top:calc(50% - 32px);left:calc(50% - 32px);width:56px;height:56px;border-width:4px}@keyframes tv-spinner-container-rotate{to{transform:rotate(360deg)}}:root{--page-background-color: #fff;background-color:var(--page-background-color)}:root[data-theme=dark]{--page-background-color: #000}body{background-color:var(--page-background-color)}#redirect-link{display:flex;position:absolute;inset:0;align-items:center;justify-content:center}#spinner{display:block;position:absolute;opacity:1;transition:opacity .2s} .twitter-tweet:not(.twitter-tweet-rendered){padding:var(--tc-padding, 1em);border:1px solid var(--tc-border-color, #cfd9de)}.twitter-tweet:not(.twitter-tweet-rendered)>:first-child{margin-top:0}.twitter-tweet:not(.twitter-tweet-rendered)>:last-child{margin-bottom:0}lite-youtube{background-color:#000;position:relative;display:block;contain:content;background-position:center center;background-size:cover;cursor:pointer;max-width:720px}lite-youtube:before{content:attr(data-title);display:block;position:absolute;top:0;background-image:linear-gradient(180deg,#000000ab,#0000008a 14%,#00000026 54%,#0000000d 72%,#0000 94%);height:99px;width:100%;font-family:YouTube Noto,Roboto,Arial,Helvetica,sans-serif;color:#eee;text-shadow:0 0 2px rgba(0,0,0,.5);font-size:18px;padding:25px 20px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;box-sizing:border-box}lite-youtube:hover:before{color:#fff}lite-youtube:after{content:"";display:block;padding-bottom:56.25%}lite-youtube>iframe{width:100%;height:100%;position:absolute;top:0;left:0;border:0}lite-youtube>.lty-playbtn{display:block;width:100%;height:100%;background:no-repeat center/68px 48px;background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 68 48"><path d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z" fill="red"/><path d="M45 24 27 14v20" fill="white"/></svg>');position:absolute;cursor:pointer;z-index:1;filter:grayscale(100%);transition:filter .1s cubic-bezier(0,0,.2,1);border:0}lite-youtube:hover>.lty-playbtn,lite-youtube .lty-playbtn:focus{filter:none}lite-youtube.lyt-activated{cursor:unset}lite-youtube.lyt-activated:before,lite-youtube.lyt-activated>.lty-playbtn{opacity:0;pointer-events:none}.lyt-visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}lite-youtube>iframe{all:unset!important;width:100%!important;height:100%!important;position:absolute!important;inset:0!important;border:0!important}lite-vimeo{font-size:10px;background-color:#000;position:relative;display:block;contain:content;background-position:center center;background-size:cover}lite-vimeo:after{content:"";display:block;padding-bottom:56.25%}lite-vimeo>iframe{all:unset!important;width:100%!important;height:100%!important;position:absolute!important;inset:0!important;border:0!important}lite-vimeo>.ltv-playbtn{content:"";position:absolute;inset:0;width:100%;background:transparent;outline:0;border:0;cursor:pointer}lite-vimeo>.ltv-playbtn:before{width:6.5em;height:4em;background:#172322bf;opacity:.8;border-radius:.25rem;transition:all .2s cubic-bezier(0,0,.2,1)}lite-vimeo>.ltv-playbtn:focus:before{outline:auto}lite-vimeo:hover>.ltv-playbtn:before{background-color:#00adef;background-color:var(--ltv-color, #00adef);opacity:1}lite-vimeo>.ltv-playbtn:after{border-style:solid;border-width:1em 0 1em 1.7em;border-color:transparent transparent transparent #fff}lite-vimeo>.ltv-playbtn:before,lite-vimeo>.ltv-playbtn:after{content:"";position:absolute;top:50%;left:50%;transform:translate3d(-50%,-50%,0)}lite-vimeo.ltv-activated:before,lite-vimeo.ltv-activated>.ltv-playbtn{cursor:unset;opacity:0;pointer-events:none} </style><script type="module" src="/pine-script-docs/_astro/hoisted.yX2nbPMa.js"></script></head> <body> <div id="search-content-blur" hidden></div> <script> /* eslint-disable @typescript-eslint/typedef */ window.ThemeProvider = (() => { function getCurrent() { return ( // eslint-disable-next-line no-restricted-syntax typeof localStorage !== 'undefined' && localStorage.getItem('tv-docs-theme') ); } const storedTheme = getCurrent(); const theme = storedTheme || (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'); document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark'; document.documentElement.classList.toggle( 'theme-dark', theme === 'dark', ); // add support for ui-lib themes document.documentElement.classList.toggle( 'sl-theme-dark', theme === 'dark', ); // add support for shoelace themes return { updatePickers(themeArg = storedTheme || 'auto') { let currentTheme = themeArg; if (currentTheme === 'unknown') { currentTheme = getCurrent() || 'auto'; } document .querySelectorAll('docs-theme-select') .forEach((picker) => { const select = picker.querySelector('select'); if (select) select.value = currentTheme; /** @type {HTMLTemplateElement | null} */ const tmpl = document.querySelector(`#theme-icons`); const newIcon = tmpl && tmpl.content.querySelector('.' + currentTheme); if (newIcon) { const oldIcon = picker.querySelector('svg.label-icon'); if (oldIcon) { oldIcon.replaceChildren( ...newIcon.cloneNode(true).childNodes, ); } } }); }, }; })(); /* eslint-enable @typescript-eslint/typedef */ </script><template id="theme-icons"><svg width="16" height="16" viewBox="0 0 28 28" class="light" data-icon="theme/sun-28"> <symbol id="ai:local:theme/sun-28"><g fill="currentColor"><path d="M14 3h1.5v5H14V3Zm0 18h1.5v5H14v-5Zm12-5.5V14h-5v1.5h5ZM8 14v1.5H3V14h5Zm15.3-7-1-1-3.6 3.6 1.1 1 3.5-3.5ZM9.5 18.7l1.1 1.1-3.5 3.5-1-1 3.4-3.6ZM22 23.3l1-1-3.6-3.6-1 1.1 3.5 3.5ZM10.3 9.6l-1.1 1-3.5-3.5 1-1 3.6 3.5Z"/><path fill-rule="evenodd" d="M19 14.5a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0Zm-1.5 0a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" clip-rule="evenodd"/></g></symbol><use xlink:href="#ai:local:theme/sun-28"></use> </svg><svg width="16" height="16" viewBox="0 0 28 28" class="dark" data-icon="theme/moon-28"> <symbol id="ai:local:theme/moon-28"><path fill="currentColor" fill-rule="evenodd" d="M21 7.02A9.23 9.23 0 0 0 15.2 5 9.1 9.1 0 0 0 6 14c0 4.97 4.12 9 9.2 9a9.33 9.33 0 0 0 5.8-2.02A7 7 0 0 1 14.36 14 7 7 0 0 1 21 7.02Zm-3.95-.3a7.91 7.91 0 0 0-1.85-.22A7.6 7.6 0 0 0 7.5 14a7.6 7.6 0 0 0 7.7 7.5 8 8 0 0 0 1.85-.22A8.46 8.46 0 0 1 12.86 14c0-3.1 1.69-5.8 4.19-7.28Z" clip-rule="evenodd"/></symbol><use xlink:href="#ai:local:theme/moon-28"></use> </svg><svg width="16" height="16" viewBox="0 0 28 28" class="auto" data-icon="theme/system-28"> <symbol id="ai:local:theme/system-28"><path fill="currentColor" d="M8 4h1v2H8V4Zm0 9v2h1v-2H8Zm6-3V9h-2v1h2ZM3 9v1h2V9H3Zm5.5 3a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Zm4.2-6-.7-.7-1.4 1.4.7.7L12.7 6ZM5 13.7l-.7-.7 1.4-1.4.7.7L5 13.7Zm7.7-.7-.7.7-1.4-1.4.7-.7 1.4 1.4ZM4.3 6l.7-.7 1.4 1.4-.7.7L4.3 6Zm3 17 14-14 .8.7L8 23.7l-.7-.7Zm17.2-.1a3.5 3.5 0 0 1-3.4-5.9H21a4 4 0 1 0 3.5 5.9Z"/></symbol><use xlink:href="#ai:local:theme/system-28"></use> </svg></template> <div class="backdrop" data-mobile-menu-backdrop data-astro-cid-h2irkosh></div> <div class="menu-container" data-astro-cid-h2irkosh> <div class="header" data-astro-cid-h2irkosh> <div class="header-group" data-astro-cid-h2irkosh> <div id="version-select" data-astro-cid-kx7qoxgq> <label style="--sl-select-width: undefined; --sl-label-icon-size: 16px;" data-astro-cid-lmznfliq> <span class="sr-only" data-astro-cid-lmznfliq>Version</span> <select value="v6" data-has-border no-icon="true" data-astro-cid-lmznfliq> <option value="v6" selected="true" data-astro-cid-lmznfliq>Version 6</option><option value="v5" data-astro-cid-lmznfliq>Version 5</option><option value="v4" data-astro-cid-lmznfliq>Version 4</option><option value="v3" data-astro-cid-lmznfliq>Version 3</option> </select> <svg width="16" height="16" viewBox="0 0 24 24" class="icon caret" data-astro-cid-lmznfliq data-icon="theme/down-caret"> <symbol id="ai:local:theme/down-caret"><path fill="currentColor" d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></symbol><use xlink:href="#ai:local:theme/down-caret"></use> </svg> </label> </div> <docs-theme-select class="" data-astro-cid-3wpspbi7> <label style="--sl-select-width: 48px; --sl-label-icon-size: 28px;" data-astro-cid-lmznfliq> <span class="sr-only" data-astro-cid-lmznfliq>Theme</span> <svg width="28" height="28" viewBox="0 0 28 28" class="icon label-icon" data-button data-round data-astro-cid-lmznfliq data-icon="theme/system-28"> <use xlink:href="#ai:local:theme/system-28"></use> </svg> <select value="auto" data-button data-astro-cid-lmznfliq> <option value="dark" data-astro-cid-lmznfliq> Dark </option><option value="light" data-astro-cid-lmznfliq> Light </option><option value="auto" selected="true" data-astro-cid-lmznfliq> Auto </option> </select> </label> </docs-theme-select> <script> ThemeProvider.updatePickers('unknown'); </script> </div> <div class="header-group" data-astro-cid-h2irkosh> <div class="not-content" style="stroke-width:2px" data-astro-cid-pkzv2hgs> <button id="mobile-menu-back-button" title="Close menu" data-astro-cid-pkzv2hgs class="not-content stvb-base stvb-pointer stvb-gray stvb-medium stvb-primary stvb-icon"> <svg width="28" height="28" viewBox="0 0 28 28" data-astro-cid-h2irkosh data-icon="theme/arrow-back"> <symbol id="ai:local:theme/arrow-back"><g fill="none"><g clip-path="url(#a)"><path stroke="var(--arrow-fill-color, #131722)" d="m17 20-6-6 6-6"/></g><defs><clipPath id="a"><path fill="#fff" d="M28 28H0V0h28z"/></clipPath></defs></g></symbol><use xlink:href="#ai:local:theme/arrow-back"></use> </svg> </button> </div> </div> </div> <aside id="nav" class="keep-visible" style="--navbar-right-border-width: 0px" data-astro-cid-sa57sq6l> <div class="sidebar-viewport slick-scroll" data-astro-cid-sa57sq6l> <div class="sidebar" data-mobile data-astro-cid-sa57sq6l> <ul class="toc" aria-label="Docs sidebar" data-astro-cid-sa57sq6l> <li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/welcome" data-astro-cid-omxx3dey>Welcome to Pine Script™ v6</a></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Pine Script™ primer</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/primer/first-steps" data-astro-cid-omxx3dey>First steps</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/primer/first-indicator" data-astro-cid-omxx3dey>First indicator</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/primer/next-steps" data-astro-cid-omxx3dey>Next steps</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Language</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/execution-model" data-astro-cid-omxx3dey>Execution model</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/time-series" data-astro-cid-omxx3dey>Time series</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/script-structure" data-astro-cid-omxx3dey>Script structure</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/identifiers" data-astro-cid-omxx3dey>Identifiers</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/operators" data-astro-cid-omxx3dey>Operators</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/variable-declarations" data-astro-cid-omxx3dey>Variable declarations</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/conditional-structures" data-astro-cid-omxx3dey>Conditional structures</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/loops" data-astro-cid-omxx3dey>Loops</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/type-system" data-astro-cid-omxx3dey>Type system</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/built-ins" data-astro-cid-omxx3dey>Built-ins</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/user-defined-functions" data-astro-cid-omxx3dey>User-defined functions</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/objects" data-astro-cid-omxx3dey>Objects</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/enums" data-astro-cid-omxx3dey>Enums</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/methods" data-astro-cid-omxx3dey>Methods</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/arrays" data-astro-cid-omxx3dey>Arrays</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/matrices" data-astro-cid-omxx3dey>Matrices</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/maps" data-astro-cid-omxx3dey>Maps</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Concepts</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/alerts" data-astro-cid-omxx3dey>Alerts</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/backgrounds" data-astro-cid-omxx3dey>Backgrounds</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/bar-coloring" data-astro-cid-omxx3dey>Bar coloring</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/bar-plotting" data-astro-cid-omxx3dey>Bar plotting</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/bar-states" data-astro-cid-omxx3dey>Bar states</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/chart-information" data-astro-cid-omxx3dey>Chart information</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/colors" data-astro-cid-omxx3dey>Colors</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/fills" data-astro-cid-omxx3dey>Fills</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/inputs" data-astro-cid-omxx3dey>Inputs</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/levels" data-astro-cid-omxx3dey>Levels</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/libraries" data-astro-cid-omxx3dey>Libraries</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/lines-and-boxes" data-astro-cid-omxx3dey>Lines and boxes</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/non-standard-charts-data" data-astro-cid-omxx3dey>Non-standard charts data</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/other-timeframes-and-data" data-astro-cid-omxx3dey>Other timeframes and data</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/plots" data-astro-cid-omxx3dey>Plots</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/repainting" data-astro-cid-omxx3dey>Repainting</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/sessions" data-astro-cid-omxx3dey>Sessions</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/strategies" data-astro-cid-omxx3dey>Strategies</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/tables" data-astro-cid-omxx3dey>Tables</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/text-and-shapes" data-astro-cid-omxx3dey>Text and shapes</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/time" data-astro-cid-omxx3dey>Time</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/timeframes" data-astro-cid-omxx3dey>Timeframes</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><details open data-is-parent data-is-on-path data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Writing scripts</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/style-guide" data-astro-cid-omxx3dey>Style guide</a></li><li class="item" data-current data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/debugging" data-astro-cid-omxx3dey>Debugging</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/profiling-and-optimization" data-astro-cid-omxx3dey>Profiling and optimization</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/publishing" data-astro-cid-omxx3dey>Publishing scripts</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/limitations" data-astro-cid-omxx3dey>Limitations</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>FAQ</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/general" data-astro-cid-omxx3dey>General</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/alerts" data-astro-cid-omxx3dey>Alerts</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/data-structures" data-astro-cid-omxx3dey>Data structures</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/functions" data-astro-cid-omxx3dey>Functions</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/indicators" data-astro-cid-omxx3dey>Indicators</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/other-data-and-timeframes" data-astro-cid-omxx3dey>Other data and timeframes</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/programming" data-astro-cid-omxx3dey>Programming</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/strings-and-formatting" data-astro-cid-omxx3dey>Strings and formatting</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/error-messages" data-astro-cid-omxx3dey>Error messages</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/release-notes" data-astro-cid-omxx3dey>Release notes</a></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Migration guides</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/migration-guides/to-pine-version-6" data-astro-cid-omxx3dey>To Pine Script™ version 6</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/migration-guides/to-pine-version-5" data-astro-cid-omxx3dey>To Pine Script™ version 5</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/migration-guides/to-pine-version-4" data-astro-cid-omxx3dey>To Pine Script™ version 4</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/migration-guides/to-pine-version-3" data-astro-cid-omxx3dey>To Pine Script™ version 3</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/where-can-i-get-more-information" data-astro-cid-omxx3dey>Where can I get more information?</a></li> </ul> <div class="toc-bottom" data-astro-cid-sa57sq6l></div> </div> </div> </aside> </div> <header class="header" data-astro-cid-d74r2unp> <nav role="navigation" aria-label="Main Navigation" data-astro-cid-d74r2unp> <mobile-menu-button id="mobile-menu-button-wc" data-astro-cid-oojooh3d> <!-- Annoyingly I need to wrap this. TODO: improve this --> <div id="mobile-menu-button-header" data-astro-cid-oojooh3d> <div class="not-content" style="" data-astro-cid-pkzv2hgs> <button title="Open navigation menu" data-astro-cid-pkzv2hgs class="not-content stvb-base stvb-pointer stvb-gray stvb-medium stvb-secondary stvb-icon stvb-icon-force-color stvb-force-no-border"> <svg width="28" height="28" viewBox="0 0 24 24" data-astro-cid-oojooh3d data-icon="theme/bars"> <symbol id="ai:local:theme/bars"><path fill="currentColor" d="M3 8h18a1 1 0 1 0 0-2H3a1 1 0 0 0 0 2Zm18 8H3a1 1 0 0 0 0 2h18a1 1 0 0 0 0-2Zm0-5H3a1 1 0 0 0 0 2h18a1 1 0 0 0 0-2Z"/></symbol><use xlink:href="#ai:local:theme/bars"></use> </svg> </button> </div> </div> </mobile-menu-button> <div data-hide-when-search data-astro-cid-d74r2unp> <div class="header-logo" data-astro-cid-tycb33lk> <a href="/pine-script-docs/" aria-label="Home button" data-astro-cid-tycb33lk> <div class="documentation-logo logo" data-astro-cid-tycb33lk><svg width="188" height="44" viewBox="0 0 188 44" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M26.9989 28.0001L18.4281 20.7531L11.3382 23.2611C10.402 23.5923 9.60771 22.5041 10.2085 21.7134L21.0877 7.39502C21.4749 6.88536 22.2346 6.86567 22.6478 7.35459L34.7627 21.6923C35.1531 22.1543 35.0472 22.8544 34.5376 23.1802L26.9989 28.0001ZM32.4978 22.1105L27.1641 25.5207L19.7195 19.2258C19.1767 18.7669 18.4312 18.6305 17.7611 18.8676L13.8245 20.2602L21.9253 9.59841L32.4978 22.1105Z" fill="currentColor"/> <path d="M33.432 28.0842L38.3592 34.7471C38.7427 35.2657 38.3724 36 37.7274 36H6.27248C5.62746 36 5.25722 35.2657 5.64074 34.7471L10.8523 27.6996C10.9484 27.5697 11.0822 27.4725 11.2356 27.4214L17.6878 25.2707C17.9285 25.1904 18.1932 25.2314 18.3984 25.3806L26.2854 31.1166C26.5445 31.3051 26.8922 31.3173 27.1639 31.1475L32.3838 27.885C32.7316 27.6677 33.1881 27.7544 33.432 28.0842Z" fill="currentColor"/> <path d="M59.56 13.96C63.016 13.96 65.536 16.456 65.536 19.696C65.536 22.936 63.016 25.432 59.56 25.432H57.376V31H53.896V13.96H59.56ZM59.512 22.168C61.096 22.168 62.152 21.088 62.152 19.696C62.152 18.304 61.096 17.224 59.512 17.224H57.376V22.168H59.512ZM70.8636 14.944C70.8636 16.096 69.9276 17.032 68.7516 17.032C67.6236 17.032 66.6636 16.096 66.6636 14.944C66.6636 13.792 67.6236 12.856 68.7516 12.856C69.9276 12.856 70.8636 13.792 70.8636 14.944ZM67.1196 31V19H70.4076V31H67.1196ZM73.0849 31V19H76.3729V20.368C76.9969 19.408 78.2449 18.736 79.8049 18.736C82.7089 18.736 84.4369 20.848 84.4369 23.968V31H81.1489V24.52C81.1489 22.792 80.4049 21.736 79.0369 21.736C77.5249 21.736 76.3729 22.84 76.3729 25.144V31H73.0849ZM86.2041 25C86.2041 21.448 88.8681 18.736 92.5161 18.736C95.6601 18.736 98.4201 20.752 98.4201 24.64C98.4201 24.928 98.4201 25.264 98.3721 25.768H89.3961C89.5881 27.376 91.0041 28.264 92.5881 28.264C94.0761 28.264 95.1561 27.568 95.6841 26.752L98.1321 28.576C97.0281 30.184 95.0841 31.264 92.5641 31.264C88.9881 31.264 86.2041 28.792 86.2041 25ZM92.4201 21.448C91.1961 21.448 89.8281 22.072 89.5161 23.536H95.1321C94.8441 22.12 93.6441 21.448 92.4201 21.448ZM104.412 28.24L107.076 26.008C107.916 27.28 109.38 28.024 110.772 28.024C112.14 28.024 113.052 27.352 113.052 26.368C113.052 25.408 112.356 24.736 110.676 24.16L109.236 23.656C106.5 22.696 105.036 21.112 105.036 18.784C105.036 15.568 107.484 13.672 110.796 13.672C112.884 13.672 114.708 14.392 116.172 16.024L113.868 18.4C113.052 17.416 111.996 16.936 110.82 16.936C109.644 16.936 108.54 17.44 108.54 18.448C108.54 19.48 109.38 19.936 111.18 20.584L112.548 21.088C115.044 22 116.604 23.584 116.604 26.152C116.58 29.2 114.156 31.288 110.628 31.288C107.916 31.288 105.636 30.112 104.412 28.24ZM129.859 27.808C128.827 29.872 126.667 31.264 124.171 31.264C120.619 31.264 117.811 28.624 117.811 25C117.811 21.376 120.619 18.736 124.171 18.736C126.667 18.736 128.827 20.128 129.859 22.192L127.003 23.728C126.523 22.624 125.491 21.808 124.171 21.808C122.443 21.808 121.123 23.152 121.123 25C121.123 26.848 122.443 28.192 124.171 28.192C125.491 28.192 126.523 27.376 127.003 26.272L129.859 27.808ZM131.482 31V19H134.77V20.92C135.178 19.744 136.402 18.856 137.746 18.856C138.082 18.856 138.442 18.88 138.85 19V22.336C138.346 22.168 137.89 22.072 137.362 22.072C135.802 22.072 134.77 23.296 134.77 25.264V31H131.482ZM144.215 14.944C144.215 16.096 143.279 17.032 142.103 17.032C140.975 17.032 140.015 16.096 140.015 14.944C140.015 13.792 140.975 12.856 142.103 12.856C143.279 12.856 144.215 13.792 144.215 14.944ZM140.471 31V19H143.759V31H140.471ZM146.436 36.016V19H149.724V20.344C150.276 19.576 151.548 18.736 153.204 18.736C156.396 18.736 158.844 21.592 158.844 25C158.844 28.408 156.396 31.264 153.204 31.264C151.548 31.264 150.276 30.424 149.724 29.656V36.016H146.436ZM155.508 25C155.508 23.128 154.284 21.736 152.484 21.736C150.684 21.736 149.46 23.128 149.46 25C149.46 26.872 150.684 28.264 152.484 28.264C154.284 28.264 155.508 26.872 155.508 25ZM168.407 30.88C167.879 31.048 167.231 31.144 166.319 31.144C163.775 31.144 161.735 29.728 161.735 26.8V21.88H159.311V19H161.735V15.664H165.023V19H168.407V21.88H165.023V26.152C165.023 27.616 165.647 28.192 167.063 28.192C167.591 28.192 168.023 28.12 168.407 27.976V30.88ZM177.626 22.648V13.96H179.978L181.874 16.888L183.746 13.96H186.122V22.648H183.698V18.184L181.874 20.968L180.026 18.136V22.648H177.626ZM171.386 22.648V16.456H169.058V13.96H176.258V16.456H173.93V22.648H171.386Z" fill="currentColor"/> </svg> </div> </a> </div> </div> <div class="flex" data-astro-cid-d74r2unp></div> <div class="flex" data-astro-cid-d74r2unp> <div class="search-container" data-astro-cid-fg37foga> <div class="search-wrapper" data-astro-cid-fg37foga> <input class="search-input" type="text" placeholder="Search docs" name="s" value="" data-astro-cid-fg37foga> <svg width="28" height="28" viewBox="0 0 28 28" class="search-button" data-astro-cid-fg37foga data-icon="theme/search"> <symbol id="ai:local:theme/search"><path fill="currentColor" fill-rule="evenodd" d="M18.5 12.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0Zm-1.25 5.8a7.5 7.5 0 1 1 1.06-1.06l4.22 4.23.53.53L22 23.06l-.53-.53-4.22-4.22Z" clip-rule="evenodd"/></symbol><use xlink:href="#ai:local:theme/search"></use> </svg> <button class="search-clear" type="button" title="Reset" data-search-clear data-astro-cid-fg37foga>Clear</button> <span class="divider" data-astro-cid-fg37foga></span> <button class="search-close" type="button" title="Close" data-search-close data-astro-cid-fg37foga> <svg width="18" height="18" viewBox="0 0 18 18" data-astro-cid-fg37foga data-icon="theme/cross-18"> <use xlink:href="#ai:local:theme/cross-18"></use> </svg> </button> </div> <div id="search-results-wrapper" data-astro-cid-fg37foga> <aside id="search-results" hidden data-astro-cid-fg37foga> <!-- Don't use h1 because when built it will be used as the first heading on the page --> <div class="heading" data-astro-cid-fg37foga>Search results</div> <div id="search-results-contents" data-astro-cid-fg37foga></div> </aside> </div> </div> </div> <ul class="links" data-astro-cid-d74r2unp> </ul> <div class="flex" data-astro-cid-d74r2unp></div> <div data-hide-when-search data-astro-cid-d74r2unp> <div id="version-select" data-hideable="true" data-astro-cid-kx7qoxgq> <label style="--sl-select-width: undefined; --sl-label-icon-size: 16px;" data-astro-cid-lmznfliq> <span class="sr-only" data-astro-cid-lmznfliq>Version</span> <select value="v6" data-has-border no-icon="true" data-astro-cid-lmznfliq> <option value="v6" selected="true" data-astro-cid-lmznfliq>Version 6</option><option value="v5" data-astro-cid-lmznfliq>Version 5</option><option value="v4" data-astro-cid-lmznfliq>Version 4</option><option value="v3" data-astro-cid-lmznfliq>Version 3</option> </select> <svg width="16" height="16" viewBox="0 0 24 24" class="icon caret" data-astro-cid-lmznfliq data-icon="theme/down-caret"> <use xlink:href="#ai:local:theme/down-caret"></use> </svg> </label> </div> </div> <button id="search-button" data-astro-cid-6zeqadij> <svg width="28" height="28" viewBox="0 0 28 28" data-astro-cid-6zeqadij data-icon="theme/search"> <use xlink:href="#ai:local:theme/search"></use> </svg> </button> <script data-base-url="/pine-script-docs"> async function loadPageFind() { const base = document.currentScript.getAttribute('data-base-url'); const pageFindBundleUrl = `${base}/pagefind/`; const pagefind = await import(`${pageFindBundleUrl}pagefind.js`); await pagefind.options({ bundlePath: pageFindBundleUrl, }); window.pagefind = pagefind; } loadPageFind().catch(); </script> <docs-theme-select class="hide-with-breakpoint-568" data-astro-cid-3wpspbi7> <label style="--sl-select-width: 48px; --sl-label-icon-size: 28px;" data-astro-cid-lmznfliq> <span class="sr-only" data-astro-cid-lmznfliq>Theme</span> <svg width="28" height="28" viewBox="0 0 28 28" class="icon label-icon" data-button data-round data-astro-cid-lmznfliq data-icon="theme/system-28"> <use xlink:href="#ai:local:theme/system-28"></use> </svg> <select value="auto" data-button data-astro-cid-lmznfliq> <option value="dark" data-astro-cid-lmznfliq> Dark </option><option value="light" data-astro-cid-lmznfliq> Light </option><option value="auto" selected="true" data-astro-cid-lmznfliq> Auto </option> </select> </label> </docs-theme-select> <script> ThemeProvider.updatePickers('unknown'); </script> </nav> </header> <div id="image-lightbox" class="not-content" hidden data-astro-cid-kws7taxh> <div class="button-wrapper" data-astro-cid-kws7taxh> <div class="not-content" style="" data-astro-cid-pkzv2hgs> <button id="lightbox-close-button" title="Close image preview" data-astro-cid-pkzv2hgs class="not-content stvb-base stvb-pointer stvb-black stvb-medium stvb-secondary stvb-icon stvb-force-no-border"> <svg width="24" height="24" viewBox="0 0 18 18" data-astro-cid-kws7taxh data-icon="theme/cross-18"> <symbol id="ai:local:theme/cross-18"><g fill="none"><g clip-path="url(#a)"><path fill="currentColor" fill-rule="evenodd" d="M5.53 4.47 4.47 5.53 7.94 9l-3.47 3.47 1.06 1.06L9 10.06l3.47 3.47 1.06-1.06L10.06 9l3.47-3.47-1.06-1.06L9 7.94 5.53 4.47Z" clip-rule="evenodd"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h18v18H0z"/></clipPath></defs></g></symbol><use xlink:href="#ai:local:theme/cross-18"></use> </svg> </button> </div> </div> <img id="lightbox-image" src="" data-astro-cid-kws7taxh> </div> <div id="page-container" data-astro-cid-xgirumru> <aside id="nav" class="" style="" data-astro-cid-sa57sq6l> <div class="sidebar-viewport slick-scroll" data-astro-cid-sa57sq6l> <div class="sidebar" data-astro-cid-sa57sq6l> <ul class="toc" aria-label="Docs sidebar" data-astro-cid-sa57sq6l> <li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/welcome" data-astro-cid-omxx3dey>Welcome to Pine Script™ v6</a></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Pine Script™ primer</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <symbol id="ai:local:theme/right-caret"><path fill="currentColor" d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></symbol><use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/primer/first-steps" data-astro-cid-omxx3dey>First steps</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/primer/first-indicator" data-astro-cid-omxx3dey>First indicator</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/primer/next-steps" data-astro-cid-omxx3dey>Next steps</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Language</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/execution-model" data-astro-cid-omxx3dey>Execution model</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/time-series" data-astro-cid-omxx3dey>Time series</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/script-structure" data-astro-cid-omxx3dey>Script structure</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/identifiers" data-astro-cid-omxx3dey>Identifiers</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/operators" data-astro-cid-omxx3dey>Operators</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/variable-declarations" data-astro-cid-omxx3dey>Variable declarations</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/conditional-structures" data-astro-cid-omxx3dey>Conditional structures</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/loops" data-astro-cid-omxx3dey>Loops</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/type-system" data-astro-cid-omxx3dey>Type system</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/built-ins" data-astro-cid-omxx3dey>Built-ins</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/user-defined-functions" data-astro-cid-omxx3dey>User-defined functions</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/objects" data-astro-cid-omxx3dey>Objects</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/enums" data-astro-cid-omxx3dey>Enums</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/methods" data-astro-cid-omxx3dey>Methods</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/arrays" data-astro-cid-omxx3dey>Arrays</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/matrices" data-astro-cid-omxx3dey>Matrices</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/language/maps" data-astro-cid-omxx3dey>Maps</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Concepts</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/alerts" data-astro-cid-omxx3dey>Alerts</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/backgrounds" data-astro-cid-omxx3dey>Backgrounds</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/bar-coloring" data-astro-cid-omxx3dey>Bar coloring</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/bar-plotting" data-astro-cid-omxx3dey>Bar plotting</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/bar-states" data-astro-cid-omxx3dey>Bar states</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/chart-information" data-astro-cid-omxx3dey>Chart information</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/colors" data-astro-cid-omxx3dey>Colors</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/fills" data-astro-cid-omxx3dey>Fills</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/inputs" data-astro-cid-omxx3dey>Inputs</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/levels" data-astro-cid-omxx3dey>Levels</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/libraries" data-astro-cid-omxx3dey>Libraries</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/lines-and-boxes" data-astro-cid-omxx3dey>Lines and boxes</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/non-standard-charts-data" data-astro-cid-omxx3dey>Non-standard charts data</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/other-timeframes-and-data" data-astro-cid-omxx3dey>Other timeframes and data</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/plots" data-astro-cid-omxx3dey>Plots</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/repainting" data-astro-cid-omxx3dey>Repainting</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/sessions" data-astro-cid-omxx3dey>Sessions</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/strategies" data-astro-cid-omxx3dey>Strategies</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/tables" data-astro-cid-omxx3dey>Tables</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/text-and-shapes" data-astro-cid-omxx3dey>Text and shapes</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/time" data-astro-cid-omxx3dey>Time</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/concepts/timeframes" data-astro-cid-omxx3dey>Timeframes</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><details open data-is-parent data-is-on-path data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Writing scripts</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/style-guide" data-astro-cid-omxx3dey>Style guide</a></li><li class="item" data-current data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/debugging" data-astro-cid-omxx3dey>Debugging</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/profiling-and-optimization" data-astro-cid-omxx3dey>Profiling and optimization</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/publishing" data-astro-cid-omxx3dey>Publishing scripts</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/writing/limitations" data-astro-cid-omxx3dey>Limitations</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>FAQ</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/general" data-astro-cid-omxx3dey>General</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/alerts" data-astro-cid-omxx3dey>Alerts</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/data-structures" data-astro-cid-omxx3dey>Data structures</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/functions" data-astro-cid-omxx3dey>Functions</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/indicators" data-astro-cid-omxx3dey>Indicators</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/other-data-and-timeframes" data-astro-cid-omxx3dey>Other data and timeframes</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/programming" data-astro-cid-omxx3dey>Programming</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/faq/strings-and-formatting" data-astro-cid-omxx3dey>Strings and formatting</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/error-messages" data-astro-cid-omxx3dey>Error messages</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/release-notes" data-astro-cid-omxx3dey>Release notes</a></li><li class="item" data-astro-cid-omxx3dey><details data-astro-cid-omxx3dey><summary data-astro-cid-omxx3dey><div class="summary-link" data-astro-cid-omxx3dey>Migration guides</div><div class="caret" data-astro-cid-omxx3dey><svg width="18" height="18" viewBox="0 0 24 24" class="icon" data-astro-cid-omxx3dey data-icon="theme/right-caret"> <use xlink:href="#ai:local:theme/right-caret"></use> </svg></div></summary><ul class="children" data-astro-cid-omxx3dey><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/migration-guides/to-pine-version-6" data-astro-cid-omxx3dey>To Pine Script™ version 6</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/migration-guides/to-pine-version-5" data-astro-cid-omxx3dey>To Pine Script™ version 5</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/migration-guides/to-pine-version-4" data-astro-cid-omxx3dey>To Pine Script™ version 4</a></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/migration-guides/to-pine-version-3" data-astro-cid-omxx3dey>To Pine Script™ version 3</a></li></ul></details></li><li class="item" data-astro-cid-omxx3dey><a class="page-link" href="/pine-script-docs/where-can-i-get-more-information" data-astro-cid-omxx3dey>Where can I get more information?</a></li> </ul> <div class="toc-bottom" data-astro-cid-sa57sq6l></div> </div> </div> </aside> <main class="main-pane" data-page-type="md" data-astro-cid-xgirumru> <a id="top" data-astro-cid-xgirumru></a> <main class="content" data-toc-shown data-astro-cid-ju3wuhkz> <div class="content-width" data-astro-cid-xgirumru> <div class="breadcrumbs" data-pagefind-ignore data-astro-cid-wlavna2o> <a href="/pine-script-docs" aria-label="Return back to the documentation home page." data-astro-cid-wlavna2o> <span data-astro-cid-wlavna2o>User Manual</span> </a> <span class="divider" data-astro-cid-wlavna2o>/</span> <a href="/pine-script-docs/writing/style-guide" data-astro-cid-wlavna2o>Writing scripts</a> <span class="divider" data-astro-cid-wlavna2o>/</span> <span class="current-item" data-astro-cid-wlavna2o>Debugging</span> </div> </div> <div id="slot-container" data-astro-cid-xgirumru> <h1 id="debugging" class="md-heading"><a href="#debugging">Debugging<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h1> <h2 id="introduction" class="md-heading"><a href="#introduction">Introduction<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <p>TradingView’s close integration between the Pine Editor and the chart interface facilitates efficient, interactive debugging of Pine Script™ code, as scripts can produce dynamic results in multiple locations, on and off the chart. Programmers can utilize such results to refine their script’s behaviors and ensure everything works as expected.</p> <p>When a programmer understands the appropriate techniques for inspecting the variety of behaviors one may encounter while writing a script, they can quickly and thoroughly identify and resolve potential problems in their code, which allows for a more seamless overall coding experience. This page demonstrates some of the handiest ways to debug code when working with Pine Script™.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>Before venturing further on this page, we recommend familiarizing yourself with Pine’s <a href="/pine-script-docs/language/execution-model/">Execution model</a> and <a href="/pine-script-docs/language/type-system/">Type system</a>, as it’s crucial to understand these details when debugging in the Pine Script™ environment.</p></div></aside> <h2 id="the-lay-of-the-land" class="md-heading"><a href="#the-lay-of-the-land">The lay of the land<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <p>Pine scripts can output their results in multiple different ways, any of which programmers can utilize for debugging.</p> <p>The <code dir="auto">plot*()</code> functions can display results in a chart pane, the script’s status line, the price (y-axis) scale, and the Data Window, providing simple, convenient ways to debug numeric and conditional values:</p> <p><img src="/pine-script-docs/_astro/Debugging-The-lay-of-the-land-1.BMFtSmLt_rnRYW.webp" alt="image" width="1342" height="590" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("The lay of the land - Plots") // Plot the `bar_index` in all available locations. plot(bar_index, "bar_index", color.teal, 3)</div> <p>Note that:</p> <ul> <li>A script’s status line outputs will only show when enabling the “Values” checkbox within the “Indicators” section of the chart’s “Status line” settings.</li> <li>Price scales will only show plot values or names when enabling the options from the “Indicators and financials” dropdown in the chart’s “Scales and lines” settings.</li> </ul> <p>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">bgcolor()</a> function displays colors in the script pane’s background, and the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_barcolor">barcolor()</a> function changes the colors of the main chart’s bars or candles. Both of these functions provide a simple way to visualize conditions:</p> <p><img src="/pine-script-docs/_astro/Debugging-The-lay-of-the-land-2.Dt_T7jt8_Zx7tBv.webp" alt="image" width="1342" height="556" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("The lay of the land - Background and bar colors") //@variable Is `true` if the `close` is rising over 2 bars. bool risingPrice = ta.rising(close, 2) // Highlight the chart background and color the main chart bars based on `risingPrice`. bgcolor(risingPrice ? color.new(color.green, 70) : na, title= "`risingPrice` highlight") barcolor(risingPrice ? color.aqua : chart.bg_color, title = "`risingPrice` bar color")</div> <p>Pine’s <a href="/pine-script-docs/language/type-system/#drawing-types">drawing types</a> (<a href="/pine-script-docs/concepts/lines-and-boxes/#lines">line</a>, <a href="/pine-script-docs/concepts/lines-and-boxes/#boxes">box</a>, <a href="/pine-script-docs/concepts/lines-and-boxes/#polylines">polyline</a>, <a href="/pine-script-docs/concepts/text-and-shapes/#labels">label</a>) produce drawings in the script’s pane. While they don’t return results in other locations, such as the status line or Data Window, they provide alternative, flexible solutions for inspecting numeric values, conditions, and strings directly on the chart:</p> <p><img src="/pine-script-docs/_astro/Debugging-The-lay-of-the-land-3.BR7JNYrd_Z2s1rX.webp" alt="image" width="1342" height="562" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("The lay of the land - Drawings", overlay = true) //@variable Is `true` when the time changes on the "1D" timeframe. bool newDailyBar = timeframe.change("1D") //@variable The previous bar's `bar_index` from when `newDailyBar` last occurred. int closedIndex = ta.valuewhen(newDailyBar, bar_index - 1, 0) //@variable The previous bar's `close` from when `newDailyBar` last occurred. float closedPrice = ta.valuewhen(newDailyBar, close[1], 0) if newDailyBar //@variable Draws a line from the previous `closedIndex` and `closedPrice` to the current values. line debugLine = line.new(closedIndex[1], closedPrice[1], closedIndex, closedPrice, width = 2) //@variable Variable info to display in a label. string debugText = "'1D' bar closed at: \n(" + str.tostring(closedIndex) + ", " + str.tostring(closedPrice) + ")" //@variable Draws a label at the current `closedIndex` and `closedPrice`. label.new(closedIndex, closedPrice, debugText, color = color.purple, textcolor = color.white)</div> <p>The <code dir="auto">log.*()</code> functions produce <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> results. Every time a script calls any of these functions, the script logs a message in the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> pane, along with a timestamp and navigation options to identify the specific times, chart bars, and lines of code that triggered a log:</p> <p><img src="/pine-script-docs/_astro/Debugging-The-lay-of-the-land-4.fSt39wX6_2urrNy.webp" alt="image" width="1342" height="666" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("The lay of the land - Pine Logs") //@variable The natural logarithm of the current `high - low` range. float logRange = math.log(high - low) // Plot the `logRange`. plot(logRange, "logRange") if barstate.isconfirmed // Generate an "error" or "info" message on the confirmed bar, depending on whether `logRange` is defined. switch na(logRange) => log.error("Undefined `logRange` value.") => log.info("`logRange` value: " + str.tostring(logRange)) else // Generate a "warning" message for unconfirmed values. log.warning("Unconfirmed `logRange` value: " + str.tostring(logRange))</div> <p>One can apply any of the above, or a combination, to establish debugging routines to fit their needs and preferences, depending on the data types and structures they’re working with. See the sections below for detailed explanations of various debugging techniques.</p> <h2 id="numeric-values" class="md-heading"><a href="#numeric-values">Numeric values<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <p>When creating code in Pine Script™, working with numbers is inevitable. Therefore, to ensure a script works as intended, it’s crucial to understand how to inspect the numeric (<a href="/pine-script-docs/language/type-system/#int">int</a> and <a href="/pine-script-docs/language/type-system/#float">float</a>) values it receives and calculates.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>This section discusses fundamental <em>chart-based</em> approaches for debugging numbers. Scripts can also convert numbers to <a href="/pine-script-docs/language/type-system/#string">strings</a>, allowing one to inspect numbers using string-related techniques. For more information, see the <a href="/pine-script-docs/writing/debugging/#strings">Strings</a> and <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> sections.</p></div></aside> <h3 id="plotting-numbers" class="md-heading"><a href="#plotting-numbers">Plotting numbers<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>One of the most straightforward ways to inspect a script’s numeric values is to use <code dir="auto">plot*()</code> functions, which can display results graphically on the chart and show formatted numbers in the script’s status line, the price scale, and the Data Window. The locations where a <code dir="auto">plot*()</code> function displays its results depend on the <code dir="auto">display</code> parameter. By default, its value is <a href="https://www.tradingview.com/pine-script-reference/v6/#const_display.all">display.all</a>.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>Only a script’s <em>global scope</em> can contain <code dir="auto">plot*()</code> calls, meaning these functions can only accept global variables and literals. They cannot use variables declared from the local scopes of <a href="/pine-script-docs/language/loops/">loops</a>, <a href="/pine-script-docs/language/conditional-structures/">conditional structures</a>, or <a href="/pine-script-docs/language/user-defined-functions/">user-defined functions</a> and <a href="/pine-script-docs/language/methods/#user-defined-methods">methods</a>.</p></div></aside> <p>The following example uses the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plot">plot()</a> function to display the 1-bar change in the value of the built-in <a href="https://www.tradingview.com/pine-script-reference/v6/#var_time">time</a> variable measured in chart timeframes (e.g., a plotted value of 1 on the “1D” chart means there is a one-day difference between the opening times of the current and previous bars). Inspecting this series can help to identify time gaps in a chart’s data, which is helpful information when designing time-based indicators.</p> <p>Since we have not specified a <code dir="auto">display</code> argument, the function uses <a href="https://www.tradingview.com/pine-script-reference/v6/#const_display.all">display.all</a>, meaning it will show data in <em>all</em> possible locations, as we see below:</p> <p><img src="/pine-script-docs/_astro/Debugging-Numeric-values-Plotting-numbers-1.CPWsJyU1_26SArq.webp" alt="image" width="1342" height="590" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Plotting numbers demo", "Time changes") //@variable The one-bar change in the chart symbol's `time` value, measured in units of the chart timeframe. float timeChange = ta.change(time) / (1000.0 * timeframe.in_seconds()) // Display the `timeChange` in all possible locations. plot(timeChange, "Time difference (in chart bar units)", color.purple, 3)</div> <p>Note that:</p> <ul> <li>The numbers displayed in the script’s status line and the Data Window reflect the plotted values at the location of the chart’s cursor. These areas will show the latest bar’s value when the mouse pointer isn’t on the chart.</li> <li>The number in the price scale reflects the latest available value on the visible chart.</li> </ul> <h4 id="without-affecting-the-scale" class="md-heading"><a href="#without-affecting-the-scale">Without affecting the scale<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h4> <p>When debugging multiple numeric values in a script, programmers may wish to inspect them without interfering with the price scales or cluttering the visual outputs in the chart’s pane, as distorted scales and overlapping plots may make it harder to evaluate the results.</p> <p>A simple way to inspect numbers without adding more visuals to the chart’s pane is to change the <code dir="auto">display</code> values in the script’s <code dir="auto">plot*()</code> calls to other <code dir="auto">display.*</code> variables or expressions using them.</p> <p>Let’s look at a practical example. Here, we’ve drafted the following script that calculates a custom-weighted moving average by dividing the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_math.sum">sum</a> of <code dir="auto">weight * close</code> values by the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_math.sum">sum</a> of the <code dir="auto">weight</code> series:</p> <p><img src="/pine-script-docs/_astro/Debugging-Numeric-values-Plotting-numbers-Without-affecting-the-scale-1.D9lHNsXL_mUjuG.webp" alt="image" width="1342" height="558" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Plotting without affecting the scale demo", "Weighted Average", true) //@variable The number of bars in the average. int lengthInput = input.int(20, "Length", 1) //@variable The weight applied to the price on each bar. float weight = math.pow(close - open, 2) //@variable The numerator of the average. float numerator = math.sum(weight * close, lengthInput) //@variable The denominator of the average. float denominator = math.sum(weight, lengthInput) //@variable The `lengthInput`-bar weighted average. float average = numerator / denominator // Plot the `average`. plot(average, "Weighted Average", linewidth = 3)</div> <p>Suppose we’d like to inspect the variables used in the <code dir="auto">average</code> calculation to understand and fine-tune the result. If we were to use <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plot">plot()</a> to display the script’s <code dir="auto">weight</code>, <code dir="auto">numerator</code>, and <code dir="auto">denominator</code> in all locations, we can no longer easily identify our <code dir="auto">average</code> line on the chart since each variable has a radically different scale:</p> <p><img src="/pine-script-docs/_astro/Debugging-Numeric-values-Plotting-numbers-Without-affecting-the-scale-2.CNBE_Mtb_2rATc4.webp" alt="image" width="1342" height="558" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Plotting without affecting the scale demo", "Weighted Average", true) //@variable The number of bars in the average. int lengthInput = input.int(20, "Length", 1) //@variable The weight applied to the price on each bar. float weight = math.pow(close - open, 2) //@variable The numerator of the average. float numerator = math.sum(close * weight, lengthInput) //@variable The denominator of the average. float denominator = math.sum(weight, lengthInput) //@variable The `lengthInput`-bar weighted average. float average = numerator / denominator // Plot the `average`. plot(average, "Weighted Average", linewidth = 3) // Create debug plots for the `weight`, `numerator`, and `denominator`. plot(weight, "weight", color.purple) plot(numerator, "numerator", color.teal) plot(denominator, "denominator", color.maroon)</div> <p>While we could hide individual plots from the “Style” tab of the script’s settings, doing so also prevents us from inspecting the results in any other location. To simultaneously view the variables’ values and preserve the scale of our chart, we can change the <code dir="auto">display</code> values in our debug plots.</p> <p>The version below includes a <code dir="auto">debugLocations</code> variable in the debug <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plot">plot()</a> calls with a value of <code dir="auto">display.all - display.pane</code> to specify that all locations <em>except</em> the chart pane will show the results. Now we can inspect the calculation’s values without the extra clutter:</p> <p><img src="/pine-script-docs/_astro/Debugging-Numeric-values-Plotting-numbers-Without-affecting-the-scale-3.iomfmsC__26l9R3.webp" alt="image" width="1342" height="558" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Plotting without affecting the scale demo", "Weighted Average", true) //@variable The number of bars in the average. int lengthInput = input.int(20, "Length", 1) //@variable The weight applied to the price on each bar. float weight = math.pow(close - open, 2) //@variable The numerator of the average. float numerator = math.sum(close * weight, lengthInput) //@variable The denominator of the average. float denominator = math.sum(weight, lengthInput) //@variable The `lengthInput`-bar weighted average. float average = numerator / denominator // Plot the `average`. plot(average, "Weighted Average", linewidth = 3) //@variable The display locations of all debug plots. debugLocations = display.all - display.pane // Create debug plots for the `weight`, `numerator`, and `denominator`. plot(weight, "weight", color.purple, display = debugLocations) plot(numerator, "numerator", color.teal, display = debugLocations) plot(denominator, "denominator", color.maroon, display = debugLocations)</div> <h4 id="from-local-scopes" class="md-heading"><a href="#from-local-scopes">From local scopes<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h4> <p>A script’s <em>local scopes</em> are sections of indented code within <a href="/pine-script-docs/language/conditional-structures/">conditional structures</a>, <a href="/pine-script-docs/language/user-defined-functions/">functions</a>, and <a href="/pine-script-docs/language/methods/#user-defined-methods">methods</a>. When working with variables declared within these scopes, using the <code dir="auto">plot*()</code> functions to display their values directly <em>will not</em> work, as plots only work with literals and <em>global</em> variables.</p> <p>To display a local variable’s values using plots, one can assign its results to a global variable and pass that variable to the <code dir="auto">plot*()</code> call.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>The approach described below works for local variables declared within <a href="/pine-script-docs/language/conditional-structures/">conditional structures</a>. Employing a similar process for <a href="/pine-script-docs/language/user-defined-functions/">functions</a> and <a href="/pine-script-docs/language/methods/#user-defined-methods">methods</a> requires <a href="/pine-script-docs/language/type-system/#collections">collections</a>, <a href="/pine-script-docs/language/type-system/#user-defined-types">user-defined types</a>, or other built-in reference types. See the <a href="/pine-script-docs/writing/debugging/#debugging-functions">Debugging functions</a> section for more information.</p></div></aside> <p>For example, this script calculates the all-time maximum and minimum change in the <a href="https://www.tradingview.com/pine-script-reference/v6/#var_close">close</a> price over a <code dir="auto">lengthInput</code> period. It uses an <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structure to declare a local <code dir="auto">change</code> variable and update the global <code dir="auto">maxChange</code> and <code dir="auto">minChange</code> once every <code dir="auto">lengthInput</code> bars:</p> <p><img src="/pine-script-docs/_astro/Debugging-Numeric-values-Plotting-numbers-From-local-scopes-1.DEllI76K_2tIueB.webp" alt="image" width="1342" height="554" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Plotting numbers from local scopes demo", "Periodic changes") //@variable The number of chart bars in each period. int lengthInput = input.int(20, "Period length", 1) //@variable The maximum `close` change over each `lengthInput` period on the chart. var float maxChange = na //@variable The minimum `close` change over each `lengthInput` period on the chart. var float minChange = na //@variable Is `true` once every `lengthInput` bars. bool periodClose = bar_index % lengthInput == 0 if periodClose //@variable The change in `close` prices over `lengthInput` bars. float change = close - close[lengthInput] // Update the global `maxChange` and `minChange`. maxChange := math.max(nz(maxChange, change), change) minChange := math.min(nz(minChange, change), change) // Plot the `maxChange` and `minChange`. plot(maxChange, "Max periodic change", color.teal, 3) plot(minChange, "Min periodic change", color.maroon, 3) hline(0.0, color = color.gray, linestyle = hline.style_solid)</div> <p>Suppose we want to inspect the history of the <code dir="auto">change</code> variable using a plot. While we cannot plot the variable directly since the script declares it in a local scope, we can assign its value to another <em>global</em> variable for use in a <code dir="auto">plot*()</code> function.</p> <p>Below, we’ve added a <code dir="auto">debugChange</code> variable with an initial value of <a href="https://www.tradingview.com/pine-script-reference/v6/#var_na">na</a> to the global scope, and the script reassigns its value within the <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structure using the local <code dir="auto">change</code> variable. Now, we can use <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plot">plot()</a> with the <code dir="auto">debugChange</code> variable to view the history of available <code dir="auto">change</code> values:</p> <p><img src="/pine-script-docs/_astro/Debugging-Numeric-values-Plotting-numbers-From-local-scopes-2.CPaEqcWa_i20qC.webp" alt="image" width="1342" height="554" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Plotting numbers from local scopes demo", "Periodic changes") //@variable The number of chart bars in each period. int lengthInput = input.int(20, "Period length", 1) //@variable The maximum `close` change over each `lengthInput` period on the chart. var float maxChange = na //@variable The minimum `close` change over each `lengthInput` period on the chart. var float minChange = na //@variable Is `true` once every `lengthInput` bars. bool periodClose = bar_index % lengthInput == 0 //@variable Tracks the history of the local `change` variable. float debugChange = na if periodClose //@variable The change in `close` prices over `lengthInput` bars. float change = close - close[lengthInput] // Update the global `maxChange` and `minChange`. maxChange := math.max(nz(maxChange, change), change) minChange := math.min(nz(minChange, change), change) // Assign the `change` value to the `debugChange` variable. debugChange := change // Plot the `maxChange` and `minChange`. plot(maxChange, "Max periodic change", color.teal, 3) plot(minChange, "Min periodic change", color.maroon, 3) hline(0.0, color = color.gray, linestyle = hline.style_solid) // Create a debug plot to visualize the `change` history. plot(debugChange, "Extracted change", color.purple, 15, plot.style_areabr)</div> <p>Note that:</p> <ul> <li>The script uses <a href="https://www.tradingview.com/pine-script-reference/v6/#const_plot.style_areabr">plot.style_areabr</a> in the debug plot, which doesn’t bridge over <a href="https://www.tradingview.com/pine-script-reference/v6/#var_na">na</a> values as the default style does.</li> <li>When the rightmost visible bar’s plotted value is <a href="https://www.tradingview.com/pine-script-reference/v6/#var_na">na</a> the number in the price scale represents the latest <em>non-na</em> value before that bar, if one exists.</li> </ul> <h3 id="with-drawings" class="md-heading"><a href="#with-drawings">With drawings<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>An alternative approach to graphically inspecting the history of a script’s numeric values is to use Pine’s <a href="/pine-script-docs/language/type-system/#drawing-types">drawing types</a>, including <a href="/pine-script-docs/concepts/lines-and-boxes/#lines">lines</a>, <a href="/pine-script-docs/concepts/lines-and-boxes/#boxes">boxes</a>, <a href="/pine-script-docs/concepts/lines-and-boxes/#polylines">polylines</a>, and <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a>.</p> <p>While Pine drawings don’t display results anywhere other than the chart pane, scripts can create them from within <em>local scopes</em>, including the scopes of <a href="/pine-script-docs/language/user-defined-functions/">functions</a> and <a href="/pine-script-docs/language/methods/#user-defined-methods">methods</a> (see the <a href="/pine-script-docs/writing/debugging/#debugging-functions">Debugging functions</a> section to learn more). Additionally, scripts can position drawings at <em>any</em> available chart location, irrespective of the current <a href="https://www.tradingview.com/pine-script-reference/v6/#var_bar_index">bar_index</a>.</p> <p>For example, let’s revisit the “Periodic changes” script from the <a href="/pine-script-docs/writing/debugging/#from-local-scopes">previous section</a>. Suppose we’d like to inspect the history of the local <code dir="auto">change</code> variable <em>without</em> using a plot. In this case, we can avoid declaring a separate global variable and instead create drawing objects directly from the <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structure’s local scope.</p> <p>The script below is a modification of the previous script that uses <a href="/pine-script-docs/concepts/lines-and-boxes/#boxes">boxes</a> to visualize the <code dir="auto">change</code> variable’s behavior. Inside the scope of the <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structure, it calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_box.new">box.new()</a> to create a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_box">box</a> that spans from the bar <code dir="auto">lengthInput</code> bars ago to the current <a href="https://www.tradingview.com/pine-script-reference/v6/#var_bar_index">bar_index</a>:</p> <p><img src="/pine-script-docs/_astro/Debugging-Numeric-values-With-drawings-1.DsvQ-qM2_Z2i05an.webp" alt="image" width="1342" height="554" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Drawing numbers from local scopes demo", "Periodic changes", max_boxes_count = 500) //@variable The number of chart bars in each period. int lengthInput = input.int(20, "Period length", 1) //@variable The maximum `close` change over each `lengthInput` period on the chart. var float maxChange = na //@variable The minimum `close` change over each `lengthInput` period on the chart. var float minChange = na //@variable Is `true` once every `lengthInput` bars. bool periodClose = bar_index % lengthInput == 0 if periodClose //@variable The change in `close` prices over `lengthInput` bars. float change = close - close[lengthInput] // Update the global `maxChange` and `minChange`. maxChange := math.max(nz(maxChange, change), change) minChange := math.min(nz(minChange, change), change) //@variable Draws a box on the chart to visualize the `change` value. box debugBox = box.new( bar_index - lengthInput, math.max(change, 0.0), bar_index, math.min(change, 0.0), color.purple, bgcolor = color.new(color.purple, 80), text = str.tostring(change) ) // Plot the `maxChange` and `minChange`. plot(maxChange, "Max periodic change", color.teal, 3) plot(minChange, "Min periodic change", color.maroon, 3) hline(0.0, color = color.gray, linestyle = hline.style_solid)</div> <p>Note that:</p> <ul> <li>The script includes <code dir="auto">max_boxes_count = 500</code> in the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_indicator">indicator()</a> function, which allows it to show up to 500 <a href="/pine-script-docs/concepts/lines-and-boxes/#boxes">boxes</a> on the chart.</li> <li>We used <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_math.max">math.max(change, 0.0)</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_math.min">math.min(change, 0.0)</a> in the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_box.new">box.new()</a> function as the <code dir="auto">top</code> and <code dir="auto">bottom</code> values.</li> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_box.new">box.new()</a> call includes <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.tostring">str.tostring(change)</a> as its <code dir="auto">text</code> argument to display a <em>“string” representation</em> of the <code dir="auto">change</code> variable’s “float” value in each <a href="https://www.tradingview.com/pine-script-reference/v6/#type_box">box</a> drawing. See <a href="/pine-script-docs/writing/debugging/#representing-other-types">this</a> portion of the <a href="/pine-script-docs/writing/debugging/#strings">Strings</a> section below to learn more about representing data with strings.</li> </ul> <p>For more information about using <a href="/pine-script-docs/concepts/lines-and-boxes/#boxes">boxes</a> and other related <a href="/pine-script-docs/language/type-system/#drawing-types">drawing types</a>, see our User Manual’s <a href="/pine-script-docs/concepts/lines-and-boxes/">Lines and boxes</a> page.</p> <h2 id="conditions" class="md-heading"><a href="#conditions">Conditions<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <p>Many scripts one will create in Pine involve declaring and evaluating <em>conditions</em> to dictate specific script actions, such as triggering different calculation patterns, visuals, signals, alerts, strategy orders, etc. As such, it’s imperative to understand how to inspect the conditions a script uses to ensure proper execution.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>This section discusses debugging techniques based on chart visuals. To learn about <em>logging</em> conditions, see the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> section below.</p></div></aside> <h3 id="as-numbers" class="md-heading"><a href="#as-numbers">As numbers<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>One possible way to debug a script’s conditions is to define <em>numeric values</em> based on them, which allows programmers to inspect them using numeric approaches, such as those outlined in the <a href="/pine-script-docs/writing/debugging/#numeric-values">previous section</a>.</p> <p>Let’s look at a simple example. This script calculates the ratio between the <a href="https://www.tradingview.com/pine-script-reference/v6/#var_ohlc4">ohlc4</a> price and the <code dir="auto">lengthInput</code>-bar <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_ta.sma">moving average</a>. It assigns a condition to the <code dir="auto">priceAbove</code> variable that returns <code dir="auto">true</code> whenever the value of the ratio exceeds 1 (i.e., the price is above the average).</p> <p>To inspect the occurrences of the condition, we created a <code dir="auto">debugValue</code> variable assigned to the result of an expression that uses the ternary <a href="https://www.tradingview.com/pine-script-reference/v6/#op_?:">?:</a> operator to return 1 when <code dir="auto">priceAbove</code> is <code dir="auto">true</code> and 0 otherwise. The script plots the variable’s value in all available locations:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-As-numbers-1.BoeptaNB_2nR2E8.webp" alt="image" width="1342" height="498" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Conditions as numbers demo", "MA signal") //@variable The number of bars in the moving average calculation. int lengthInput = input.int(20, "Length", 1) //@variable The ratio of the `ohlc4` price to its `lengthInput`-bar moving average. float ratio = ohlc4 / ta.sma(ohlc4, lengthInput) //@variable The condition to inspect. Is `true` when `ohlc4` is above its moving average, `false` otherwise. bool priceAbove = ratio > 1.0 //@variable Returns 1 when the `priceAbove` condition is `true`, 0 otherwise. int debugValue = priceAbove ? 1 : 0 // Plot the `debugValue. plot(debugValue, "Conditional number", color.teal, 3)</div> <p>Note that:</p> <ul> <li>Representing “bool” values using numbers also allows scripts to display conditional shapes or characters at specific y-axis locations with <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotshape">plotshape()</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a>, and it facilitates conditional debugging with <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotarrow">plotarrow()</a>. See the <a href="/pine-script-docs/writing/debugging/#plotting-conditional-shapes">next section</a> to learn more.</li> </ul> <h3 id="plotting-conditional-shapes" class="md-heading"><a href="#plotting-conditional-shapes">Plotting conditional shapes<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotshape">plotshape()</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a> functions provide utility for debugging conditions, as they can plot shapes or characters at absolute or relative chart locations whenever they contain a <code dir="auto">true</code> or non-na <code dir="auto">series</code> argument.</p> <p>These functions can also display <em>numeric</em> representations of the <code dir="auto">series</code> in the script’s status line and the Data Window, meaning they’re also helpful for debugging <a href="/pine-script-docs/writing/debugging/#numeric-values">numbers</a>. We show a simple, practical way to debug numbers with these functions in the <a href="/pine-script-docs/writing/debugging/#tips">Tips</a> section.</p> <p>The chart locations of the plots depend on the <code dir="auto">location</code> parameter, which is <a href="https://www.tradingview.com/pine-script-reference/v6/#const_location.abovebar">location.abovebar</a> by default.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>When using <a href="https://www.tradingview.com/pine-script-reference/v6/#const_location.abovebar">location.abovebar</a> or <a href="https://www.tradingview.com/pine-script-reference/v6/#const_location.belowbar">location.belowbar</a>, the function positions the shapes/characters relative to the <em>main chart</em> prices. If the script plots its values in a separate chart pane, we recommend debugging with other <code dir="auto">location</code> options to avoid affecting the pane’s scale.</p></div></aside> <p>Let’s inspect a condition using these functions. The following script calculates an <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_ta.rsi">RSI</a> with a <code dir="auto">lengthInput</code> length and a <code dir="auto">crossBelow</code> variable whose value is the result of a condition that returns <code dir="auto">true</code> when the RSI crosses below 30. It calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotshape">plotshape()</a> to display a circle near the top of the pane each time the condition occurs:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-Plotting-conditional-shapes-1.B_YUlhVQ_Z1ARRXr.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Conditional shapes demo", "RSI cross under 30") //@variable The length of the RSI. int lengthInput = input.int(14, "Length", 1) //@variable The calculated RSI value. float rsi = ta.rsi(close, lengthInput) //@variable Is `true` when the `rsi` crosses below 30, `false` otherwise. bool crossBelow = ta.crossunder(rsi, 30.0) // Plot the `rsi`. plot(rsi, "RSI", color.rgb(136, 76, 146), linewidth = 3) // Plot the `crossBelow` condition as circles near the top of the pane. plotshape(crossBelow, "RSI crossed below 30", shape.circle, location.top, color.red, size = size.small)</div> <p>Note that:</p> <ul> <li>The status line and Data Window show a value of 1 when <code dir="auto">crossBelow</code> is <code dir="auto">true</code> and 0 when it’s <code dir="auto">false</code>.</li> </ul> <p>Suppose we’d like to display the shapes at <em>precise</em> locations rather than relative to the chart pane. We can achieve this by using <a href="/pine-script-docs/writing/debugging/#as-numbers">conditional numbers</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#const_location.absolute">location.absolute</a> in the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotshape">plotshape()</a> call.</p> <p>In this example, we’ve modified the previous script by creating a <code dir="auto">debugNumber</code> variable that returns the <code dir="auto">rsi</code> value when <code dir="auto">crossBelow</code> is <code dir="auto">true</code> and <a href="https://www.tradingview.com/pine-script-reference/v6/#var_na">na</a> otherwise. The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotshape">plotshape()</a> function uses this new variable as its <code dir="auto">series</code> argument and <a href="https://www.tradingview.com/pine-script-reference/v6/#const_location.absolute">location.absolute</a> as its <code dir="auto">location</code> argument:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-Plotting-conditional-shapes-2.Daveblc1_ZgMwC0.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Conditional shapes demo", "RSI cross under 30") //@variable The length of the RSI. int lengthInput = input.int(14, "Length", 1) //@variable The calculated RSI value. float rsi = ta.rsi(close, lengthInput) //@variable Is `true` when the `rsi` crosses below 30, `false` otherwise. bool crossBelow = ta.crossunder(rsi, 30.0) //@variable Returns the `rsi` when `crossBelow` is `true`, `na` otherwise. float debugNumber = crossBelow ? rsi : na // Plot the `rsi`. plot(rsi, "RSI", color.rgb(136, 76, 146), linewidth = 3) // Plot circles at the `debugNumber`. plotshape(debugNumber, "RSI when it crossed below 30", shape.circle, location.absolute, color.red, size = size.small)</div> <p>Note that:</p> <ul> <li>Since we passed a <em>numeric</em> series to the function, our conditional plot now shows the values of the <code dir="auto">debugNumber</code> in the status line and Data Window instead of 1 or 0.</li> </ul> <p>Another handy way to debug conditions is to use <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotarrow">plotarrow()</a>. This function plots an arrow with a location relative to the <em>main chart prices</em> whenever the <code dir="auto">series</code> argument is nonzero and not <a href="https://www.tradingview.com/pine-script-reference/v6/#var_na">na</a>. The length of each arrow varies with the <code dir="auto">series</code> value supplied. As with <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotshape">plotshape()</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotarrow">plotarrow()</a> can also display numeric results in the status line and the Data Window.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>Since this function always positions arrows relative to the main chart prices, we recommend only using it if the script occupies the main chart pane to avoid otherwise interfering with the scale.</p></div></aside> <p>This example shows an alternative way to inspect our <code dir="auto">crossBelow</code> condition using <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotarrow">plotarrow()</a>. In this version, we’ve set <code dir="auto">overlay</code> to <code dir="auto">true</code> in the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_indicator">indicator()</a> function and added a <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotarrow">plotarrow()</a> call to visualize the conditional values. The <code dir="auto">debugNumber</code> in this example measures how far the <code dir="auto">rsi</code> dropped below 30 each time the condition occurs:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-Plotting-conditional-shapes-3.IZzMwtM0_Z1HvpVm.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Conditional shapes demo", "RSI cross under 30", true) //@variable The length of the RSI. int lengthInput = input.int(14, "Length", 1) //@variable The calculated RSI value. float rsi = ta.rsi(close, lengthInput) //@variable Is `true` when the `rsi` crosses below 30, `false` otherwise. bool crossBelow = ta.crossunder(rsi, 30.0) //@variable Returns `rsi - 30.0` when `crossBelow` is `true`, `na` otherwise. float debugNumber = crossBelow ? rsi - 30.0 : na // Plot the `rsi`. plot(rsi, "RSI", color.rgb(136, 76, 146), display = display.data_window) // Plot circles at the `debugNumber`. plotarrow(debugNumber, "RSI cross below 30 distnce")</div> <p>Note that:</p> <ul> <li>We set the <code dir="auto">display</code> value in the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plot">plot()</a> of the <code dir="auto">rsi</code> to <a href="https://www.tradingview.com/pine-script-reference/v6/#const_display.data_window">display.data_window</a> to <a href="/pine-script-docs/writing/debugging/#without-affecting-the-scale">preserve the chart’s scale</a>.</li> </ul> <p>To learn more about <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotshape">plotshape()</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a>, and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotarrow">plotarrow()</a>, see this manual’s <a href="/pine-script-docs/concepts/text-and-shapes/">Text and shapes</a> page.</p> <h3 id="conditional-colors" class="md-heading"><a href="#conditional-colors">Conditional colors<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>An elegant way to visually represent conditions in Pine is to create expressions that return <a href="/pine-script-docs/language/type-system/#color">color</a> values based on <code dir="auto">true</code> or <code dir="auto">false</code> states, as scripts can use them to control the appearance of <a href="/pine-script-docs/language/type-system/#drawing-types">drawing objects</a> or the results of <code dir="auto">plot*()</code>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_fill">fill()</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">bgcolor()</a>, or <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_barcolor">barcolor()</a> calls.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>As with <code dir="auto">plot*()</code> functions, scripts can only call <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_fill">fill()</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">bgcolor()</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_barcolor">barcolor()</a> from the <em>global scope</em>, and the functions cannot accept any local variables.</p></div></aside> <p>For example, this script calculates the change in <a href="https://www.tradingview.com/pine-script-reference/v6/#var_close">close</a> prices over <code dir="auto">lengthInput</code> bars and declares two “bool” variables to identify when the price change is positive or negative.</p> <p>The script uses these “bool” values as conditions in <a href="https://www.tradingview.com/pine-script-reference/v6/#op_?:">ternary</a> expressions to assign the values of three “color” variables, then uses those variables as the <code dir="auto">color</code> arguments in <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plot">plot()</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">bgcolor()</a>, and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_barcolor">barcolor()</a> to debug the results:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-Conditional-colors-1.B5Y6dhKf_Z1jtyTu.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Conditional colors demo", "Price change colors") //@variable The number of bars in the price change calculation. int lengthInput = input.int(10, "Length", 1) //@variable The change in `close` prices over `lengthInput` bars. float priceChange = ta.change(close, lengthInput) //@variable Is `true` when the `priceChange` is a positive value, `false` otherwise. bool isPositive = priceChange > 0 //@variable Is `true` when the `priceChange` is a negative value, `false` otherwise. bool isNegative = priceChange < 0 //@variable Returns a color for the `priceChange` plot to show when `isPositive`, `isNegative`, or neither occurs. color plotColor = isPositive ? color.teal : isNegative ? color.maroon : chart.fg_color //@variable Returns an 80% transparent color for the background when `isPositive` or `isNegative`, `na` otherwise. color bgColor = isPositive ? color.new(color.aqua, 80) : isNegative ? color.new(color.fuchsia, 80) : na //@variable Returns a color to emphasize chart bars when `isPositive` occurs. Otherwise, returns the `chart.bg_color`. color barColor = isPositive ? color.orange : chart.bg_color // Plot the `priceChange` and color it with the `plotColor`. plot(priceChange, "Price change", plotColor, style = plot.style_area) // Highlight the pane's background with the `bgColor`. bgcolor(bgColor, title = "Background highlight") // Emphasize the chart bars with positive price change using the `barColor`. barcolor(barColor, title = "Positive change bars")</div> <p>Note that:</p> <ul> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_barcolor">barcolor()</a> function always colors the main chart’s bars, regardless of whether the script occupies another chart pane, and the chart will only display the results if the bars are visible.</li> </ul> <p>See the <a href="/pine-script-docs/concepts/colors/">Colors</a>, <a href="/pine-script-docs/concepts/fills/">Fills</a>, <a href="/pine-script-docs/concepts/backgrounds/">Backgrounds</a>, and <a href="/pine-script-docs/concepts/bar-coloring/">Bar coloring</a> pages for more information about working with colors, filling plots, highlighting backgrounds, and coloring bars.</p> <h3 id="using-drawings" class="md-heading"><a href="#using-drawings">Using drawings<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>Pine Script™‘s <a href="/pine-script-docs/language/type-system/#drawing-types">drawing types</a> provide flexible ways to visualize conditions on the chart, especially when the conditions are within local scopes.</p> <p>Consider the following script, which calculates a custom <code dir="auto">filter</code> with a smoothing parameter (<code dir="auto">alpha</code>) that changes its value within an <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structure based on recent <a href="https://www.tradingview.com/pine-script-reference/v6/#var_volume">volume</a> conditions:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-Using-drawings-1.bqLda39j_Z13aGwI.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Conditional drawings demo", "Volume-based filter", true) //@variable The number of bars in the volume average. int lengthInput = input.int(20, "Volume average length", 1) //@variable The average `volume` over `lengthInput` bars. float avgVolume = ta.sma(volume, lengthInput) //@variable A custom price filter based on volume activity. float filter = close //@variable The smoothing parameter of the filter calculation. Its value depends on multiple volume conditions. float alpha = na // Set the `alpha` to 1 if `volume` exceeds its `lengthInput`-bar moving average. if volume > avgVolume alpha := 1.0 // Set the `alpha` to 0.5 if `volume` exceeds its previous value. else if volume > volume[1] alpha := 0.5 // Set the `alpha` to 0.01 otherwise. else alpha := 0.01 // Calculate the new `filter` value. filter := (1.0 - alpha) * nz(filter[1], filter) + alpha * close // Plot the `filter`. plot(filter, "Filter", linewidth = 3)</div> <p>Suppose we’d like to inspect the conditions that control the <code dir="auto">alpha</code> value. There are several ways we could approach the task with chart visuals. However, some approaches will involve more code and careful handling.</p> <p>For example, to visualize the <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structure’s conditions using <a href="/pine-script-docs/writing/debugging/#plotting-conditional-shapes">plotted shapes</a> or <a href="/pine-script-docs/writing/debugging/#conditional-colors">background colors</a>, we’d have to create additional variables or expressions in the global scope for the <code dir="auto">plot*()</code> or <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">bgcolor()</a> functions to access.</p> <p>Alternatively, we can use <a href="/pine-script-docs/language/type-system/#drawing-types">drawing types</a> to visualize the conditions concisely without those extra steps.</p> <p>The following is a modification of the previous script that calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_label.new">label.new()</a> within specific branches of the <a href="/pine-script-docs/language/conditional-structures/">conditional structure</a> to draw <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> on the chart whenever those branches execute. These simple changes allow us to identify those conditions on the chart without much extra code:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-Using-drawings-2.6tfkMr81_1G1BSn.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Conditional drawings demo", "Volume-based filter", true, max_labels_count = 500) //@variable The number of bars in the volume average. int lengthInput = input.int(20, "Volume average length", 1) //@variable The average `volume` over `lengthInput` bars. float avgVolume = ta.sma(volume, lengthInput) //@variable A custom price filter based on volume activity. float filter = close //@variable The smoothing parameter of the filter calculation. Its value depends on multiple volume conditions. float alpha = na // Set the `alpha` to 1 if `volume` exceeds its `lengthInput`-bar moving average. if volume > avgVolume // Add debug label. label.new(chart.point.now(high), "alpha = 1", color = color.teal, textcolor = color.white) alpha := 1.0 // Set the `alpha` to 0.5 if `volume` exceeds its previous value. else if volume > volume[1] // Add debug label. label.new(chart.point.now(high), "alpha = 0.5", color = color.green, textcolor = color.white) alpha := 0.5 // Set the `alpha` to 0.01 otherwise. else alpha := 0.01 // Calculate the new `filter` value. filter := (1.0 - alpha) * nz(filter[1], filter) + alpha * close // Plot the `filter`. plot(filter, "Filter", linewidth = 3)</div> <p>Note that:</p> <ul> <li>We added the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_label.new">label.new()</a> calls <em>above</em> the <code dir="auto">alpha</code> reassignment expressions, as the returned types of each branch in the <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structure must match.</li> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_indicator">indicator()</a> function includes <code dir="auto">max_labels_count = 500</code> to specify that the script can show up to 500 <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> on the chart.</li> </ul> <h3 id="compound-and-nested-conditions" class="md-heading"><a href="#compound-and-nested-conditions">Compound and nested conditions<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>When a programmer needs to identify situations where more than one condition can occur, they may construct <em>compound conditions</em> by aggregating individual conditions with logical operators (<a href="https://www.tradingview.com/pine-script-reference/v6/#kw_and">and</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_or">or</a>).</p> <p>For example, this line of code shows a <code dir="auto">compoundCondition</code> variable that only returns <code dir="auto">true</code> if <code dir="auto">condition1</code> and either <code dir="auto">condition2</code> or <code dir="auto">condition3</code> occurs:</p> <div class="pine-colorizer not-content">bool compoundCondition = condition1 and (condition2 or condition3)</div> <p>One may alternatively create <em>nested conditions</em> using <a href="/pine-script-docs/language/conditional-structures/">conditional structures</a> or <a href="https://www.tradingview.com/pine-script-reference/v6/#op_?:">ternary expressions</a>. For example, this <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structure assigns <code dir="auto">true</code> to the <code dir="auto">nestedCondition</code> variable if <code dir="auto">condition1</code> and <code dir="auto">condition2</code> or <code dir="auto">condition3</code> occurs. However, unlike the logical expression above, the branches of this structure also allow the script to execute additional code before assigning the “bool” value:</p> <div class="pine-colorizer not-content">bool nestedCondition = false if condition1 // [additional_code] if condition2 // [additional_code] nestedCondition := true else if condition3 // [additional_code] nestedCondition := true</div> <p>In either case, whether working with compound or nested conditions in code, one will save many headaches and ensure they work as expected by validating the behaviors of the <em>individual conditions</em> that compose them.</p> <p>For example, this script calculates an <code dir="auto">rsi</code> and the <code dir="auto">median</code> of the <code dir="auto">rsi</code> over <code dir="auto">lengthInput</code> bars. Then, it creates five variables to represent different singular conditions. The script uses these variables in a logical expression to assign a “bool” value to the <code dir="auto">compoundCondition</code> variable, and it displays the results of the <code dir="auto">compoundCondition</code> using a <a href="/pine-script-docs/writing/debugging/#conditional-colors">conditional background color</a>:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-Compound-conditions-1.BIlbHbn5_Z1hVb8A.webp" alt="image" width="1342" height="588" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Compound conditions demo") //@variable The length of the RSI and median RSI calculations. int lengthInput = input.int(14, "Length", 2) //@variable The `lengthInput`-bar RSI. float rsi = ta.rsi(close, lengthInput) //@variable The `lengthInput`-bar median of the `rsi`. float median = ta.median(rsi, lengthInput) //@variable Condition #1: Is `true` when the 1-bar `rsi` change switches from 1 to -1. bool changeNegative = ta.change(math.sign(ta.change(rsi))) == -2 //@variable Condition #2: Is `true` when the previous bar's `rsi` is greater than 70. bool prevAbove70 = rsi[1] > 70.0 //@variable Condition #3: Is `true` when the current `close` is lower than the previous bar's `open`. bool closeBelow = close < open[1] //@variable Condition #4: Is `true` when the `rsi` is between 60 and 70. bool betweenLevels = bool(math.max(70.0 - rsi, 0.0) * math.max(rsi - 60.0, 0.0)) //@variable Condition #5: Is `true` when the `rsi` is above the `median`. bool aboveMedian = rsi > median //@variable Is `true` when the first condition occurs alongside conditions 2 and 3 or 4 and 5. bool compundCondition = changeNegative and ((prevAbove70 and closeBelow) or (betweenLevels and aboveMedian)) //Plot the `rsi` and the `median`. plot(rsi, "RSI", color.rgb(201, 109, 34), 3) plot(median, "RSI Median", color.rgb(180, 160, 102), 2) // Highlight the background red when the `compundCondition` occurs. bgcolor(compundCondition ? color.new(color.red, 60) : na, title = "compundCondition")</div> <p>As we see above, it’s not necessarily easy to understand the behavior of the <code dir="auto">compoundCondition</code> by only visualizing its end result, as five underlying singular conditions determine the final value. To effectively debug the <code dir="auto">compoundCondition</code> in this case, we must also inspect the conditions that compose it.</p> <p>In the example below, we’ve added five <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a> calls to display <a href="/pine-script-docs/writing/debugging/#plotting-conditional-shapes">characters</a> on the chart and numeric values in the status line and Data Window when each singular condition occurs. Inspecting each of these results provides us with more complete information about the <code dir="auto">compoundCondition</code>’s behavior:</p> <p><img src="/pine-script-docs/_astro/Debugging-Conditions-Compound-conditions-2.CqS0Ugyz_Z181FHW.webp" alt="image" width="1342" height="590" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Compound conditions demo") //@variable The length of the RSI and median RSI calculations. int lengthInput = input.int(14, "Length", 2) //@variable The `lengthInput`-bar RSI. float rsi = ta.rsi(close, lengthInput) //@variable The `lengthInput`-bar median of the `rsi`. float median = ta.median(rsi, lengthInput) //@variable Condition #1: Is `true` when the 1-bar `rsi` change switches from 1 to -1. bool changeNegative = ta.change(math.sign(ta.change(rsi))) == -2 //@variable Condition #2: Is `true` when the previous bar's `rsi` is greater than 70. bool prevAbove70 = rsi[1] > 70.0 //@variable Condition #3: Is `true` when the current `close` is lower than the previous bar's `open`. bool closeBelow = close < open[1] //@variable Condition #4: Is `true` when the `rsi` is between 60 and 70. bool betweenLevels = bool(math.max(70.0 - rsi, 0.0) * math.max(rsi - 60.0, 0.0)) //@variable Condition #5: Is `true` when the `rsi` is above the `median`. bool aboveMedian = rsi > median //@variable Is `true` when the first condition occurs alongside conditions 2 and 3 or 4 and 5. bool compundCondition = changeNegative and ((prevAbove70 and closeBelow) or (betweenLevels and aboveMedian)) //Plot the `rsi` and the `median`. plot(rsi, "RSI", color.rgb(201, 109, 34), 3) plot(median, "RSI Median", color.rgb(180, 160, 102), 2) // Highlight the background red when the `compundCondition` occurs. bgcolor(compundCondition ? color.new(color.red, 60) : na, title = "compundCondition") // Plot characters on the chart when conditions 1-5 occur. plotchar(changeNegative ? rsi : na, "changeNegative (1)", "1", location.absolute, chart.fg_color) plotchar(prevAbove70 ? 70.0 : na, "prevAbove70 (2)", "2", location.absolute, chart.fg_color) plotchar(closeBelow ? close : na, "closeBelow (3)", "3", location.bottom, chart.fg_color) plotchar(betweenLevels ? 60 : na, "betweenLevels (4)", "4", location.absolute, chart.fg_color) plotchar(aboveMedian ? median : na, "aboveMedian (5)", "5", location.absolute, chart.fg_color)</div> <p>Note that:</p> <ul> <li>Each <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a> call uses a <a href="/pine-script-docs/writing/debugging/#as-numbers">conditional number</a> as the <code dir="auto">series</code> argument. The functions display the numeric values in the status line and Data Window.</li> <li>All the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a> calls, excluding the one for the <code dir="auto">closeBelow</code> condition, use <a href="https://www.tradingview.com/pine-script-reference/v6/#const_location.absolute">location.absolute</a> as the <code dir="auto">location</code> argument to display characters at precise locations whenever their <code dir="auto">series</code> is not <a href="https://www.tradingview.com/pine-script-reference/v6/#var_na">na</a> (i.e., the condition occurs). The call for <code dir="auto">closeBelow</code> uses <a href="https://www.tradingview.com/pine-script-reference/v6/#const_location.bottom">location.bottom</a> to display its characters near the bottom of the pane.</li> <li>In this section’s examples, we assigned individual conditions to separate variables with straightforward names and annotations. While this format isn’t required to create a compound condition since one can combine conditions directly within a logical expression, it makes for more readable code that’s easier to debug, as explained in the <a href="/pine-script-docs/writing/debugging/#tips">Tips</a> section.</li> </ul> <h2 id="strings" class="md-heading"><a href="#strings">Strings<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <p><a href="/pine-script-docs/language/type-system/#string">Strings</a> are sequences of alphanumeric, control, and other characters (e.g., Unicode). They provide utility when debugging scripts, as programmers can use them to represent a script’s data types as human-readable text and inspect them with <a href="/pine-script-docs/language/type-system/#drawing-types">drawing types</a> that have text-related properties, or by using <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a>.</p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>This section discusses “string” conversions and inspecting strings via <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> and <a href="/pine-script-docs/concepts/tables/">tables</a>. <a href="/pine-script-docs/concepts/lines-and-boxes/#boxes">Boxes</a> can also display text. However, their utility for debugging strings is more limited than the techniques covered in this section and the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> section below.</p></div></aside> <h3 id="representing-other-types" class="md-heading"><a href="#representing-other-types">Representing other types<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>Users can create “string” representations of virtually any data type, facilitating effective debugging when other approaches may not suffice. Before exploring “string” inspection techniques, let’s briefly review ways to <em>represent</em> a script’s data using strings.</p> <p>Pine Script™ includes predefined logic to construct “string” representations of several other built-in types, such as <a href="/pine-script-docs/language/type-system/#int">int</a>, <a href="/pine-script-docs/language/type-system/#float">float</a>, <a href="/pine-script-docs/language/type-system/#bool">bool</a>, <a href="/pine-script-docs/language/arrays/">array</a>, and <a href="/pine-script-docs/language/matrices/">matrix</a>. Scripts can conveniently represent such types as strings via the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.tostring">str.tostring()</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.format">str.format()</a> functions.</p> <p>For example, this snippet creates strings to represent multiple values using these functions:</p> <div class="pine-colorizer not-content">//@variable Returns: "1.25" string floatRepr = str.tostring(1.25) //@variable Returns: "1" string rounded0 = str.tostring(1.25, "#") //@variable Returns: "1.3" string rounded1 = str.tostring(1.25, "#.#") //@variable Returns: "1.2500" string trailingZeros = str.tostring(1.25, "#.0000") //@variable Returns: "true" string trueRepr = str.tostring(true) //@variable Returns: "false" string falseRepr = str.tostring(5 == 3) //@variable Returns: "[1, 2, -3.14]" string floatArrayRepr = str.tostring(array.from(1, 2.0, -3.14)) //@variable Returns: "[2, 20, 0]" string roundedArrayRepr = str.tostring(array.from(2.22, 19.6, -0.43), "#") //@variable Returns: "[Hello, World, !]" string stringArrayRepr = str.tostring(array.from("Hello", "World", "!")) //@variable Returns: "Test: 2.718 ^ 2 > 5: true" string mixedTypeRepr = str.format("{0}{1, number, #.###} ^ 2 > {2}: {3}", "Test: ", math.e, 5, math.e * math.e > 5) //@variable Combines all the above strings into a multi-line string. string combined = str.format( "{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}", floatRepr, rounded0, rounded1, trailingZeros, trueRepr, falseRepr, floatArrayRepr, roundedArrayRepr, stringArrayRepr, mixedTypeRepr )</div> <p>When working with “int” values that symbolize UNIX timestamps, such as those returned from time-related functions and variables, one can also use <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.format">str.format()</a> or <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.format_time">str.format_time()</a> to convert them to human-readable date strings. This code block demonstrates multiple ways to convert a timestamp using these functions:</p> <div class="pine-colorizer not-content">//@variable A UNIX timestamp, in milliseconds. int unixTime = 1279411200000 //@variable Returns: "2010-07-18T00:00:00+0000" string default = str.format_time(unixTime) //@variable Returns: "2010-07-18" string ymdRepr = str.format_time(unixTime, "yyyy-MM-dd") //@variable Returns: "07-18-2010" string mdyRepr = str.format_time(unixTime, "MM-dd-yyyy") //@variable Returns: "20:00:00, 2010-07-17" string hmsymdRepr = str.format_time(unixTime, "HH:mm:ss, yyyy-MM-dd", "America/New_York") //@variable Returns: "Year: 2010, Month: 07, Day: 18, Time: 12:00:00" string customFormat = str.format( "Year: {0, time, yyyy}, Month: {1, time, MM}, Day: {2, time, dd}, Time: {3, time, hh:mm:ss}", unixTime, unixTime, unixTime, unixTime )</div> <p>When working with types that <em>don’t</em> have built-in “string” representations, e.g., <a href="/pine-script-docs/language/type-system/#color">color</a>, <a href="/pine-script-docs/language/maps/">map</a>, <a href="/pine-script-docs/language/type-system/#user-defined-types">user-defined types</a>, etc., programmers can use custom logic or formatting to construct representations. For example, this code calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.format">str.format()</a> to represent a “color” value using its <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_color.r">r</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_color.g">g</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_color.b">b</a>, and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_color.t">t</a> components:</p> <div class="pine-colorizer not-content">//@variable The built-in `color.maroon` value with 17% transparency. color myColor = color.new(color.maroon, 17) // Get the red, green, blue, and transparency components from `myColor`. float r = color.r(myColor) float g = color.g(myColor) float b = color.b(myColor) float t = color.t(myColor) //@variable Returns: "color (r = 136, g = 14, b = 79, t = 17)" string customRepr = str.format("color (r = {0}, g = {1}, b = {2}, t = {3})", r, g, b, t)</div> <p>There are countless ways one can represent data using strings. When choosing string formats for debugging, ensure the results are <strong>readable</strong> and provide enough information for proper inspection. The following segments explain ways to validate strings by displaying them on the chart using <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a>, and the section after these segments explains how to display strings as messages in the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> pane.</p> <h3 id="using-labels" class="md-heading"><a href="#using-labels">Using labels<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p><a href="/pine-script-docs/concepts/text-and-shapes/#labels">Labels</a> allow scripts to display dynamic text (“series strings”) at any available location on the chart. Where to display such text on the chart depends on the information the programmer wants to inspect and their debugging preferences.</p> <h4 id="on-successive-bars" class="md-heading"><a href="#on-successive-bars">On successive bars<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h4> <p>When inspecting the history of values that affect the chart’s scale or working with multiple series that have different types, a simple, handy debugging approach is to draw <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> that display <a href="/pine-script-docs/writing/debugging/#representing-other-types">string representations</a> on successive bars.</p> <p>For example, this script calculates four series: <code dir="auto">highestClose</code>, <code dir="auto">percentRank</code>, <code dir="auto">barsSinceHigh</code>, and <code dir="auto">isLow</code>. It uses <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.format">str.format()</a> to create a formatted “string” representing the series values and a timestamp, then it calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_label.new">label.new()</a> to draw a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_label">label</a> that display the results at the <a href="https://www.tradingview.com/pine-script-reference/v6/#var_high">high</a> on each bar:</p> <p><img src="/pine-script-docs/_astro/Debugging-Strings-Using-labels-On-successive-bars-1.QDEDvANn_xLWsm.webp" alt="image" width="1342" height="506" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Labels on successive bars demo", "Inspecting multiple series", true, max_labels_count = 500) //@variable The number of bars in the calculation window. int lengthInput = input.int(50, "Length", 1) //@variable The highest `close` over `lengthInput` bars. float highestClose = ta.highest(close, lengthInput) //@variable The percent rank of the current `close` compared to previous values over `lengthInput` bars. float percentRank = ta.percentrank(close, lengthInput) //@variable The number of bars since the `close` was equal to the `highestClose`. int barsSinceHigh = ta.barssince(close == highestClose) //@variable Is `true` when the `percentRank` is 0, i.e., when the `close` is the lowest. bool isLow = percentRank == 0.0 //@variable A multi-line string representing the `time`, `highestClose`, `percentRank`, `barsSinceHigh`, and `isLow`. string debugString = str.format( "time (GMT): {0, time, yyyy-MM-dd'T'HH:mm:ss}\nhighestClose: {1, number, #.####} \npercentRank: {2, number, #.##}%\nbarsSinceHigh: {3, number, integer}\nisLow: {4}", time, highestClose, percentRank, barsSinceHigh, isLow ) //@variable Draws a label showing the `debugString` at each bar's `high`. label debugLabel = label.new(chart.point.now(high), debugString, textcolor = color.white)</div> <p>While the above example allows one to inspect the results of the script’s series on any bar with a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_label">label</a> drawing, consecutive drawings like these can clutter the chart, especially when viewing longer strings.</p> <p>An alternative, more visually compact way to inspect successive bars’ values with <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> is to utilize the <code dir="auto">tooltip</code> property instead of the <code dir="auto">text</code> property, as a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_label">label</a> will only show its tooltip when the cursor <em>hovers</em> over it.</p> <p>Below, we’ve modified the previous script by using the <code dir="auto">debugString</code> as the <code dir="auto">tooltip</code> argument instead of the <code dir="auto">text</code> argument in the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_label.new">label.new()</a> call. Now, we can view the results on specific bars without the extra noise:</p> <p><img src="/pine-script-docs/_astro/Debugging-Strings-Using-labels-On-successive-bars-2.GO5WpodJ_Z1KqWXN.webp" alt="image" width="1342" height="528" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Tooltips on successive bars demo", "Inspecting multiple series", true, max_labels_count = 500) //@variable The number of bars in the calculation window. int lengthInput = input.int(50, "Length", 1) //@variable The highest `close` over `lengthInput` bars. float highestClose = ta.highest(close, lengthInput) //@variable The percent rank of the current `close` compared to previous values over `lengthInput` bars. float percentRank = ta.percentrank(close, lengthInput) //@variable The number of bars since the `close` was equal to the `highestClose`. int barsSinceHigh = ta.barssince(close == highestClose) //@variable Is `true` when the `percentRank` is 0, i.e., when the `close` is the lowest. bool isLow = percentRank == 0.0 //@variable A multi-line string representing the `time`, `highestClose`, `percentRank`, `barsSinceHigh`, and `isLow`. string debugString = str.format( "time (GMT): {0, time, yyyy-MM-dd'T'HH:mm:ss}\nhighestClose: {1, number, #.####} \npercentRank: {2, number, #.##}%\nbarsSinceHigh: {3, number, integer}\nisLow: {4}", time, highestClose, percentRank, barsSinceHigh, isLow ) //@variable Draws a label showing the `debugString` in a tooltip at each bar's `high`. label debugLabel = label.new(chart.point.now(high), tooltip = debugString)</div> <p>It’s important to note that a script can display up to 500 <a href="https://www.tradingview.com/pine-script-reference/v6/#type_label">label</a> drawings, meaning the above examples will only allow users to inspect the strings from the most recent 500 chart bars.</p> <p>If a programmer wants to see the results from <em>earlier</em> chart bars, one approach is to create conditional logic that only allows drawings within a specific time range, e.g.:</p> <div class="pine-colorizer not-content">if time >= startTime and time <= endTime <create_drawing_id></div> <p>If we use this structure in our previous example with <a href="https://www.tradingview.com/pine-script-reference/v6/#var_chart.left_visible_bar_time">chart.left_visible_bar_time</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#var_chart.right_visible_bar_time">chart.right_visible_bar_time</a> as the <code dir="auto">startTime</code> and <code dir="auto">endTime</code> values, the script will only create <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> on <strong>visible chart bars</strong> and avoid drawing on others. With this logic, we can scroll to view labels on <em>any</em> chart bar, as long as there are up to <code dir="auto">max_labels_count</code> bars in the visible range:</p> <p><img src="/pine-script-docs/_astro/Debugging-Strings-Using-labels-On-successive-bars-3.Dr46dKLS_Z1WAyIK.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Tooltips on visible bars demo", "Inspecting multiple series", true, max_labels_count = 500) //@variable The number of bars in the calculation window. int lengthInput = input.int(50, "Length", 1) //@variable The highest `close` over `lengthInput` bars. float highestClose = ta.highest(close, lengthInput) //@variable The percent rank of the current `close` compared to previous values over `lengthInput` bars. float percentRank = ta.percentrank(close, lengthInput) //@variable The number of bars since the `close` was equal to the `highestClose`. int barsSinceHigh = ta.barssince(close == highestClose) //@variable Is `true` when the `percentRank` is 0, i.e., when the `close` is the lowest. bool isLow = percentRank == 0.0 //@variable A multi-line string representing the `time`, `highestClose`, `percentRank`, `barsSinceHigh`, and `isLow`. string debugString = str.format( "time (GMT): {0, time, yyyy-MM-dd'T'HH:mm:ss}\nhighestClose: {1, number, #.####} \npercentRank: {2, number, #.##}%\nbarsSinceHigh: {3, number, integer}\nisLow: {4}", time, highestClose, percentRank, barsSinceHigh, isLow ) if time >= chart.left_visible_bar_time and time <= chart.right_visible_bar_time //@variable Draws a label showing the `debugString` in a tooltip at each visible bar's `high`. label debugLabel = label.new(chart.point.now(high), tooltip = debugString)</div> <p>Note that:</p> <ul> <li>If the visible chart contains more bars than allowed drawings, the script will only show results on the latest bars in the visible range. For best results with this technique, zoom on the chart to keep the visible range limited to the allowed number of drawings.</li> </ul> <h4 id="at-the-end-of-the-chart" class="md-heading"><a href="#at-the-end-of-the-chart">At the end of the chart<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h4> <p>A frequent approach to debugging a script’s strings with <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> is to display them at the <em>end</em> of the chart, namely when the strings do not change or when only a specific bar’s values require analysis.</p> <p>The script below contains a user-defined <code dir="auto">printLabel()</code> function that draws a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_label">label</a> at the last available time on the chart, regardless of when the script calls it. We’ve used the function in this example to display a “Hello world!” string, some basic chart information, and the data feed’s current OHLCV values:</p> <p><img src="/pine-script-docs/_astro/Debugging-Strings-Using-labels-At-the-end-of-the-chart-1.C-6hYXkR_Z1lpCgi.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Labels at the end of the chart demo", "Chart info", true) //@function Draws a label to print the `txt` at the last available time on the chart. // When called from the global scope, the label updates its text using the specified `txt` on every bar. //@param txt The string to display on the chart. //@param price The optional y-axis location of the label. If not specified, draws the label above the last chart bar. //@returns The resulting label ID. printLabel(string txt, float price = na) => int labelTime = math.max(last_bar_time, chart.right_visible_bar_time) var label result = label.new( labelTime, na, txt, xloc.bar_time, na(price) ? yloc.abovebar : yloc.price, na, label.style_none, chart.fg_color, size.large ) label.set_text(result, txt) label.set_y(result, price) result //@variable A formatted string containing information about the current chart. string chartInfo = str.format( "Symbol: {0}:{1}\nTimeframe: {2}\nStandard chart: {3}\nReplay active: {4}", syminfo.prefix, syminfo.ticker, timeframe.period, chart.is_standard, str.contains(syminfo.tickerid, "replay") ) //@variable A formatted string containing OHLCV values. string ohlcvInfo = str.format( "O: {0, number, #.#####}, H: {1, number, #.#####}, L: {2, number, #.#####}, C: {3, number, #.#####}, V: {4}", open, high, low, close, str.tostring(volume, format.volume) ) // Print "Hello world!" and the `chartInfo` at the end of the chart on the first bar. if barstate.isfirst printLabel("Hello world!" + "\n\n\n\n\n\n\n") printLabel(chartInfo + "\n\n") // Print current `ohlcvInfo` at the end of the chart, updating the displayed text as new data comes in. printLabel(ohlcvInfo)</div> <p>Note that:</p> <ul> <li>The <code dir="auto">printLabel()</code> function sets the x-coordinate of the drawn <a href="https://www.tradingview.com/pine-script-reference/v6/#type_label">label</a> using the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_math.max">max</a> of the <a href="https://www.tradingview.com/pine-script-reference/v6/#var_last_bar_time">last_bar_time</a> and the <a href="https://www.tradingview.com/pine-script-reference/v6/#var_chart.right_visible_bar_time">chart.right_visible_bar_time</a> to ensure it always shows the results at the last available bar.</li> <li>When called from the <em>global scope</em>, the function creates a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_label">label</a> with <code dir="auto">text</code> and <code dir="auto">y</code> properties that update on every bar.</li> <li>We’ve made three calls to the function and added linefeed characters (<code dir="auto">\n</code>) to demonstrate that users can superimpose the results from multiple <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> at the end of the chart if the strings have adequate line spacing.</li> </ul> <h3 id="using-tables" class="md-heading"><a href="#using-tables">Using tables<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p><a href="/pine-script-docs/concepts/tables/">Tables</a> display strings within cells arranged in columns and rows at fixed locations relative to a chart pane’s visual space. They can serve as versatile chart-based debugging tools, as unlike <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a>, they allow programmers to inspect one or <em>more</em> “series strings” in an organized visual structure agnostic to the chart’s scale or bar index.</p> <p>For example, this script calculates a custom <code dir="auto">filter</code> whose result is the ratio of the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_ta.ema">EMA</a> of weighted <a href="https://www.tradingview.com/pine-script-reference/v6/#var_close">close</a> prices to the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_ta.ema">EMA</a> of the <code dir="auto">weight</code> series. For inspection of the variables used in the calculation, it creates a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_table">table</a> instance on the first bar, initializes the table’s cells on the last historical bar, then updates necessary cells with “string” representations of the values from <code dir="auto">barsBack</code> bars ago on the latest chart bar:</p> <p><img src="/pine-script-docs/_astro/Debugging-Strings-Using-tables-1.Bfvract8_Z20ywVF.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Debugging with tables demo", "History inspection", true) //@variable The number of bars back in the chart's history to inspect. int barsBack = input.int(10, "Bars back", 0, 4999) //@variable The percent rank of `volume` over 10 bars. float weight = ta.percentrank(volume, 10) //@variable The 10-bar EMA of `weight * close` values. float numerator = ta.ema(weight * close, 10) //@variable The 10-bar EMA of `weight` values. float denominator = ta.ema(weight, 10) //@variable The ratio of the `numerator` to the `denominator`. float filter = numerator / denominator // Plot the `filter`. plot(filter, "Custom filter") //@variable The color of the frame, border, and text in the `debugTable`. color tableColor = chart.fg_color //@variable A table that contains "string" representations of variable names and values on the latest chart bar. var table debugTable = table.new( position.top_right, 2, 5, frame_color = tableColor, frame_width = 1, border_color = tableColor, border_width = 1 ) // Initialize cells on the last confirmed historical bar. if barstate.islastconfirmedhistory table.cell(debugTable, 0, 0, "Variable", text_color = tableColor) table.cell(debugTable, 1, 0, str.format("Value {0, number, integer} bars ago", barsBack), text_color = tableColor) table.cell(debugTable, 0, 1, "weight", text_color = tableColor) table.cell(debugTable, 1, 1, "", text_color = tableColor) table.cell(debugTable, 0, 2, "numerator", text_color = tableColor) table.cell(debugTable, 1, 2, "", text_color = tableColor) table.cell(debugTable, 0, 3, "denominator", text_color = tableColor) table.cell(debugTable, 1, 3, "", text_color = tableColor) table.cell(debugTable, 0, 4, "filter", text_color = tableColor) table.cell(debugTable, 1, 4, "", text_color = tableColor) // Update value cells on the last available bar. if barstate.islast table.cell_set_text(debugTable, 1, 1, str.tostring(weight[barsBack], format.percent)) table.cell_set_text(debugTable, 1, 2, str.tostring(numerator[barsBack])) table.cell_set_text(debugTable, 1, 3, str.tostring(denominator[barsBack])) table.cell_set_text(debugTable, 1, 4, str.tostring(filter[barsBack]))</div> <p>Note that:</p> <ul> <li>The script uses the <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_var">var</a> keyword to specify that the <a href="https://www.tradingview.com/pine-script-reference/v6/#type_table">table</a> assigned to the <code dir="auto">debugTable</code> variable on the first bar persists throughout the script’s execution.</li> <li>This script modifies the table within two <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> structures. The first structure initializes the cells with <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_table.cell">table.cell()</a> only on the last confirmed historical bar (<a href="https://www.tradingview.com/pine-script-reference/v6/#var_barstate.islastconfirmedhistory">barstate.islastconfirmedhistory</a>). The second structure updates the <code dir="auto">text</code> properties of relevant cells with <a href="/pine-script-docs/writing/debugging/#representing-other-types">string representations</a> of our variables’ values using <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_table.cell_set_text">table.cell_set_text()</a> calls on the latest available bar (<a href="https://www.tradingview.com/pine-script-reference/v6/#var_barstate.islast">barstate.islast</a>).</li> </ul> <p>It’s important to note that although tables can provide debugging utility, namely when working with multiple series or creating on-chart logs, they carry a higher computational cost than other techniques discussed on this page and may require <em>more code</em>. Additionally, unlike <a href="/pine-script-docs/writing/debugging/#using-labels">labels</a>, one can only view a table’s state from the latest script execution. We therefore recommend using them <em>wisely</em> and <em>sparingly</em> while debugging, opting for <em>simplified</em> approaches where possible. For more information about using <a href="https://www.tradingview.com/pine-script-reference/v6/#type_table">table</a> objects, see the <a href="/pine-script-docs/concepts/tables/">Tables</a> page.</p> <h2 id="pine-logs" class="md-heading"><a href="#pine-logs">Pine Logs<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <p>Pine Logs are <em>interactive messages</em> that scripts can output at specific points in their execution. They provide a powerful way for programmers to inspect a script’s data, conditions, and execution flow with minimal code.</p> <p>Unlike the other tools discussed on this page, Pine Logs have a deliberate design for in-depth script debugging. Scripts do not display Pine Logs on the chart or in the Data Window. Instead, they print messages with timestamps in the dedicated <em>Pine Logs pane</em>, which provides specialized navigation features and filtering options.</p> <p>To access the Pine Logs pane, select “Pine Logs…” from the Editor’s “More” menu or from the “More” menu of a script loaded on the chart that uses <code dir="auto">log.*()</code> functions:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-1.D3YhPfKI_1eBx6z.webp" alt="image" width="720" height="296" loading="lazy" decoding="async"></p> <aside aria-label="Notice!" class="tv-informer not-content" style="--informer-header-color:#FF9800;--informer-back-color-light:#FFF3E0;--informer-back-color-dark:#33261A"><div class="tv-informer-icon"><svg viewBox="0 0 18 18" width="18" height="18"><path fill-rule="evenodd" d="M9 17A8 8 0 1 0 9 1a8 8 0 0 0 0 16ZM9 4c-.79 0-1.38.7-1.25 1.48l.67 4.03a.59.59 0 0 0 1.16 0l.67-4.03A1.27 1.27 0 0 0 9 4Zm0 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="currentColor"></path></svg></div><div class="tv-informer-content"><p><span class="tv-informer-header">Notice!</span>Only <strong>personal scripts</strong> can generate Pine Logs. A published script <em>cannot</em> create logs, even if it has <code dir="auto">log.*()</code> function calls in its code. One must consider alternative approaches, such as those outlined in the sections above, when <a href="/pine-script-docs/writing/publishing/">publishing scripts</a> with debugging functionality.</p></div></aside> <h3 id="creating-logs" class="md-heading"><a href="#creating-logs">Creating logs<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>Scripts can create logs by calling the functions in the <code dir="auto">log.*()</code> namespace.</p> <p>All <code dir="auto">log.*()</code> functions have the following signatures:</p> <div class="expressive-code not-content"><link rel="stylesheet" href="/pine-script-docs/_astro/ec.dtidy.css"/><script type="module" src="/pine-script-docs/_astro/ec.qopfj.js"></script><figure class="frame"><figcaption class="header"></figcaption><pre data-language="text"><code><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">log.*(message) → void</span></div></div><div class="ec-line"><div class="code"> </div></div><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">log.*(formatString, arg0, arg1, ...) → void</span></div></div></code></pre></figure></div> <p>The first overload logs a specified <code dir="auto">message</code> in the Pine Logs pane. The second overload is similar to <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.format">str.format()</a>, as it logs a formatted message based on the <code dir="auto">formatString</code> and the additional arguments supplied in the call.</p> <p>Each <code dir="auto">log.*()</code> function has a different <em>debug level</em>, allowing programmers to categorize and <a href="/pine-script-docs/writing/debugging/#filtering-logs">filter</a> results shown in the pane:</p> <ul> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a> function logs an entry with the <em>“info”</em> level that appears in the pane with gray text.</li> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.warning">log.warning()</a> function logs an entry with the <em>“warning”</em> level that appears in the pane with orange text.</li> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.error">log.error()</a> function logs an entry with the <em>“error”</em> level that appears in the pane with red text.</li> </ul> <p>This code demonstrates the difference between all three <code dir="auto">log.*()</code> functions. It calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a>, <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.warning">log.warning()</a>, and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.error">log.error()</a> on the first available bar:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Creating-logs-1.B6M1BlvN_1OBeQe.webp" alt="image" width="1342" height="428" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Debug levels demo", overlay = true) if barstate.isfirst log.info("This is an 'info' message.") log.warning("This is a 'warning' message.") log.error("This is an 'error' message.")</div> <p>Pine Logs can execute anywhere within a script’s execution. They allow programmers to track information from historical bars and monitor how their scripts behave on realtime, <em>unconfirmed</em> bars. When executing on historical bars, scripts generate a new message once for each <code dir="auto">log.*()</code> call on a bar. On realtime bars, calls to <code dir="auto">log.*()</code> functions can create new entries on <em>each new tick</em>.</p> <p>For example, this script calculates the average ratio between each bar’s <code dir="auto">close - open</code> value to its <code dir="auto">high - low</code> range. When the <code dir="auto">denominator</code> is nonzero, the script calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a> to print the values of the calculation’s variables on confirmed bars and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.warning">log.warning()</a> to print the values on unconfirmed bars. Otherwise, it uses <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.error">log.error()</a> to indicate that division by zero occurred, as such cases can affect the <code dir="auto">average</code> result:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Creating-logs-2.DgOgH4xb_ZRjj9G.webp" alt="image" width="1342" height="666" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Logging historical and realtime data demo", "Average bar ratio") //@variable The current bar's change from the `open` to `close`. float numerator = close - open //@variable The current bar's `low` to `high` range. float denominator = high - low //@variable The ratio of the bar's open-to-close range to its full range. float ratio = numerator / denominator //@variable The average `ratio` over 10 non-na values. float average = ta.sma(ratio, 10) // Plot the `average`. plot(average, "average", color.purple, 3) if barstate.isconfirmed // Log a division by zero error if the `denominator` is 0. if denominator == 0.0 log.error("Division by 0 in confirmed results!") // Otherwise, log the confirmed values. else log.info( "Values (confirmed):\nnumerator: {1, number, #.########}\ndenominator: {2, number, #.########} \nratio: {0, number, #.########}\naverage: {3, number, #.########}", ratio, numerator, denominator, average ) else // Log a division by zero error if the `denominator` is 0. if denominator == 0.0 log.error("Division by 0 on unconfirmed bar.") // Otherwise, log the unconfirmed values. else log.warning( "Values (unconfirmed):\nnumerator: {1, number, #.########}\ndenominator: {2, number, #.########} \nratio: {0, number, #.########}\naverage: {3, number, #.########}", ratio, numerator, denominator, average )</div> <p>Note that:</p> <ul> <li>Pine Logs <em>do not roll back</em> on each tick in an unconfirmed bar, meaning the results for those ticks show in the pane until the script restarts its execution. To only log messages on <em>confirmed</em> bars, use <a href="https://www.tradingview.com/pine-script-reference/v6/#var_barstate.isconfirmed">barstate.isconfirmed</a> in the conditions that trigger a <code dir="auto">log.*()</code> call.</li> <li>When logging on unconfirmed bars, we recommend ensuring those logs contain <em>unique information</em> or use different <em>debug levels</em> so you can <a href="/pine-script-docs/writing/debugging/#filtering-logs">filter</a> the results as needed.</li> <li>The Pine Logs pane will show up to the most recent 10,000 entries for historical bars. If a script generates more than 10,000 logs on historical bars and a programmer needs to view earlier entries, they can use conditional logic to limit <code dir="auto">log.*()</code> calls to specific occurrences. See <a href="/pine-script-docs/writing/debugging/#using-inputs">this</a> section for an example that limits log generation to a user-specified time range.</li> </ul> <h3 id="inspecting-logs" class="md-heading"><a href="#inspecting-logs">Inspecting logs<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>Pine Logs include some helpful features that simplify the inspection process. Whenever a script generates a log, it automatically prefixes the message with a granular timestamp to signify where the log event occurred in the time series. Additionally, each entry contains <strong>“Source code”</strong> and <strong>“Scroll to bar”</strong> icons, which appear when hovering over it in the Pine Logs pane:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Inspecting-logs-1.CEw5SsHB_27329j.webp" alt="image" width="1342" height="470" loading="lazy" decoding="async"></p> <p>Clicking an entry’s “Source code” icon opens the script in the Pine Editor and highlights the specific line of code that triggered the log:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Inspecting-logs-2.1cfqckmg_1omSJk.webp" alt="image" width="1342" height="434" loading="lazy" decoding="async"></p> <p>Clicking an entry’s “Scroll to bar” icon navigates the chart to the specific bar where the log occurred, then temporarily displays a tooltip containing time information for that bar:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Inspecting-logs-3.AJrWQdc2_ZHsjQK.webp" alt="image" width="1342" height="560" loading="lazy" decoding="async"></p> <p>Note that:</p> <ul> <li>The time information in the tooltip depends on the chart’s timeframe, just like the x-axis label linked to the chart’s cursor and drawing tools. For example, the tooltip on an EOD chart will only show the weekday and the date, whereas the tooltip on a 10-second chart will also contain the time of day, including seconds.</li> </ul> <p>When a chart includes more than one script that generates logs, it’s important to note that each script maintains its own <em>independent</em> message history. To inspect the messages from a specific script when multiple are on the chart, select its title from the dropdown at the top of the Pine Logs pane:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Inspecting-logs-4.CY8OpkgY_Z10JTlu.webp" alt="image" width="1342" height="374" loading="lazy" decoding="async"></p> <h3 id="filtering-logs" class="md-heading"><a href="#filtering-logs">Filtering logs<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>A single script can generate numerous logs, depending on the conditions that trigger its <code dir="auto">log.*()</code> calls. While directly scrolling through the log history to find specific entries may suffice when a script only generates a few, it can become unwieldy when searching through hundreds or thousands of messages.</p> <p>The Pine Logs pane includes multiple options for filtering messages, which allows one to simplify their results by isolating specific <em>character sequences</em>, <em>start times</em>, and <em>debug levels</em>.</p> <p>Clicking the “Search” icon at the top of the pane opens a search bar, which matches text to filter logged messages. The search filter also highlights the matched portion of each message in blue for visual reference. For example, here, we entered “confirmed” to match all results generated by our previous script with the word somewhere in their text:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Filtering-logs-1.Bo6VZioU_Cbru5.webp" alt="image" width="1342" height="664" loading="lazy" decoding="async"></p> <p>Notice that the results from this search also considered messages with <em>“unconfirmed”</em> as matches since the word contains our query. We can omit these matches by selecting the “Whole Word” checkbox in the options at the right of the search bar:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Filtering-logs-2.75PYAT31_Z8HPfP.webp" alt="image" width="1342" height="664" loading="lazy" decoding="async"></p> <p>This filter also supports <a href="https://en.wikipedia.org/wiki/Regular_expression" rel="nofollow">regular expressions (regex)</a>, which allow users to perform advanced searches that match custom <em>character patterns</em> when selecting the “Regex” checkbox in the search options. For example, this regex matches all entries that contain “average” followed by a sequence representing a number greater than 0.5 and less than or equal to 1:</p> <p><code dir="auto">average:\s*(0\.[6-9]\d*|0\.5\d*[1-9]\d*|1\.0*)</code></p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Filtering-logs-3.C8CgIgDR_ZwuDXw.webp" alt="image" width="1342" height="664" loading="lazy" decoding="async"></p> <p>Clicking the “Start date” icon opens a dialog that allows users to specify the date and time of the first log shown in the results:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Filtering-logs-4.ByHNqBMd_1OJ3LK.webp" alt="image" width="1342" height="566" loading="lazy" decoding="async"></p> <p>After specifying the starting point, a tag containing the starting time will appear above the log history:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Filtering-logs-5.Dv8F4vq1_1DX0la.webp" alt="image" width="1342" height="388" loading="lazy" decoding="async"></p> <p>Users can filter results by <em>debug level</em> using the checkboxes available when selecting the rightmost icon in the filtering options. Here, we’ve deactivated the “info” and “warning” levels so the results will only contain “error” messages:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Filtering-logs-6.CJM074om_Z1UkF5.webp" alt="image" width="1342" height="664" loading="lazy" decoding="async"></p> <h4 id="using-inputs" class="md-heading"><a href="#using-inputs">Using inputs<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h4> <p>Another, more involved way to interactively filter a script’s logged results is to create <a href="/pine-script-docs/concepts/inputs/">inputs</a> linked to conditional logic that activates specific <code dir="auto">log.*()</code> calls in the code.</p> <p>Let’s look at an example. This code calculates an <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_ta.rma">RMA</a> of <a href="https://www.tradingview.com/pine-script-reference/v6/#var_close">close</a> prices and declares a few unique conditions to form a <a href="/pine-script-docs/writing/debugging/#compound-and-nested-conditions">compound condition</a>. The script uses <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a> to display important debugging information in the Pine Logs pane, including the values of the <code dir="auto">compoundCondition</code> variable and the “bool” variables that determine its result.</p> <p>We declared the <code dir="auto">filterLogsInput</code>, <code dir="auto">logStartInput</code>, and <code dir="auto">logEndInput</code> variables respectively assigned to an <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_input.bool">input.bool()</a> and two <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_input.time">input.time()</a> calls for custom log filtering. When <code dir="auto">filterLogsInput</code> is <code dir="auto">true</code>, the script will only generate a new log if the bar’s <a href="https://www.tradingview.com/pine-script-reference/v6/#var_time">time</a> is between the <code dir="auto">logStartInput</code> and <code dir="auto">logEndInput</code> values, allowing us to interactively isolate the entries that occurred within a specific time range:</p> <p><img src="/pine-script-docs/_astro/Debugging-Pine-logs-Filtering-logs-Using-inputs-1.BCr7IdYS_ZmAWLn.webp" alt="image" width="1342" height="524" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Filtering logs using inputs demo", "Compound condition in input range", true) //@variable The length for moving average calculations. int lengthInput = input.int(20, "Length", 2) //@variable If `true`, only allows logs within the input time range. bool filterLogsInput = input.bool(true, "Only log in time range", group = "Log filter") //@variable The starting time for logs if `filterLogsInput` is `true`. int logStartInput = input.time(0, "Start time", group = "Log filter", confirm = true) //@variable The ending time for logs if `filterLogsInput` is `true`. int logEndInput = input.time(0, "End time", group = "Log filter", confirm = true) //@variable The RMA of `close` prices. float rma = ta.rma(close, lengthInput) //@variable Is `true` when `close` exceeds the `rma`. bool priceBelow = close <= rma //@variable Is `true` when the current `close` is greater than the max of the previous `hl2` and `close`. bool priceRising = close > math.max(hl2[1], close[1]) //@variable Is `true` when the `rma` is positively accelerating. bool rmaAccelerating = rma - 2.0 * rma[1] + rma[2] > 0.0 //@variable Is `true` when the difference between `rma` and `close` exceeds 2 times the current ATR. bool closeAtThreshold = rma - close > ta.atr(lengthInput) * 2.0 //@variable Is `true` when all the above conditions occur. bool compoundCondition = priceBelow and priceRising and rmaAccelerating and closeAtThreshold // Plot the `rma`. plot(rma, "RMA", color.teal, 3) // Highlight the chart background when the `compoundCondition` occurs. bgcolor(compoundCondition ? color.new(color.aqua, 80) : na, title = "Compound condition highlight") //@variable If `filterLogsInput` is `true`, is only `true` in the input time range. Otherwise, always `true`. bool showLog = filterLogsInput ? time >= logStartInput and time <= logEndInput : true // Log results for a confirmed bar when `showLog` is `true`. if barstate.isconfirmed and showLog log.info( "\nclose: {0, number, #.#####}\nrma: {1, number, #.#####}\npriceBelow: {2}\npriceRising: {3} \nrmaAccelerating: {4}\ncloseAtThreshold: {5}\n\ncompoundCondition: {6}", close, rma, priceBelow, priceRising, rmaAccelerating, closeAtThreshold, compoundCondition )</div> <p>Note that:</p> <ul> <li>The <code dir="auto">input.*()</code> functions assigned to the <code dir="auto">filterLogsInput</code>, <code dir="auto">logStartInput</code>, and <code dir="auto">logEndInput</code> variables include a <code dir="auto">group</code> argument to oragnize and distinguish them in the script’s settings.</li> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_input.time">input.time()</a> calls include <code dir="auto">confirm = true</code> so that we can interactively set the start and end times directly on the chart. To reset the inputs, select “Reset points…” from the options in the script’s “More” menu.</li> <li>The condition that triggers each <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a> call includes <a href="https://www.tradingview.com/pine-script-reference/v6/#var_barstate.isconfirmed">barstate.isconfirmed</a> to limit log generation to <em>confirmed</em> bars.</li> </ul> <h2 id="debugging-functions" class="md-heading"><a href="#debugging-functions">Debugging functions<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <p><a href="/pine-script-docs/language/user-defined-functions/">User-defined functions</a> and <a href="/pine-script-docs/language/methods/#user-defined-methods">methods</a> are custom functions written by users. They encapsulate sequences of operations that a script can invoke later in its execution.</p> <p>Every <a href="/pine-script-docs/language/user-defined-functions/">user-defined function</a> or <a href="/pine-script-docs/language/methods/#user-defined-methods">method</a> has a <em>local scope</em> that embeds into the script’s global scope. The parameters in a function’s signature and the variables declared within the function body belong to that function’s local scope, and they are <em>not</em> directly accessible to a script’s outer scope or the scopes of other functions.</p> <p>The segments below explain a few ways programmers can debug the values from a function’s local scope. We will use this script as the starting point for our subsequent examples. It contains a <code dir="auto">customMA()</code> function that returns an exponential moving average whose smoothing parameter varies based on the <code dir="auto">source</code> distance outside the 25th and 75th <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_ta.percentile_linear_interpolation">percentiles</a> over <code dir="auto">length</code> bars:</p> <p><img src="/pine-script-docs/_astro/Debugging-Debugging-functions-1.C82H9E7R_Z1zqdTD.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Debugging functions demo", "Custom MA", true) //@variable The number of bars in the `customMA()` calculation. int lengthInput = input.int(50, "Length", 2) //@function Calculates a moving average that only responds to values outside the first and third quartiles. //@param source The series of values to process. //@param length The number of bars in the calculation. //@returns The moving average value. customMA(float source, int length) => //@variable The custom moving average. var float result = na // Calculate the 25th and 75th `source` percentiles. float q1 = ta.percentile_linear_interpolation(source, length, 25) float q3 = ta.percentile_linear_interpolation(source, length, 75) // Calculate the range values. float outerRange = math.max(source - q3, q1 - source, 0.0) float totalRange = ta.range(source, length) //@variable Half the ratio of the `outerRange` to the `totalRange`. float alpha = 0.5 * outerRange / totalRange // Mix the `source` with the `result` based on the `alpha` value. result := (1.0 - alpha) * nz(result, source) + alpha * source // Return the `result`. result //@variable The `customMA()` result over `lengthInput` bars. float maValue = customMA(close, lengthInput) // Plot the `maValue`. plot(maValue, "Custom MA", color.blue, 3)</div> <h3 id="extracting-local-variables" class="md-heading"><a href="#extracting-local-variables">Extracting local variables<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>When a programmer wants to inspect a <a href="/pine-script-docs/language/user-defined-functions/">user-defined function’s</a> local variables by <a href="/pine-script-docs/writing/debugging/#plotting-numbers">plotting</a> its values, <a href="/pine-script-docs/writing/debugging/#conditional-colors">coloring</a> the background or chart bars, etc., they must <em>extract</em> the values to the <em>global scope</em>, as the built-in functions that produce such outputs can only accept global variables and literals.</p> <p>Since the values returned by a function are available to the scope where a call occurs, one straightforward extraction approach is to have the function return a <a href="/pine-script-docs/language/type-system/#tuples">tuple</a> containing all the values that need inspection.</p> <p>Here, we’ve modified the <code dir="auto">customMA()</code> function to return a <a href="/pine-script-docs/language/type-system/#tuples">tuple</a> containing all the function’s calculated variables. Now, we can call the function with a <em>tuple declaration</em> to make the values available in the global scope and inspect them with <a href="/pine-script-docs/writing/debugging/#plotting-numbers">plots</a>:</p> <p><img src="/pine-script-docs/_astro/Debugging-Debugging-functions-Extracting-local-variables-1.Crv6Jvx8_Z2qevgh.webp" alt="image" width="1342" height="588" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Extracting local variables with tuples demo", "Custom MA", true) //@variable The number of bars in the `customMA()` calculation. int lengthInput = input.int(50, "Length", 2) //@function Calculates a moving average that only responds to values outside the first and third quartiles. //@param source The series of values to process. //@param length The number of bars in the calculation. //@returns The moving average value. customMA(float source, int length) => //@variable The custom moving average. var float result = na // Calculate the 25th and 75th `source` percentiles. float q1 = ta.percentile_linear_interpolation(source, length, 25) float q3 = ta.percentile_linear_interpolation(source, length, 75) // Calculate the range values. float outerRange = math.max(source - q3, q1 - source, 0.0) float totalRange = ta.range(source, length) //@variable Half the ratio of the `outerRange` to the `totalRange`. float alpha = 0.5 * outerRange / totalRange // Mix the `source` with the `result` based on the `alpha` value. result := (1.0 - alpha) * nz(result, source) + alpha * source // Return a tuple containing the `result` and other local variables. [result, q1, q3, outerRange, totalRange, alpha] // Declare a tuple containing all values returned by `customMA()`. [maValue, q1Debug, q3Debug, outerRangeDebug, totalRangeDebug, alphaDebug] = customMA(close, lengthInput) // Plot the `maValue`. plot(maValue, "Custom MA", color.blue, 3) //@variable Display location for plots with different scale. notOnPane = display.all - display.pane // Display the extracted `q1` and `q3` values in all plot locations. plot(q1Debug, "q1", color.new(color.maroon, 50)) plot(q3Debug, "q3", color.new(color.teal, 50)) // Display the other extracted values in the status line and Data Window to avoid impacting the scale. plot(outerRangeDebug, "outerRange", chart.fg_color, display = notOnPane) plot(totalRangeDebug, "totalRange", chart.fg_color, display = notOnPane) plot(alphaDebug, "alpha", chart.fg_color, display = notOnPane) // Highlight the chart when `alphaDebug` is 0, i.e., when the `maValue` does not change. bgcolor(alphaDebug == 0.0 ? color.new(color.orange, 90) : na, title = "`alpha == 0.0` highlight")</div> <p>Note that:</p> <ul> <li>We used <code dir="auto">display.all - display.pane</code> for the plots of the <code dir="auto">outerRangeDebug</code>, <code dir="auto">totalRangeDebug</code>, and <code dir="auto">alphaDebug</code> variables to <a href="/pine-script-docs/writing/debugging/#without-affecting-the-scale">avoid impacting the chart’s scale</a>.</li> <li>The script also uses a <a href="/pine-script-docs/writing/debugging/#conditional-colors">conditional color</a> to highlight the chart pane’s <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">background</a> when <code dir="auto">debugAlpha</code> is 0, indicating the <code dir="auto">maValue</code> does not change.</li> </ul> <p>Another, more <em>advanced</em> way to extract the values of a function’s local variables is to pass them to a <em>reference type</em> variable declared in the global scope.</p> <p>Function scopes can access global variables for their calculations. While a script cannot directly reassign the values of global variables from within a function’s scope, it can update the <em>elements or properties</em> of those values if they are reference types, such as <a href="/pine-script-docs/language/arrays/">arrays</a>, <a href="/pine-script-docs/language/matrices/">matrices</a>, <a href="/pine-script-docs/language/maps/">maps</a>, and <a href="/pine-script-docs/language/type-system/#user-defined-types">user-defined types</a>.</p> <p>This version declares a <code dir="auto">debugData</code> variable in the global scope that references a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_map">map</a> with “string” keys and “float” values. Within the local scope of the <code dir="auto">customMA()</code> function, the script puts <em>key-value pairs</em> containing each local variable’s name and value into the map. After calling the function, the script plots the stored <code dir="auto">debugData</code> values:</p> <div class="pine-colorizer not-content">//@version=6 indicator("Extracting local variables with reference types demo", "Custom MA", true) //@variable The number of bars in the `customMA()` calculation. int lengthInput = input.int(50, "Length", 2) //@variable A map with "string" keys and "float" values for debugging the `customMA()`. map<string, float> debugData = map.new<string, float>() //@function Calculates a moving average that only responds to values outside the first and third quartiles. //@param source The series of values to process. //@param length The number of bars in the calculation. //@returns The moving average value. customMA(float source, int length) => //@variable The custom moving average. var float result = na // Calculate the 25th and 75th `source` percentiles. float q1 = ta.percentile_linear_interpolation(source, length, 25), map.put(debugData, "q1", q1) float q3 = ta.percentile_linear_interpolation(source, length, 75), map.put(debugData, "q3", q3) // Calculate the range values. float outerRange = math.max(source - q3, q1 - source, 0.0), map.put(debugData, "outerRange", outerRange) float totalRange = ta.range(source, length), map.put(debugData, "totalRange", totalRange) //@variable Half the ratio of the `outerRange` to the `totalRange`. float alpha = 0.5 * outerRange / totalRange, map.put(debugData, "alpha", alpha) // Mix the `source` with the `result` based on the `alpha` value. result := (1.0 - alpha) * nz(result, source) + alpha * source // Return the `result`. result //@variable The `customMA()` result over `lengthInput` bars. float maValue = customMA(close, lengthInput) // Plot the `maValue`. plot(maValue, "Custom MA", color.blue, 3) //@variable Display location for plots with different scale. notOnPane = display.all - display.pane // Display the extracted `q1` and `q3` values in all plot locations. plot(map.get(debugData, "q1"), "q1", color.new(color.maroon, 50)) plot(map.get(debugData, "q3"), "q3", color.new(color.teal, 50)) // Display the other extracted values in the status line and Data Window to avoid impacting the scale. plot(map.get(debugData, "outerRange"), "outerRange", chart.fg_color, display = notOnPane) plot(map.get(debugData, "totalRange"), "totalRange", chart.fg_color, display = notOnPane) plot(map.get(debugData, "alpha"), "alpha", chart.fg_color, display = notOnPane) // Highlight the chart when the extracted `alpha` is 0, i.e., when the `maValue` does not change. bgcolor(map.get(debugData, "alpha") == 0.0 ? color.new(color.orange, 90) : na, title = "`alpha == 0.0` highlight")</div> <p>Note that:</p> <ul> <li>We placed each <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_map.put">map.put()</a> call on the same line as each variable declaration, separated by a comma, to keep things concise and avoid adding extra lines to the <code dir="auto">customMA()</code> code.</li> <li>We used <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_map.get">map.get()</a> to retrieve each value for the debug <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plot">plot()</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">bgcolor()</a> calls.</li> </ul> <h3 id="local-drawings-and-logs" class="md-heading"><a href="#local-drawings-and-logs">Local drawings and logs<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>Unlike <code dir="auto">plot.*()</code> functions and others that require values accessible to the global scope, scripts can generate <a href="/pine-script-docs/language/type-system/#drawing-types">drawing objects</a> and <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> from directly within a function, allowing programmers to flexibly debug its local variables <em>without</em> extracting values to the outer scope.</p> <p>In this example, we used <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> and <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> to display <a href="/pine-script-docs/writing/debugging/#representing-other-types">string representations</a> of the values within the <code dir="auto">customMA()</code> scope. Inside the function, the script calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.format">str.format()</a> to create a formatted string representing the local scope’s data, then calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_label.new">label.new()</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a> to respectively display the text on the chart in a tooltip and log an “info” message containing the text in the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> pane:</p> <p><img src="/pine-script-docs/_astro/Debugging-Debugging-functions-Local-drawings-and-logs-1.iGi0vyrx_2s4zkG.webp" alt="image" width="1342" height="528" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Local drawings and logs demo", "Custom MA", true, max_labels_count = 500) //@variable The number of bars in the `customMA()` calculation. int lengthInput = input.int(50, "Length", 2) //@function Calculates a moving average that only responds to values outside the first and third quartiles. //@param source The series of values to process. //@param length The number of bars in the calculation. //@returns The moving average value. customMA(float source, int length) => //@variable The custom moving average. var float result = na // Calculate the 25th and 75th `source` percentiles. float q1 = ta.percentile_linear_interpolation(source, length, 25) float q3 = ta.percentile_linear_interpolation(source, length, 75) // Calculate the range values. float outerRange = math.max(source - q3, q1 - source, 0.0) float totalRange = ta.range(source, length) //@variable Half the ratio of the `outerRange` to the `totalRange`. float alpha = 0.5 * outerRange / totalRange // Mix the `source` with the `result` based on the `alpha` value. result := (1.0 - alpha) * nz(result, source) + alpha * source //@variable A formatted string containing representations of all local variables. string debugText = str.format( "\n`customMA()` data\n----------\nsource: {0, number, #.########}\nlength: {1}\nq1: {2, number, #.########} \nq3: {3, number, #.########}\nouterRange: {4, number, #.########}\ntotalRange: {5, number, #.########} \nalpha{6, number, #.########}\nresult: {7, number, #.########}", source, length, q1, q3, outerRange, totalRange, alpha, result ) // Draw a label with a tooltip displaying the `debugText`. label.new(bar_index, high, color = color.new(chart.fg_color, 80), tooltip = debugText) // Print an "info" message in the Pine Logs pane when the bar is confirmed. if barstate.isconfirmed log.info(debugText) // Return the `result`. result //@variable The `customMA()` result over `lengthInput` bars. float maValue = customMA(close, lengthInput) // Plot the `maValue`. plot(maValue, "Custom MA", color.blue, 3)</div> <p>Note that:</p> <ul> <li>We included <code dir="auto">max_labels_count = 500</code> in the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_indicator">indicator()</a> function to display <a href="/pine-script-docs/concepts/text-and-shapes/#labels">labels</a> for the most recent 500 <code dir="auto">customMA()</code> calls.</li> <li>The function uses <a href="https://www.tradingview.com/pine-script-reference/v6/#var_barstate.isconfirmed">barstate.isconfirmed</a> in an <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_if">if</a> statement to only call <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a> on <em>confirmed</em> bars. It does not log a new message on each realtime tick.</li> </ul> <h2 id="debugging-loops" class="md-heading"><a href="#debugging-loops">Debugging loops<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <p><a href="/pine-script-docs/language/loops/">Loops</a> are structures that repeatedly execute a code block based on a <em>counter</em> (<a href="https://www.tradingview.com/pine-script-reference/v6/#kw_for">for</a>), the contents of a <a href="/pine-script-docs/language/type-system/#collections">collection</a> (<a href="https://www.tradingview.com/pine-script-reference/v6/#kw_for...in">for…in</a>), or a <em>condition</em> (<a href="https://www.tradingview.com/pine-script-reference/v6/#kw_while">while</a>). They allow scripts to perform repetitive tasks without the need for redundant lines of code.</p> <p>Each loop instance maintains a separate local scope, which all outer scopes cannot access. All variables declared within a loop’s scope are specific to that loop, meaning one cannot use them in an outer scope.</p> <p>As with other structures in Pine, there are numerous possible ways to debug loops. This section explores a few helpful techniques, including extracting local values for <a href="/pine-script-docs/concepts/plots/">plots</a>, inspecting values with <a href="/pine-script-docs/language/type-system/#drawing-types">drawings</a>, and tracing a loop’s execution with <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a>.</p> <p>We will use this script as a starting point for the examples in the following segments. It aggregates the <a href="https://www.tradingview.com/pine-script-reference/v6/#var_close">close</a> value’s rates of change over 1 - <code dir="auto">lookbackInput</code> bars and accumulates them in a <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_for">for</a> loop, then divides the result by the <code dir="auto">lookbackInput</code> to calculate a final average value:</p> <p><img src="/pine-script-docs/_astro/Debugging-Debugging-loops-1.Co481TKA_ZQmJYP.webp" alt="image" width="1342" height="504" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Debugging loops demo", "Aggregate ROC") //@variable The number of bars in the calculation. int lookbackInput = input.int(20, "Lookback", 1) //@variable The average ROC of `close` prices over each length from 1 to `lookbackInput` bars. float aroc = 0.0 // Calculation loop. for length = 1 to lookbackInput //@variable The `close` value `length` bars ago. float pastClose = close[length] //@variable The `close` rate of change over `length` bars. float roc = (close - pastClose) / pastClose // Add the `roc` to `aroc`. aroc += roc // Divide `aroc` by the `lookbackInput`. aroc /= lookbackInput // Plot the `aroc`. plot(aroc, "aroc", color.blue, 3)</div> <p>Note that:</p> <ul> <li>The <code dir="auto">aroc</code> is a <em>global</em> variable modified within the loop, whereas <code dir="auto">pastClose</code> and <code dir="auto">roc</code> are <em>local</em> variables inaccessible to the outer scope.</li> </ul> <h3 id="inspecting-a-single-iteration" class="md-heading"><a href="#inspecting-a-single-iteration">Inspecting a single iteration<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>When a programmer needs to focus on a specific loop iteration, there are multiple techniques they can use, most of which entail using a <em>condition</em> inside the loop to trigger debugging actions, such as extracting values to outer variables, creating <a href="/pine-script-docs/language/type-system/#drawing-types">drawings</a>, <a href="/pine-script-docs/writing/debugging/#pine-logs">logging</a> messages, etc.</p> <p>This example inspects the local <code dir="auto">roc</code> value from a single iteration of the loop in three different ways. When the loop counter’s value equals the <code dir="auto">debugCounterInput</code>, the script assigns the <code dir="auto">roc</code> to an <code dir="auto">rocDebug</code> variable from the global scope for <a href="/pine-script-docs/writing/debugging/#plotting-numbers">plotting</a>, draws a vertical <a href="https://www.tradingview.com/pine-script-reference/v6/#type_line">line</a> from 0 to the <code dir="auto">roc</code> value using <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_line.new">line.new()</a>, and logs a message in the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> pane using <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a>:</p> <p><img src="/pine-script-docs/_astro/Debugging-Debugging-loops-Inspecting-a-single-iteration-1.tCjAEA7s_1OlVrm.webp" alt="image" width="1342" height="664" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Inspecting a single iteration demo", "Aggregate ROC", max_lines_count = 500) //@variable The number of bars in the calculation. int lookbackInput = input.int(20, "Lookback", 1) //@variable The `length` value in the loop's execution where value extraction occurs. int debugCounterInput = input.int(1, "Loop counter value", 1, group = "Debugging") //@variable The `roc` value extracted from the loop. float rocDebug = na //@variable The average ROC of `close` over lags from 1 to `lookbackInput` bars. float aroc = 0.0 // Calculation loop. for length = 1 to lookbackInput //@variable The `close` value `length` bars ago. float pastClose = close[length] //@variable The `close` rate of change over `length` bars. float roc = (close - pastClose) / pastClose // Add the `roc` to `aroc`. aroc += roc // Trigger debug actions when the `length` equals the `debugCounterInput`. if length == debugCounterInput // Assign `roc` to `rocDebug` so the script can plot its value. rocDebug := roc // Draw a vertical line from 0 to the `roc` at the `bar_index`. line.new(bar_index, 0.0, bar_index, roc, color = color.new(color.gray, 50), width = 4) // Log an "info" message in the Pine Logs pane. log.info("{0}-bar `roc`{1}: {2, number, #.########}", length, barstate.isconfirmed ? " (confirmed)" : "", roc) // Divide `aroc` by the `lookbackInput`. aroc /= lookbackInput // Plot the `aroc`. plot(aroc, "aroc", color.blue, 3) // Plot the `rocDebug`. plot(rocDebug, "Extracted roc", color.new(color.rgb(206, 55, 136), 40), 2)</div> <p>Note that:</p> <ul> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_input.int">input.int()</a> call assigned to the <code dir="auto">debugCounterInput</code> includes a <code dir="auto">group</code> argument to distinguish it in the script’s settings.</li> <li>The <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a> call includes “(confirmed)” in the formatted message whenever <a href="https://www.tradingview.com/pine-script-reference/v6/#var_barstate.isconfirmed">barstate.isconfirmed</a> is <code dir="auto">true</code>. Searching this text in the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> pane will filter out the entries from unconfirmed bars. See the <a href="/pine-script-docs/writing/debugging/#filtering-logs">Filtering logs</a> section above.</li> </ul> <h3 id="inspecting-multiple-iterations" class="md-heading"><a href="#inspecting-multiple-iterations">Inspecting multiple iterations<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>When inspecting the values from several loop iterations, it’s often helpful to utilize <a href="/pine-script-docs/language/type-system/#collections">collections</a> or strings to gather the results for use in output functions after the loop terminates.</p> <p>This version demonstrates a few ways to collect and display the loop’s values from all iterations. It declares a <code dir="auto">logText</code> string and a <code dir="auto">debugValues</code> array in the global scope. Inside the local scope of the <a href="https://www.tradingview.com/pine-script-reference/v6/#kw_for">for</a> loop, the script <em>concatenates</em> a <a href="/pine-script-docs/writing/debugging/#representing-other-types">string representation</a> of the <code dir="auto">length</code> and <code dir="auto">roc</code> with the <code dir="auto">logText</code> and calls <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_array.push">array.push()</a> to push the iteration’s <code dir="auto">roc</code> value into the <code dir="auto">debugValues</code> array.</p> <p>After the loop ends, the script <a href="/pine-script-docs/writing/debugging/#plotting-numbers">plots</a> the <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_array.first">first</a> and <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_array.last">last</a> value from the <code dir="auto">debugValues</code> array, draws a <a href="https://www.tradingview.com/pine-script-reference/v6/#type_label">label</a> with a <em>tooltip</em> showing a <a href="/pine-script-docs/writing/debugging/#representing-other-types">string representation</a> of the <a href="https://www.tradingview.com/pine-script-reference/v6/#type_array">array</a>, and displays the <code dir="auto">logText</code> in the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> pane upon the bar’s confirmation:</p> <p><img src="/pine-script-docs/_astro/Debugging-Debugging-loops-Inspecting-multiple-iterations-1.CYLBy0Wy_ZVV2R6.webp" alt="image" width="1342" height="588" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Inspecting multiple iterations demo", "Aggregate ROC", max_labels_count = 500) //@variable The number of bars in the calculation. int lookbackInput = input.int(20, "Lookback", 1) //@variable An array containing the `roc` value from each loop iteration. array<float> debugValues = array.new<float>() //@variable A "string" containing information about the `roc` on each iteration. string logText = "" //@variable The average ROC of `close` over lags from 1 to `lookbackInput` bars. float aroc = 0.0 // Calculation loop. for length = 1 to lookbackInput //@variable The `close` value `length` bars ago. float pastClose = close[length] //@variable The `close` rate of change over `length` bars. float roc = (close - pastClose) / pastClose // Add the `roc` to `aroc`. aroc += roc // Concatenate a new "string" representation with the `debugText`. logText += "\nlength: " + str.tostring(length) + ", roc: " + str.tostring(roc) // Push the `roc` value into the `debugValues` array. array.push(debugValues, roc) // Divide `aroc` by the `lookbackInput`. aroc /= lookbackInput // Plot the `aroc`. plot(aroc, "aroc", color.blue, 3) // Plot the `roc` values from the first and last iteration. plot(array.first(debugValues), "First iteration roc", color.new(color.rgb(166, 84, 233), 50), 2) plot(array.last(debugValues), "Last iteration roc", color.new(color.rgb(115, 86, 218), 50), 2) // Draw a label with a tooltip containing a "string" representation of the `debugValues` array. label.new(bar_index, aroc, color = color.new(color.rgb(206, 55, 136), 70), tooltip = str.tostring(debugValues)) // Log the `logText` in the Pine Logs pane when the bar is confirmed. if barstate.isconfirmed log.info(logText)</div> <p>Another way to inspect a loop over several iterations is to generate sequential <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> or create/modify <a href="/pine-script-docs/language/type-system/#drawing-types">drawing objects</a> within the loop’s scope to trace its execution pattern with granular detail.</p> <p>This example uses <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> to trace the execution flow of our script’s loop. It generates a new “info” message on each iteration to track the local scope’s calculations as the loop progresses on each confirmed bar:</p> <p><img src="/pine-script-docs/_astro/Debugging-Debugging-loops-Inspecting-multiple-iterations-2.CahjoXFr_Z1z4bNL.webp" alt="image" width="1342" height="662" loading="lazy" decoding="async"></p> <div class="pine-colorizer not-content">//@version=6 indicator("Inspecting multiple iterations demo", "Aggregate ROC") //@variable The number of bars in the calculation. int lookbackInput = input.int(20, "Lookback", 1) //@variable The average ROC of `close` over lags from 1 to `lookbackInput` bars. float aroc = 0.0 // Calculation loop. for length = 1 to lookbackInput //@variable The `close` value `length` bars ago. float pastClose = close[length] //@variable The `close` rate of change over `length` bars. float roc = (close - pastClose) / pastClose // Add the `roc` to `aroc`. aroc += roc if barstate.isconfirmed log.info( "{0}\nlength (counter): {1}\npastClose: {2, number, #.#####}\n distance to pastClose: {3, number, #.########}\nroc: {4, number, #.########}\n aroc (before division): {5, number, #.########}\n{6}", length == 1 ? "LOOP START" : "", length, pastClose, close - pastClose, roc, aroc, length == lookbackInput ? "LOOP END" : "" ) // Divide `aroc` by the `lookbackInput`. aroc /= lookbackInput // Plot the `aroc`. plot(aroc, "aroc", color.blue, 3)</div> <p>Note that:</p> <ul> <li>When iteratively generating <a href="/pine-script-docs/writing/debugging/#pine-logs">logs</a> or drawings from inside a loop, make it a point to avoid unnecessary clutter and strive for easy navigation. More is not always better for debugging, especially when working within loops.</li> </ul> <h2 id="tips" class="md-heading"><a href="#tips">Tips<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h2> <h3 id="organization-and-readability" class="md-heading"><a href="#organization-and-readability">Organization and readability<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>When writing scripts, it’s wise to prioritize organized, readable source codes. Code that’s organized and easy to read helps streamline the debugging process. Additionally, well-written code is easier to maintain over time.</p> <p>Here are a few quick tips based on our <a href="/pine-script-docs/writing/style-guide/">Style guide</a> and the examples on this page:</p> <ul> <li>Aim to follow the general <a href="/pine-script-docs/writing/style-guide/#script-organization">script organization</a> recommendations. Organizing scripts using this structure makes things easier to locate and inspect.</li> <li>Choose variable and function names that make them easy to <em>identify</em> and <em>understand</em>. See the <a href="/pine-script-docs/writing/style-guide/#naming-conventions">Naming conventions</a> section for some examples.</li> <li>It’s often helpful to temporarily assign important parts of expressions to variables with informative names while debugging. Breaking expressions down into reusable parts helps simplify inspection processes.</li> <li>Use <em>comments</em> and <em>annotations</em> (<code dir="auto">//@function</code>, <code dir="auto">//@variable</code>, etc.) to document your code. Annotations are particularly helpful, as the Pine Editor’s autosuggest displays variable and function descriptions in a pop-up when hovering over their identifiers anywhere in the code.</li> <li>Remember that <em>less is more</em> in many cases. Don’t overwhelm yourself with excessive script outputs or unnecessary information while debugging. Keep things simple, and only include as much information as you need.</li> </ul> <h3 id="speeding-up-repetitive-tasks" class="md-heading"><a href="#speeding-up-repetitive-tasks">Speeding up repetitive tasks<span class="icon icon-link" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 28 28"><g fill="currentColor" clip-path="url(#a)"><path d="M14.908 5.558a5.326 5.326 0 1 1 7.533 7.533l-3.236 3.236-1.061-1.061 3.236-3.236a3.826 3.826 0 1 0-5.411-5.411l-3.236 3.236-1.06-1.06 3.235-3.237ZM5.56 14.907a5.326 5.326 0 0 0 7.532 7.533l3.236-3.236-1.061-1.061-3.236 3.236a3.826 3.826 0 1 1-5.411-5.411l3.236-3.236-1.061-1.06-3.236 3.235Z"></path><path d="m16.346 10.592-5.753 5.753 1.061 1.06 5.753-5.752-1.06-1.06Z"></path></g><defs><clippath id="a"><path fill="#fff" d="M0 0h28v28H0z"></path></clippath></defs></svg></span></a></h3> <p>There are a few handy techniques we often utilize when debugging our code:</p> <ul> <li>We use <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a> or <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotshape">plotshape()</a> to quickly display the results of “int”, “float”, or “bool” variables and expressions in the script’s status line and the Data Window.</li> <li>We often use <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">bgcolor()</a> to visualize the history of certain <a href="/pine-script-docs/writing/debugging/#conditions">conditions</a> on the chart.</li> <li>We use a one-line version of our <code dir="auto">printLabel()</code> function from <a href="/pine-script-docs/writing/debugging/#at-the-end-of-the-chart">this section</a> to print strings at the end of the chart.</li> <li>We use a <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_label.new">label.new()</a> call with a <code dir="auto">tooltip</code> argument to display strings in tooltips <a href="/pine-script-docs/writing/debugging/#on-successive-bars">on successive bars</a>.</li> <li>We use the <code dir="auto">log.*()</code> functions to quickly display data with <a href="/pine-script-docs/writing/debugging/#representing-other-types">string representations</a> in the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> pane.</li> </ul> <p>When one establishes their typical debugging processes, it’s often helpful to create <em>keyboard macros</em> to speed up repetitive tasks and spend less time setting up debug outputs in each code.</p> <p>The following is a simple <em>AutoHotkey</em> script (<strong>not</strong> Pine Script™ code) that includes hotstrings for the above five techniques. The script generates code snippets by entering a specified character sequence followed by a whitespace:</p> <div class="expressive-code not-content"><figure class="frame"><figcaption class="header"></figcaption><pre data-language="txt"><code><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">; ————— This is AHK code, not Pine Script™. —————</span></div></div><div class="ec-line"><div class="code"> </div></div><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">; Specify that hotstrings trigger when they end with space, tab, linefeed, or carriage return.</span></div></div><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">#Hotstring EndChars `t `n `r</span></div></div><div class="ec-line"><div class="code"> </div></div><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">:X:,,show::SendInput, plotchar(%Clipboard%, "%Clipboard%", "", color = chart.fg_color, display = display.all - display.pane){Enter}</span></div></div><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">:X:,,highlight::SendInput, bgcolor(bool(%Clipboard%) ? color.new(color.orange, 80) : na, title = "%Clipboard% highlight"){Enter}</span></div></div><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">:X:,,print::SendInput, printLabel(string txt, float price = na) => int labelTime = math.max(last_bar_time, chart.right_visible_bar_time), var label result = label.new(labelTime, na, txt, xloc.bar_time, na(price) ? yloc.abovebar : yloc.price, na, label.style_none, chart.fg_color, size.large), label.set_text(result, txt), label.set_y(result, price), result`nprintLabel(){Left}</span></div></div><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">:X:,,tooltip::SendInput, label.new(bar_index, high, color = color.new(chart.fg_color, 70), tooltip = str.tostring(%Clipboard%)){Enter}</span></div></div><div class="ec-line"><div class="code"><span style="--0:#e1e4e8;--1:#24292e">:X:,,log::SendInput, log.info(str.tostring(%Clipboard%)){Enter}</span></div></div></code></pre></figure></div> <p>The “,,show” macro generates a <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_plotchar">plotchar()</a> call that uses the clipboard’s contents for the <code dir="auto">series</code> and <code dir="auto">title</code> arguments. Copying a <code dir="auto">variableName</code> variable or the <code dir="auto">close > open</code> expression and typing “,,show” followed by a space will respectively yield:</p> <div class="pine-colorizer not-content">plotchar(variableName, "variableName", "", color = chart.fg_color, display = display.all - display.pane) plotchar(close > open, "close > open", "", color = chart.fg_color, display = display.all - display.pane)</div> <p>The “,,highlight” macro generates a <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_bgcolor">bgcolor()</a> call that highlights the chart pane’s background with a <a href="/pine-script-docs/writing/debugging/#conditional-colors">conditional color</a> based on the variable or expression copied to the clipboard. For example, copying the <a href="https://www.tradingview.com/pine-script-reference/v6/#var_barstate.isrealtime">barstate.isrealtime</a> variable and typing “,,highlight” followed by a space will yield:</p> <div class="pine-colorizer not-content">bgcolor(bool(barstate.isrealtime) ? color.new(color.orange, 80) : na, title = "barstate.isrealtime highlight")</div> <p>The “,,print” macro generates the one-line <code dir="auto">printLabel()</code> function and creates an empty <code dir="auto">printLabel()</code> call with the cursor placed inside it. All you need to do after typing “,,print” followed by a space is enter the text you want to display:</p> <div class="pine-colorizer not-content">printLabel(string txt, float price = na) => int labelTime = math.max(last_bar_time, chart.right_visible_bar_time), var label result = label.new(labelTime, na, txt, xloc.bar_time, na(price) ? yloc.abovebar : yloc.price, na, label.style_none, chart.fg_color, size.large), label.set_text(result, txt), label.set_y(result, price), result printLabel()</div> <p>The “,,tooltip” macro generates a <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_label.new">label.new()</a> call with a <code dir="auto">tooltip</code> argument that uses <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.tostring">str.tostring()</a> on the clipboard’s contents. Copying the <code dir="auto">variableName</code> variable and typing “,,tooltip” followed by a space yields:</p> <div class="pine-colorizer not-content">label.new(bar_index, high, color = color.new(chart.fg_color, 70), tooltip = str.tostring(variableName))</div> <p>The “,,log” macro generates a <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_log.info">log.info()</a> call with a <code dir="auto">message</code> argument that uses <a href="https://www.tradingview.com/pine-script-reference/v6/#fun_str.tostring">str.tostring()</a> on the clipboard’s contents to display string representations of variables and expressions in the <a href="/pine-script-docs/writing/debugging/#pine-logs">Pine Logs</a> pane. Copying the expression <code dir="auto">bar_index % 2 == 0</code> and typing “,,log” followed by a space yields:</p> <div class="pine-colorizer not-content">log.info(str.tostring(bar_index % 2 == 0))</div> <p>Note that:</p> <ul> <li>AHK is available for <em>Windows</em> devices. Research other software to employ a similar process if your machine uses a different operating system.</li> </ul> </div> <div class="pagination-buttons not-content" data-astro-cid-xgirumru> <a href="/pine-script-docs/writing/style-guide" class="pagination-card" data-pagefind-ignore data-astro-cid-assl6cvf> <p data-astro-cid-assl6cvf>Previous</p> <h4 class="pagination-card-header" data-astro-cid-assl6cvf> <svg width="28" height="28" viewBox="0 0 28 28" data-astro-cid-assl6cvf data-icon="theme/arrow-back"> <use xlink:href="#ai:local:theme/arrow-back"></use> </svg> Style guide </h4> </a> <a href="/pine-script-docs/writing/profiling-and-optimization" class="pagination-card" data-pagefind-ignore data-astro-cid-assl6cvf> <p data-astro-cid-assl6cvf>Next</p> <h4 class="pagination-card-header" data-astro-cid-assl6cvf> Profiling and optimization <svg width="28" height="28" viewBox="0 0 28 28" data-astro-cid-assl6cvf data-icon="theme/arrow"> <symbol id="ai:local:theme/arrow"><path fill="none" stroke="var(--arrow-fill-color, #131722)" d="m11 8 6 6-6 6"/></symbol><use xlink:href="#ai:local:theme/arrow"></use> </svg> </h4> </a> </div> </main> <div id="toc" data-pagefind-ignore="all" data-astro-cid-oor6cujd><aside class="document-toc-container ml-4 w-48" data-astro-cid-oor6cujd><section id="toc-scroll-section" class="slick-scroll" data-astro-cid-oor6cujd><header data-astro-cid-oor6cujd><h2 class="toc-header" data-astro-cid-oor6cujd>On this page</h2></header><ul class="" id="toc-entries" data-astro-cid-oor6cujd><a href="#introduction" aria-current="true" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-current data-astro-cid-oor6cujd>Introduction</li></a><a href="#the-lay-of-the-land" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-astro-cid-oor6cujd>The lay of the land</li></a><a href="#numeric-values" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-astro-cid-oor6cujd>Numeric values</li></a><a href="#plotting-numbers" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Plotting numbers</li></a><a href="#without-affecting-the-scale" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-4" data-astro-cid-oor6cujd>Without affecting the scale</li></a><a href="#from-local-scopes" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-4" data-astro-cid-oor6cujd>From local scopes</li></a><a href="#with-drawings" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>With drawings</li></a><a href="#conditions" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-astro-cid-oor6cujd>Conditions</li></a><a href="#as-numbers" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>As numbers</li></a><a href="#plotting-conditional-shapes" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Plotting conditional shapes</li></a><a href="#conditional-colors" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Conditional colors</li></a><a href="#using-drawings" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Using drawings</li></a><a href="#compound-and-nested-conditions" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Compound and nested conditions</li></a><a href="#strings" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-astro-cid-oor6cujd>Strings</li></a><a href="#representing-other-types" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Representing other types</li></a><a href="#using-labels" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Using labels</li></a><a href="#on-successive-bars" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-4" data-astro-cid-oor6cujd>On successive bars</li></a><a href="#at-the-end-of-the-chart" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-4" data-astro-cid-oor6cujd>At the end of the chart</li></a><a href="#using-tables" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Using tables</li></a><a href="#pine-logs" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-astro-cid-oor6cujd>Pine Logs</li></a><a href="#creating-logs" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Creating logs</li></a><a href="#inspecting-logs" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Inspecting logs</li></a><a href="#filtering-logs" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Filtering logs</li></a><a href="#using-inputs" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-4" data-astro-cid-oor6cujd>Using inputs</li></a><a href="#debugging-functions" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-astro-cid-oor6cujd>Debugging functions</li></a><a href="#extracting-local-variables" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Extracting local variables</li></a><a href="#local-drawings-and-logs" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Local drawings and logs</li></a><a href="#debugging-loops" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-astro-cid-oor6cujd>Debugging loops</li></a><a href="#inspecting-a-single-iteration" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Inspecting a single iteration</li></a><a href="#inspecting-multiple-iterations" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Inspecting multiple iterations</li></a><a href="#tips" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-2" data-astro-cid-oor6cujd>Tips</li></a><a href="#organization-and-readability" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Organization and readability</li></a><a href="#speeding-up-repetitive-tasks" class="document-toc-link" data-astro-cid-oor6cujd><li class="l-3" data-astro-cid-oor6cujd>Speeding up repetitive tasks</li></a></ul></section><div class="toc-bottom-fade" data-astro-cid-oor6cujd></div><div class="back-top-space" data-astro-cid-oor6cujd><div class="not-content" style="" data-astro-cid-pkzv2hgs> <a id="back-top-button" title="Back to top" href="#top" data-astro-cid-pkzv2hgs class="floating-button not-content stvb-base stvb-pointer stvb-gray stvb-medium stvb-secondary stvb-icon stvb-icon-force-color stvb-force-no-border"> <svg width="18" height="18" viewBox="0 0 18 18" data-astro-cid-oor6cujd data-icon="theme/arrow-up"> <symbol id="ai:local:theme/arrow-up"><g fill="none"><g clip-path="url(#a)"><path fill="currentColor" fill-rule="evenodd" d="m9 3.5.5.44 4 3.5-1 1.12-2.75-2.4V14h-1.5V6.15L5.49 8.56l-.98-1.12 4-3.5L9 3.5Z" clip-rule="evenodd"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h18v18H0z"/></clipPath></defs></g></symbol><use xlink:href="#ai:local:theme/arrow-up"></use> </svg> </a> </div> </div></aside></div> </main> </div> <footer data-astro-cid-b6pf7ola> <div class="footer-content" data-astro-cid-b6pf7ola> <ul data-astro-cid-b6pf7ola> <li data-astro-cid-b6pf7ola> <a href="https://www.tradingview.com/chat/#BfmVowG1TZkKO235" data-astro-cid-b6pf7ola>Pine Q&A chat</a> </li><li data-astro-cid-b6pf7ola> <a href="https://stackoverflow.com/questions/tagged/pine-script" data-astro-cid-b6pf7ola>Stack Overflow</a> ↗ </li><li data-astro-cid-b6pf7ola> <a href="https://t.me/PineCodersQA" data-astro-cid-b6pf7ola>Telegram</a> ↗ </li><li data-astro-cid-b6pf7ola> <a href="https://www.reddit.com/r/TradingView/" data-astro-cid-b6pf7ola>Reddit</a> ↗ </li> </ul> <div class="flex" data-astro-cid-b6pf7ola></div> <div class="copyright" data-astro-cid-b6pf7ola>Copyright © 2024 TradingView, Inc.</div> </div> </footer> </body></html>