(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{LEBU:function(e,t,n){"use strict";n.r(t),n.d(t,"_frontmatter",(function(){return o})),n.d(t,"default",(function(){return m}));var a=n("Fcif"),l=n("dV/x"),b=(n("mXGw"),n("/FXl")),r=n("TjRS"),i=n("wCAC");n("l1C2");const c=["components"],o={};void 0!==o&&o&&o===Object(o)&&Object.isExtensible(o)&&!Object.prototype.hasOwnProperty.call(o,"__filemeta")&&Object.defineProperty(o,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/components/uk/Scripting.mdx"}});const p={_frontmatter:o},d=r.a;function m(e){let{components:t}=e,n=Object(l.a)(e,c);return Object(b.b)(d,Object(a.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(b.b)("h1",{id:"api-для-користувацьких-індикаторів"},"API для користувацьких індикаторів"),Object(b.b)(i.e,{mdxType:"Lead"},"Пишіть власні індикатори на JavaScript, запускайте їх у безпечній пісочниці поруч із графіком і діліться ними з іншими користувачами. API надає ринкові дані (свічки, стакани, кластери, ліквідації, дані деривативів), примітиви для відображення, функції технічного аналізу та алерти."),Object(b.b)("h2",{id:"генерація-індикаторів-за-допомогою-ші"},"Генерація індикаторів за допомогою ШІ"),Object(b.b)("p",null,"Весь API також доступний у вигляді одного текстового файлу для мовних моделей: ",Object(b.b)("a",{parentName:"p",href:"../../public/AI-scripting.txt"},"AI-scripting.txt"),". Прикріпіть його до ChatGPT, Claude, Gemini або будь-якої іншої LLM і опишіть індикатор, який вам потрібен."),Object(b.b)("p",null,"Приклад запиту:"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-text"},"Read the attached [AI-scripting.txt] https://mobchart.com/docs/public/AI-scripting.txt file and use it as the only reference for the MobChart scripting API.\n\nCreate a custom indicator that plots a 20-period EMA and a 50-period EMA on the chart. Color the candles green when EMA20 is above EMA50 and red otherwise.\n\nUse only the documented API. Do not invent functions. Return the complete indicator code.\n")),Object(b.b)("h2",{id:"пісочниця-та-обмеження"},"Пісочниця та обмеження"),Object(b.b)(i.b,{type:"warning",title:"Поточні обмеження",mdxType:"Callout"},Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},"Скрипти виконуються в безпечній JavaScript-пісочниці."),Object(b.b)("li",{parentName:"ul"},"На виконання скрипту виділяється ",Object(b.b)("inlineCode",{parentName:"li"},"1500ms"),"."),Object(b.b)("li",{parentName:"ul"},"Довжина повернених масивів даних обмежена ",Object(b.b)("strong",{parentName:"li"},"5000")," елементами, тому індикатор не може поширюватися глибше ніж на ",Object(b.b)("strong",{parentName:"li"},"5000 свічок"),"."),Object(b.b)("li",{parentName:"ul"},"У межах одного індикатора доступно до ",Object(b.b)("strong",{parentName:"li"},"8 звернень"),' до джерел даних. Запит понад ліміт кидає помилку, і запуск зупиняється з позначкою "too much sources".'),Object(b.b)("li",{parentName:"ul"},"У межах одного запуску доступно до ",Object(b.b)("strong",{parentName:"li"},"3 HTTP-запитів")," (",Object(b.b)("inlineCode",{parentName:"li"},"http.get")," / ",Object(b.b)("inlineCode",{parentName:"li"},"http.post"),"), див. розділ ",Object(b.b)("strong",{parentName:"li"},"HTTP-запити"),"."))),Object(b.b)("h2",{id:"розробка-індикатора"},"Розробка індикатора"),Object(b.b)("p",null,"Розробка індикатора ведеться всередині окремого віджета, який може розташовуватися поруч із графіком, у якому буде ввімкнено даний індикатор."),Object(b.b)(i.f,{src:"../../public/chart_code.png",mdxType:"Screenshot"}),Object(b.b)("h2",{id:"створення-індикатора"},"Створення індикатора"),Object(b.b)("h3",{id:"definetitle-description-type-ispublic-ispubliccode-options"},Object(b.b)("inlineCode",{parentName:"h3"},"define(title, description, type, isPublic, isPublicCode, options)")),Object(b.b)("p",null,"Реєструє індикатор у системі."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Параметр"),Object(b.b)("th",{parentName:"tr",align:null},"Тип"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"title")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")),Object(b.b)("td",{parentName:"tr",align:null},"Назва індикатора")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"description")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")),Object(b.b)("td",{parentName:"tr",align:null},"Короткий опис")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"type")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"'onchart'")," ","|"," ",Object(b.b)("inlineCode",{parentName:"td"},"'offchart'")),Object(b.b)("td",{parentName:"tr",align:null},"Розташування індикатора (на графіку або в окремій панелі)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"isPublic")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true")," ","|"," ",Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"Індикатор доступний усім")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"isPublicCode")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true")," ","|"," ",Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"Вихідний код індикатора доступний усім")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"options")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"object")," (необов'язково)"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"{ fullRange, warmup }"),", див. нижче")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'define("My Indicator", "Shows EMA line", "onchart", true, false);\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Діапазон розрахунку.")," За замовчуванням скрипт рахує лише ту частину графіка, якій це потрібно: свічки, довантажені під час прокручування назад, або останні свічки під час оновлення, плюс ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"warmup"))," свічок історії перед ними (за замовчуванням 500), які потрібні для розрахунків, але не повертаються. Вкажіть ",Object(b.b)("inlineCode",{parentName:"p"},"warmup"),", якщо індикатору потрібно більше або менше історії, наприклад ",Object(b.b)("inlineCode",{parentName:"p"},"{ warmup: 200 }")," для EMA(200). Скрипт, значення або фігури якого залежать від ",Object(b.b)("strong",{parentName:"p"},"усього видимого діапазону")," (VWAP від першої видимої свічки, накопичена дельта, підпис біля максимуму вікна, рівні через увесь графік), має оголосити ",Object(b.b)("inlineCode",{parentName:"p"},"{ fullRange: true }"),", інакше після довантаження історії його результати будуть хибними. Режим зчитується з ",Object(b.b)("inlineCode",{parentName:"p"},"define()")," під час кожного збереження: скрипт, збережений без ",Object(b.b)("inlineCode",{parentName:"p"},"fullRange"),", розраховується частково, тому додайте прапорець до наявних накопичувальних скриптів, коли їх редагуєте. Часткові скрипти й завантажуються частинами: під час увімкнення на довгій історії графік спершу запитує останні 500 свічок (або ",Object(b.b)("inlineCode",{parentName:"p"},"warmup")," свічок, якщо це більше), а старіші частини — по одному запиту за раз, тож видима частина з'являється одразу. Скрипти з ",Object(b.b)("inlineCode",{parentName:"p"},"fullRange")," завжди розраховуються одним запитом по всьому діапазону."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'define("Window max", "Label at the highest visible high", "onchart", true, true, { fullRange: true });\n')),Object(b.b)("p",null,"Розташування індикаторів при ",Object(b.b)("strong",{parentName:"p"},"onchart")," та ",Object(b.b)("strong",{parentName:"p"},"offchart"),":"),Object(b.b)(i.f,{src:"../../public/onchart_offchart.png",mdxType:"Screenshot"}),Object(b.b)("h2",{id:"введення-параметрів"},"Введення параметрів"),Object(b.b)("p",null,"Класи ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"input"))," та ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"style"))," дозволяють створювати налаштування для користувача (аналог ",Object(b.b)("inlineCode",{parentName:"p"},"input()")," у PineScript)."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number(title, defaultValue, min, max, step)")),Object(b.b)("td",{parentName:"tr",align:null},"Числове введення")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"range(title, defaultValue, min, max, step)")),Object(b.b)("td",{parentName:"tr",align:null},"Введення з діапазону")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"select(title, defaultValue, values)")),Object(b.b)("td",{parentName:"tr",align:null},"Випадний список")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"color(title, defaultValue)")),Object(b.b)("td",{parentName:"tr",align:null},"Вибір кольору")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"boolean(title, defaultValue)")),Object(b.b)("td",{parentName:"tr",align:null},"Двійкова змінна")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tickers(title, defaultValue, exchange)")),Object(b.b)("td",{parentName:"tr",align:null},"Множинний вибір тікерів біржі (за замовчуванням біржа графіка); повертає вибрані тікери масивом")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад (input) для основних параметрів:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const length = input.number("Period", 14, 1, 100, 1);\nconst type = input.select("Type", \'sma\', [\'sma\', \'ema\']);\nconst color = input.color("Line Color", "#FF0000");\n// пари для включення / виключення, вибираються з тікерів біржі графіка\nconst include = input.tickers("Include pairs", []);\nconst exclude = input.tickers("Exclude pairs", []);\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Або (style) для візуальних параметрів:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const length = style.number("Size", 14, 1, 100, 1);\nconst color = style.select("Background Color", \'#FF0000\', ["#FF0000", "#AA0000", "#BB0000"]);\nconst color = style.color("Background Color", "#FF0000");\n')),Object(b.b)(i.f,{src:"../../public/input_style.png",mdxType:"Screenshot"}),Object(b.b)("h2",{id:"джерела-даних"},"Джерела даних"),Object(b.b)("p",null,"Клас ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"source"))," отримує ринкові дані з сервера. Методи за свічками приймають однакові параметри; два живі знімки відрізняються: ",Object(b.b)("inlineCode",{parentName:"p"},"orderbook()")," приймає біржу й тікер, ",Object(b.b)("inlineCode",{parentName:"p"},"levels()")," — біржу та об'єкт налаштувань."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Параметр"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"exchange"),", ",Object(b.b)("inlineCode",{parentName:"td"},"ticker"),", ",Object(b.b)("inlineCode",{parentName:"td"},"timeframe")),Object(b.b)("td",{parentName:"tr",align:null},"За замовчуванням — графік, на якому відкрито індикатор. Передайте інші значення, щоб отримати дані іншого ринку.")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"lookback")),Object(b.b)("td",{parentName:"tr",align:null},"Кількість барів історії від поточної дати, ",Object(b.b)("strong",{parentName:"td"},"не більше 5000"),".")))),Object(b.b)(i.b,{type:"note",title:"Дані вирівняні за свічками графіка",mdxType:"Callout"},Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()"),", ",Object(b.b)("inlineCode",{parentName:"p"},"depths()"),", ",Object(b.b)("inlineCode",{parentName:"p"},"clusters()"),", ",Object(b.b)("inlineCode",{parentName:"p"},"liquidations()")," та ",Object(b.b)("inlineCode",{parentName:"p"},"moreData()")," таймфрейму графіка повертають ",Object(b.b)("strong",{parentName:"p"},"по одному запису на кожну свічку графіка"),": ",Object(b.b)("inlineCode",{parentName:"p"},"depths()[i]")," — це стакан свічки ",Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()[i]"),", ",Object(b.b)("inlineCode",{parentName:"p"},"moreData()[i]")," — її дані по деривативах і так далі. Якщо джерело не має запису для свічки (наприклад, історія стакана коротша за історію свічок), елемент дорівнює ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"null"))," — завжди перевіряйте це. Дані, запитані з ",Object(b.b)("inlineCode",{parentName:"p"},"lookback")," або для іншого таймфрейму, повертаються як є, і їх потрібно зіставляти за ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"startTime")),". ",Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()")," ринку графіка містить лише свічки, які сервер уже завантажив, і ніколи не містить ",Object(b.b)("inlineCode",{parentName:"p"},"null"),"; поки довантажується старіша історія, індикатор перераховується автоматично.")),Object(b.b)("h3",{id:"ohlcvexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"ohlcv(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"Дані свічок."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "open": 115886.17,\n "high": 115911.96,\n "low": 115764.27,\n "close": 115815.16,\n "volume": 228.41528,\n "startTime": 1757699100000\n },\n {...},\n ...\n] \n')),Object(b.b)("h3",{id:"depthsexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"depths(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"Історичні знімки стакана, по одному на свічку. Зберігаються лише найбільші лімітні заявки (дані теплової карти)."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "asks": {\n "109425": 5.467,\n "109495": 3.564,\n ...\n },\n "bids": {\n "33000": 3.746,\n "35000": 16.49,\n ...\n }\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(b.b)("h3",{id:"clustersexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"clusters(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"Кластерні дані (футпринт): обсяг покупок і продажів на кожному ціновому рівні свічки."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "totalBuy": 16053385,\n "totalSell": 20490989,\n "0.8654": { "buy": 286845, "sell": 336689 },\n "0.8653": { "buy": 271848, "sell": 259167 },\n "0.8652": { "buy": 318814, "sell": 373497 },\n ...\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(b.b)("h3",{id:"liquidationsexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"liquidations(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"Ліквідований обсяг на кожному ціновому рівні свічки (лише ф’ючерсні ринки). Той самий формат, що й у ",Object(b.b)("inlineCode",{parentName:"p"},"clusters()"),"."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "totalBuy": 16053385,\n "totalSell": 20490989,\n "0.8654": { "buy": 286845, "sell": 336689 },\n "0.8653": { "buy": 271848, "sell": 259167 },\n "0.8652": { "buy": 318814, "sell": 373497 },\n ...\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(b.b)("h3",{id:"moredataexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"moreData(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"Дані деривативів по свічках: ставка фінансування, свічка відкритого інтересу, співвідношення long/short (лише ф’ючерсні ринки)."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n { \n "data": {\n "FR": 0.00003777, // Funding Rate\n "OI": { // Open Interest Candle\n "open": 85645.708,\n "close": 83496.225,\n "high": 85801.04,\n "low": 83397.918\n },\n "LS": { "l": 0.5426, "s": 0.4574 }, // Long/Short Ratio\n "taLS": { "l": 0.552, "s": 0.448 }, // Top Traders Account Ratio\n "tpLS": { "l": 0.5996, "s": 0.4004 } // Top Traders Position Ratio\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(b.b)("h3",{id:"orderbookexchange-ticker"},Object(b.b)("inlineCode",{parentName:"h3"},"orderbook(exchange, ticker)")),Object(b.b)("p",null,"Актуальний знімок стакана: повний поточний стакан, не прив’язаний до свічок."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'{\n "asks": {\n "109425": 5.467,\n "109495": 3.564,\n ...\n },\n "bids": {\n "109400": 1.2,\n "109390": 0.8,\n ...\n }\n}\n\n')),Object(b.b)("p",null,"Рівні не відсортовані — використовуйте помічники ",Object(b.b)("inlineCode",{parentName:"p"},"ta")," для стакана (",Object(b.b)("inlineCode",{parentName:"p"},"ta.bestBid"),", ",Object(b.b)("inlineCode",{parentName:"p"},"ta.sumBids"),", ...), щоб працювати зі стаканом.\nІсторичні стакани свічок надходять із ",Object(b.b)("inlineCode",{parentName:"p"},"depths()"),": ",Object(b.b)("inlineCode",{parentName:"p"},"depths()[i].data")," має той самий формат, але там зберігаються лише найбільші лімітні заявки."),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},"const candles = source.ohlcv(); // The exchange, ticker, and timeframe parameters default to the current chart.\nconst closes = candles.map(c => c.close);\n")),Object(b.b)("h3",{id:"levelsexchange-settings"},Object(b.b)("inlineCode",{parentName:"h3"},"levels(exchange, settings?)")),Object(b.b)("p",null,"Рівні ",Object(b.b)("strong",{parentName:"p"},"скринера ліквідності"),": великі лімітні ордери біржі, що стоять у стакані, відфільтровані тими самими налаштуваннями, що й на сторінці скринера. Живі дані, не прив'язані до свічок. Без плану близькість обмежена 1%, час життя 60 хвилинами, а результат 200 рівнями; з планом до 2000 рівнів. Найбільші ордери йдуть першими. Рахується одним запитом джерела даних."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'{\n "BTCUSDT": {\n "asks": {\n "109500": {\n "price": 109500,\n "quantity": 42.5, // size in the base asset\n "quantityUSDT": 4653750, // size in the quote currency\n "distance": 0.62, // from the current price, percent\n "duration": 184, // minutes the order has been standing\n "touches": 2,\n "currentTouches": 1,\n "filledPercent": 12.4,\n "strength": 95.5, // percent, see the screener\n "diversity": 11,\n "isContinuous": true,\n "date": "2026-10-10T06:12:03.000Z"\n },\n ...\n },\n "bids": { ... },\n "volume1hTotal": 183000000\n },\n ...\n}\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Налаштування")," (усі необов'язкові):"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Налаштування"),Object(b.b)("th",{parentName:"tr",align:null},"Типово"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tickers")),Object(b.b)("td",{parentName:"tr",align:null},"усі тікери"),Object(b.b)("td",{parentName:"tr",align:null},"лише ці тікери біржі")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"exclude")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"[]")),Object(b.b)("td",{parentName:"tr",align:null},"тікери, які пропустити")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"type")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"all"')),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"all"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"bids"')," або ",Object(b.b)("inlineCode",{parentName:"td"},'"asks"'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"nearness")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"5")),Object(b.b)("td",{parentName:"tr",align:null},"макс. відстань від поточної ціни у відсотках")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"size")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"100000")),Object(b.b)("td",{parentName:"tr",align:null},"мін. розмір ордера в котирувальній валюті")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"lifespan")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"мін. кількість хвилин, які стоїть ордер")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"touches"),", ",Object(b.b)("inlineCode",{parentName:"td"},"currentTouches")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"мін. дотики рівня / поточного ордера")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"filled")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"мін. виконана частина ордера у відсотках")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"strength"),", ",Object(b.b)("inlineCode",{parentName:"td"},"diversity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"мін. сила (відсотки) і різноманітність, як у скринері")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"continuousOnly")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"пропускати ордери, які зникали й поверталися")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"volume1h")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"мін. обсяг тікера за 1 годину в котирувальній валюті")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"spotAndFutures")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"лише тікери, що є і на споті, і на ф'ючерсах")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"limit")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"500")),Object(b.b)("td",{parentName:"tr",align:null},"макс. кількість рівнів, найбільші першими (макс. 2000)")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// the big orders around the price of the chart market as horizontal lines, labelled with the size and the lifespan\nconst candles = await source.ohlcv();\nconst lastDate = candles.at(-1).startTime;\nconst levels = await source.levels(currentExchange, { tickers: [currentTicker], nearness: 3, size: 300000, lifespan: 30 });\nconst own = levels[currentTicker] || { asks: {}, bids: {} };\nfor (const [type, color] of [["asks", "#ef5350"], ["bids", "#26a69a"]]) {\n for (const [price, level] of Object.entries(own[type])) {\n plot.horizontalLine(`${type} ${price}`, +price, color, 0.8, Math.min(4, 1 + level.quantityUSDT / 1e6));\n plot.text(`${type} ${price} label`, `${(level.quantityUSDT / 1e6).toFixed(2)}M · ${level.duration}m`, lastDate, +price, 10, color);\n }\n}\n')),Object(b.b)("h3",{id:"keylevelsexchange-settings"},Object(b.b)("inlineCode",{parentName:"h3"},"keyLevels(exchange, settings?)")),Object(b.b)("p",null,"Рівні ",Object(b.b)("strong",{parentName:"p"},"скринера Key levels"),": open, high і low поточного та попереднього дня, тижня, місяця й року для кожного тикера біржі, з відстанню кожного рівня від поточної ціни. Живі дані, не прив'язані до свічок. Без тарифу результат містить лише рівні в межах ±1% від ціни (фіксований діапазон сторінки скринера) і не більше 100 тикерів; з тарифом будь-який діапазон відстані та до 1000 тикерів. Першими йдуть тикери з найближчим рівнем. Рахується як один запит джерела даних."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'{\n "BTCUSDT": {\n "price": 79776.57, // поточна ціна\n "updatedAt": 1788707880000,\n "bootstrapped": true, // false, поки історія тикера ще збирається\n "nearest": 0.08, // відстань до найближчого рівня, у відсотках\n "matches": 5, // рівні всередині діапазону відстані\n "daily": { "start": 1788652800000, "open": 79700, "high": 79985, "low": 79710, "openApprox": false,\n "distance": { "open": -0.1, "high": 0.26, "low": -0.08 } }, // відсоток від ціни, зі знаком\n "prevDay": { ... }, "weekly": { ... }, "prevWeek": { ... },\n "monthly": { ... }, "prevMonth": { ... }, "yearly": { ... }, "prevYear": null // null: даних за період ще немає\n },\n ...\n}\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Налаштування")," (усі необов'язкові):"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Налаштування"),Object(b.b)("th",{parentName:"tr",align:null},"Типово"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tickers")),Object(b.b)("td",{parentName:"tr",align:null},"усі тикери"),Object(b.b)("td",{parentName:"tr",align:null},"лише ці тикери біржі")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"exclude")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"[]")),Object(b.b)("td",{parentName:"tr",align:null},"тикери, які слід пропустити")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"periods")),Object(b.b)("td",{parentName:"tr",align:null},"усі"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"daily"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"prevDay"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"weekly"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"prevWeek"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"monthly"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"prevMonth"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"yearly"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"prevYear"'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fields")),Object(b.b)("td",{parentName:"tr",align:null},"усі"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"open"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"high"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"low"'),": які рівні повернути")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"distanceFrom"),", ",Object(b.b)("inlineCode",{parentName:"td"},"distanceTo")),Object(b.b)("td",{parentName:"tr",align:null},"немає"),Object(b.b)("td",{parentName:"tr",align:null},"діапазон відстані від ціни зі знаком, у відсотках (напр. ",Object(b.b)("inlineCode",{parentName:"td"},"-2")," і ",Object(b.b)("inlineCode",{parentName:"td"},"2"),"); повертаються лише тикери з рівнем усередині діапазону. Без тарифу діапазон фіксований: ±1%")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"limit")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"200")),Object(b.b)("td",{parentName:"tr",align:null},"максимум тикерів, найближчий рівень першим (макс. 1000; 100 без тарифу)")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// the key levels of the chart market as horizontal lines\nconst candles = await source.ohlcv();\nconst lastDate = candles.at(-1).startTime;\nconst rows = await source.keyLevels(currentExchange, { tickers: [currentTicker], periods: ["daily", "prevDay", "weekly"] });\nconst own = rows[currentTicker];\nif (own) {\n for (const period of ["daily", "prevDay", "weekly"]) {\n const level = own[period];\n if (!level) continue;\n for (const [field, color] of [["high", "#ef5350"], ["low", "#26a69a"], ["open", "#90a4ae"]]) {\n if (level[field] == null) continue;\n plot.horizontalLine(`${period} ${field}`, level[field], color, 0.8, 1);\n plot.text(`${period} ${field} label`, `${period} ${field.toUpperCase()}`, lastDate, level[field], 10, color);\n }\n }\n}\n')),Object(b.b)("h3",{id:"levelsmetricsexchange-settings"},Object(b.b)("inlineCode",{parentName:"h3"},"levelsMetrics(exchange, settings?)")),Object(b.b)("p",null,"Історія ",Object(b.b)("strong",{parentName:"p"},"сильних рівнів ліквідності"),", яку збирає сторінка ",Object(b.b)("strong",{parentName:"p"},"Метрики"),": кожні 5 хвилин сервер робить знімок рівнів скринера ліквідності кожної біржі з тривалістю від 30 хвилин і силою від 80% та зберігає тиждень таких знімків. Джерело фільтрує знімки за період так само, як сторінка, і повертає по кожному знімку кількість і обсяг ($) відповідних рівнів, зведення за тікерами та історію життя кожного рівня. Це зібрані дані, не прив'язані до свічок: зіставляйте ",Object(b.b)("inlineCode",{parentName:"p"},"series[].at")," з датами свічок. Без підписки період не більше 24 годин і в списку не більше 100 рівнів; з підпискою до 7 днів і 1000 рівнів. Рахується як один запит до джерела даних."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'{\n "exchange": "binanceFutures",\n "hours": 24,\n "snapshotMinutes": 5,\n "latestAt": 1792102098685,\n "summary": { "snapshots": 287, "uniqueLevels": 217, "uniqueTickers": 118, "activeNow": 180, "bidsNow": 102, "asksNow": 78, "usdNow": 119294436 },\n "series": [ // one point per snapshot, oldest first\n { "at": 1792015822555, "bids": 24, "asks": 21, "bidsUsd": 1851345, "asksUsd": 1228883, "tickers": 20 },\n ...\n ],\n "tickers": { // per ticker, over the period\n "BTCUSDT": { "now": 3, "nowUsd": 95710480, "snapshots": 63, "bids": 3, "asks": 0, "levels": 3,\n "maxUsd": 42347880, "maxDuration": 8220, "maxStrength": 100 },\n ...\n },\n "levels": [ // the lifecycle of every level, active ones first\n { "ticker": "BTCUSDT", "side": "bids", "price": 52050, "usd": 42347880, "quantity": 813.6, "distance": 19.8,\n "duration": 8220, "strength": 100, "continuous": 1, "firstSeen": 1792015822555, "lastSeen": 1792102098685,\n "snapshots": 63, "maxDuration": 8220, "maxStrength": 100, "active": true },\n ...\n ],\n "levelsTotal": 217\n}\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Налаштування")," (усі необов'язкові):"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Налаштування"),Object(b.b)("th",{parentName:"tr",align:null},"За замовчуванням"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tickers")),Object(b.b)("td",{parentName:"tr",align:null},"усі тікери"),Object(b.b)("td",{parentName:"tr",align:null},"лише ці тікери біржі")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"exclude")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"[]")),Object(b.b)("td",{parentName:"tr",align:null},"тікери, які треба пропустити")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"hours")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"24")),Object(b.b)("td",{parentName:"tr",align:null},"період у годинах (максимум 168; 24 без підписки)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"minDuration")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"30")),Object(b.b)("td",{parentName:"tr",align:null},"мінімальна тривалість заявки у хвилинах: ",Object(b.b)("inlineCode",{parentName:"td"},"30"),", ",Object(b.b)("inlineCode",{parentName:"td"},"60"),", ",Object(b.b)("inlineCode",{parentName:"td"},"120")," або ",Object(b.b)("inlineCode",{parentName:"td"},"180"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"minStrength")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"80")),Object(b.b)("td",{parentName:"tr",align:null},"мінімальна сила заявки у відсотках: ",Object(b.b)("inlineCode",{parentName:"td"},"80"),", ",Object(b.b)("inlineCode",{parentName:"td"},"90")," або ",Object(b.b)("inlineCode",{parentName:"td"},"100"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"maxDistance")),Object(b.b)("td",{parentName:"tr",align:null},"немає"),Object(b.b)("td",{parentName:"tr",align:null},"максимальна відстань заявки до поточної ціни у відсотках, перевіряється в кожному знімку")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"stableOnly")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true"),": лише заявки, обсяг яких не стрибав («виключити заявки з нестабільним обсягом»)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"limit")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"200")),Object(b.b)("td",{parentName:"tr",align:null},"максимум рівнів у ",Object(b.b)("inlineCode",{parentName:"td"},"levels")," (максимум 1000; 100 без підписки)")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// $ size of the strong levels of the chart market per candle\nconst candles = await source.ohlcv();\nconst data = await source.levelsMetrics(currentExchange, { tickers: [currentTicker], hours: 24, minDuration: 60, minStrength: 90, stableOnly: true });\nconst series = data.series; // oldest first\nlet j = 0;\nconst buy = [], sell = [];\nfor (let i = 0; i < candles.length; i++) {\n const end = candles[i + 1] ? candles[i + 1].startTime : candles[i].startTime + (candles[1].startTime - candles[0].startTime);\n while (j + 1 < series.length && series[j + 1].at < end) j++; // the last snapshot inside the candle\n const point = series[j] && series[j].at < end ? series[j] : null;\n buy.push(point ? point.bidsUsd : null);\n sell.push(point ? point.asksUsd : null);\n}\nplot.areaSeries("Buy levels ($)", buy, "#26a69a", 0.3, "#26a69a", 1, 1, 0);\nplot.areaSeries("Sell levels ($)", sell, "#ef5350", 0.3, "#ef5350", 1, 1, 0);\n')),Object(b.b)("h2",{id:"http-запити"},"HTTP-запити"),Object(b.b)("p",null,"Клас ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"http"))," надсилає запити до зовнішніх HTTP API та повертає відповідь, тому індикатор може використовувати дані, яких немає в ",Object(b.b)("inlineCode",{parentName:"p"},"source"),": ваш власний сервер, публічний REST API, провайдер on-chain метрик, ...\nЯк і ",Object(b.b)("inlineCode",{parentName:"p"},"source.*"),", виклики пишуться як синхронні функції, ",Object(b.b)("inlineCode",{parentName:"p"},"await")," не потрібен."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"get(url, options?)")),Object(b.b)("td",{parentName:"tr",align:null},"GET-запит")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"post(url, body?, options?)")),Object(b.b)("td",{parentName:"tr",align:null},"POST-запит. Об’єкт або масив ",Object(b.b)("inlineCode",{parentName:"td"},"body")," надсилається як JSON (",Object(b.b)("inlineCode",{parentName:"td"},"Content-Type: application/json"),"), рядок — як є")))),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"options")," — це ",Object(b.b)("inlineCode",{parentName:"p"},"{ headers: { name: value } }"),": до ",Object(b.b)("strong",{parentName:"p"},"10")," власних заголовків (наприклад ",Object(b.b)("inlineCode",{parentName:"p"},"Authorization")," або ",Object(b.b)("inlineCode",{parentName:"p"},"x-api-key"),")."),Object(b.b)("p",null,"Обидва методи повертають однаковий об’єкт відповіді та ",Object(b.b)("strong",{parentName:"p"},"ніколи не кидають винятків"),":"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'{\n ok: true, // статус 200–299\n status: 200, // HTTP-статус, 0 якщо запит не було надіслано\n headers: { "content-type": "application/json", ... },\n data: { ... }, // тіло відповіді, розібране як JSON, null якщо тіло не JSON\n text: "...", // сире тіло відповіді\n error: null // причина, якщо запит не вдався: "timeout", "url not allowed", "too many requests", ...\n}\n')),Object(b.b)(i.b,{type:"warning",title:"Обмеження та безпека",mdxType:"Callout"},Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},"До ",Object(b.b)("strong",{parentName:"li"},"3 запитів")," за один запуск скрипту та ",Object(b.b)("strong",{parentName:"li"},"60 запитів на хвилину")," на користувача."),Object(b.b)("li",{parentName:"ul"},"Лише публічні ",Object(b.b)("inlineCode",{parentName:"li"},"http://")," / ",Object(b.b)("inlineCode",{parentName:"li"},"https://")," URL. Запити до ",Object(b.b)("inlineCode",{parentName:"li"},"localhost"),", приватних мереж та адрес метаданих хмар відхиляються, редиректи ",Object(b.b)("strong",{parentName:"li"},"не виконуються")," (відповідь ",Object(b.b)("inlineCode",{parentName:"li"},"3xx")," повертається як є)."),Object(b.b)("li",{parentName:"ul"},"Запити надсилаються з проксі-серверів MobChart: цільовий API бачить адресу проксі й ніколи — ваш IP."),Object(b.b)("li",{parentName:"ul"},"Тайм-аут ",Object(b.b)("strong",{parentName:"li"},"5 секунд"),", тіло запиту до ",Object(b.b)("strong",{parentName:"li"},"64 КБ"),", відповідь до ",Object(b.b)("strong",{parentName:"li"},"512 КБ")," (більші відповіді завершуються помилкою ",Object(b.b)("inlineCode",{parentName:"li"},"response too large"),")."),Object(b.b)("li",{parentName:"ul"},"Заголовки ",Object(b.b)("inlineCode",{parentName:"li"},"Host"),", ",Object(b.b)("inlineCode",{parentName:"li"},"Cookie"),", ",Object(b.b)("inlineCode",{parentName:"li"},"Proxy-*"),", ",Object(b.b)("inlineCode",{parentName:"li"},"X-Forwarded-*")," та інші заголовки з’єднання задати не можна, ",Object(b.b)("inlineCode",{parentName:"li"},"Set-Cookie")," ніколи не повертається."),Object(b.b)("li",{parentName:"ul"},"Перевірка алертів регулярно запускає ваш скрипт на сервері: API викликається під час кожної перевірки, враховуйте ліміти цільового API."),Object(b.b)("li",{parentName:"ul"},"Код публічного індикатора (",Object(b.b)("inlineCode",{parentName:"li"},"isPublicCode = true"),") видно всім — ніколи не розміщуйте API-ключі в публічному коді."))),Object(b.b)("p",null,"Можливі значення ",Object(b.b)("inlineCode",{parentName:"p"},"error"),": ",Object(b.b)("inlineCode",{parentName:"p"},"invalid url"),", ",Object(b.b)("inlineCode",{parentName:"p"},"url not allowed"),", ",Object(b.b)("inlineCode",{parentName:"p"},"invalid headers"),", ",Object(b.b)("inlineCode",{parentName:"p"},"invalid body"),", ",Object(b.b)("inlineCode",{parentName:"p"},"body too large"),", ",Object(b.b)("inlineCode",{parentName:"p"},"response too large"),", ",Object(b.b)("inlineCode",{parentName:"p"},"timeout"),", ",Object(b.b)("inlineCode",{parentName:"p"},"too many requests"),", ",Object(b.b)("inlineCode",{parentName:"p"},"rate limit"),", ",Object(b.b)("inlineCode",{parentName:"p"},"busy"),", ",Object(b.b)("inlineCode",{parentName:"p"},"proxy unavailable"),", ",Object(b.b)("inlineCode",{parentName:"p"},"network error"),"."),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад (GET):")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'define("Fear & Greed", "Crypto Fear & Greed index", "offchart", true, true);\n\nconst res = http.get("https://api.alternative.me/fng/?limit=30");\nif (!res.ok) logger.log("request failed:", res.status, res.error);\n\n// res.data = { data: [{ value: "71", timestamp: "1757635200" }, ...] }\nconst byDay = {};\n(res.data?.data || []).forEach((row) => { byDay[Number(row.timestamp) * 1000] = Number(row.value); });\n\nconst candles = source.ohlcv();\nconst values = candles.map((c) => c ? byDay[c.startTime - (c.startTime % 86400000)] ?? null : null);\nplot.lineSeries("Fear & Greed", values, "#00C8FF");\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад (POST):")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nconst last = candles.at(-1);\n\nconst res = http.post(\n "https://example.com/api/signals",\n { exchange: currentExchange, ticker: currentTicker, close: last.close },\n { headers: { "x-api-key": "YOUR_KEY" } } // private code only\n);\nlogger.log("signal sent:", res.ok, res.status, res.data);\n')),Object(b.b)("h2",{id:"глобальні-змінні"},"Глобальні змінні"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Змінна"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"),Object(b.b)("th",{parentName:"tr",align:null},"Приклад"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"currentExchange")),Object(b.b)("td",{parentName:"tr",align:null},"Поточна біржа на графіку"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"binance"),", ",Object(b.b)("inlineCode",{parentName:"td"},"binanceFutures"),", ",Object(b.b)("inlineCode",{parentName:"td"},"bybit"),", ",Object(b.b)("inlineCode",{parentName:"td"},"bybitFutures"),", ",Object(b.b)("inlineCode",{parentName:"td"},"okx"),", ",Object(b.b)("inlineCode",{parentName:"td"},"okxFutures"),", ",Object(b.b)("inlineCode",{parentName:"td"},"coinbase"),", ",Object(b.b)("inlineCode",{parentName:"td"},"bitfinex"),", ",Object(b.b)("inlineCode",{parentName:"td"},"bitfinexFutures"),", ",Object(b.b)("inlineCode",{parentName:"td"},"hyperliquid"),", ",Object(b.b)("inlineCode",{parentName:"td"},"hyperliquidFutures"),", ",Object(b.b)("inlineCode",{parentName:"td"},"asterFutures"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"currentTicker")),Object(b.b)("td",{parentName:"tr",align:null},"Поточний тикер на графіку (формат залежить від біржі)"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"BTCUSDT"),", ",Object(b.b)("inlineCode",{parentName:"td"},"ADA-USD"),", ",Object(b.b)("inlineCode",{parentName:"td"},"BTC/USDC"),", ...")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"currentTimeframe")),Object(b.b)("td",{parentName:"tr",align:null},"Поточний таймфрейм на графіку"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"1m"),", ",Object(b.b)("inlineCode",{parentName:"td"},"5m"),", ",Object(b.b)("inlineCode",{parentName:"td"},"15m"),", ...")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"exchanges")),Object(b.b)("td",{parentName:"tr",align:null},"Назви всіх бірж (незмінний масив)"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'["binance", "binanceFutures", ...]'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tickers")),Object(b.b)("td",{parentName:"tr",align:null},"Тікери всіх бірж: ",Object(b.b)("inlineCode",{parentName:"td"},"tickers[currentExchange]")," — список біржі графіка (незмінний)"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tickers.binance")," = ",Object(b.b)("inlineCode",{parentName:"td"},'["BTCUSDT", "ETHUSDT", ...]'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"heatmapStep")),Object(b.b)("td",{parentName:"tr",align:null},"Крок ціни теплової карти стакана та кластерів за поточної ціни (точність, до якої сервер округлює ціни: 5 вище 5000, 1 для 1000-5000, 0.1 для 100-1000, ...), береться з останнього закриття графіка; ",Object(b.b)("inlineCode",{parentName:"td"},"null"),", поки ціна невідома (відома після першого ",Object(b.b)("inlineCode",{parentName:"td"},"source.ohlcv()")," ринку графіка)"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"5"),", ",Object(b.b)("inlineCode",{parentName:"td"},"1"),", ",Object(b.b)("inlineCode",{parentName:"td"},"0.1"),", ",Object(b.b)("inlineCode",{parentName:"td"},"0.001"),", ...")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},"const candles = source.ohlcv(currentExchange, currentTicker, currentTimeframe);\nconst closes = candles.map(c => c.close);\n")),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Формати тикерів.")," Кожен метод ",Object(b.b)("inlineCode",{parentName:"p"},"source"),", що приймає біржу й тикер, пропускає тикер через ",Object(b.b)("inlineCode",{parentName:"p"},"resolveTicker"),": з переданого формату (",Object(b.b)("inlineCode",{parentName:"p"},"ETHUSDT"),", ",Object(b.b)("inlineCode",{parentName:"p"},"ETH-USD"),", ",Object(b.b)("inlineCode",{parentName:"p"},"ETH/USDC"),", ",Object(b.b)("inlineCode",{parentName:"p"},"ETH:USD"),", ",Object(b.b)("inlineCode",{parentName:"p"},"ETHF0:USTF0"),", ...) береться базова монета, і тикер збирається заново у форматі запитаної біржі. Тому ",Object(b.b)("inlineCode",{parentName:"p"},"ETH-USD")," працює для Binance, а ",Object(b.b)("inlineCode",{parentName:"p"},"currentTicker")," графіка Binance працює для Coinbase. Зберігається лише монета: використовується стандартна пара біржі (USDT на Binance, USD на Coinbase, USDC на Hyperliquid, ...), а монета, якої немає на біржі, дає порожній результат і рядок у логах."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// тикер у форматі Coinbase на Binance Futures: приводиться до ETHUSDT\nconst depths = source.depths("binanceFutures", "ETH-USD");\n// тикер графіка Binance на Coinbase: ETHUSDT стає ETH-USD\nconst spot = source.ohlcv("coinbase", currentTicker, currentTimeframe);\n')),Object(b.b)("h2",{id:"логування"},"Логування"),Object(b.b)("p",null,"Клас ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"logger"))," використовується для виведення інформації та налагодження."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"log(...args)")),Object(b.b)("td",{parentName:"tr",align:null},"Додає запис до логу (з обмеженням довжини та кількості)")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nlogger.log("First candle:", candles?.[0]);\n')),Object(b.b)(i.f,{src:"../../public/code_editor_log.png",mdxType:"Screenshot"}),Object(b.b)("h2",{id:"візуалізація"},"Візуалізація"),Object(b.b)("p",null,"Клас ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"plot"))," відповідає за відображення графічних елементів і серій даних."),Object(b.b)("h3",{id:"геометричні-фігури"},"Геометричні фігури"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"box(title, date1, price1, date2, price2, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"Прямокутник")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"square(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"Квадрат")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"diamond(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"Ромб")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"triangle(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"Трикутник")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"circle(title, date1, price1, radius = 10, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"Коло")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"text(title, value, date1, price1, fontSize, fill, opacity)")),Object(b.b)("td",{parentName:"tr",align:null},"Текст на графіку")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"table(title, rows, options)")),Object(b.b)("td",{parentName:"tr",align:null},"Таблиця в куті графіка, див. ",Object(b.b)("a",{parentName:"td",href:"#%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%96"},"Таблиці"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"straightLine(title, date1, price1, date2, price2, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(b.b)("td",{parentName:"tr",align:null},"Пряма лінія")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"horizontalLine(title, price1, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(b.b)("td",{parentName:"tr",align:null},"Горизонтальна лінія через весь графік")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"verticalLine(title, date1, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(b.b)("td",{parentName:"tr",align:null},"Вертикальна лінія через весь графік")))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Параметр"),Object(b.b)("th",{parentName:"tr",align:null},"Тип даних"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"title")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")),Object(b.b)("td",{parentName:"tr",align:null},"Назва елемента (унікальний ідентифікатор на графіку)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"date1")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")," (timestamp, ms)"),Object(b.b)("td",{parentName:"tr",align:null},"Початкова часова мітка")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"price1")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"Початкова ціна (координата по осі Y)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"date2")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")," (timestamp, ms)"),Object(b.b)("td",{parentName:"tr",align:null},"Кінцева часова мітка (для ліній і прямокутників)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"price2")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"Кінцева ціна (для ліній і прямокутників)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"size")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"Розмір фігури (у пікселях)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"radius")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"Радіус кола (за замовчуванням 10)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fill")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")," (hex, наприклад ",Object(b.b)("inlineCode",{parentName:"td"},'"#FF0000"'),")"),Object(b.b)("td",{parentName:"tr",align:null},"Колір заливки фігури")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"opacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")," (0–1)"),Object(b.b)("td",{parentName:"tr",align:null},"Прозорість заливки")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"stroke")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")," (hex, наприклад ",Object(b.b)("inlineCode",{parentName:"td"},'"#000000"'),")"),Object(b.b)("td",{parentName:"tr",align:null},"Колір обвідки")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"strokeOpacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")," (0–1)"),Object(b.b)("td",{parentName:"tr",align:null},"Прозорість обвідки")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"strokeWidth")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"Товщина лінії обвідки (у пікселях)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"strokeDasharray")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"array")," (наприклад ",Object(b.b)("inlineCode",{parentName:"td"},"[5,5]"),")"),Object(b.b)("td",{parentName:"tr",align:null},"Стиль пунктирної лінії")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fontSize")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"Розмір тексту (у пікселях)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"value")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")),Object(b.b)("td",{parentName:"tr",align:null},"Текстове значення (для методу ",Object(b.b)("inlineCode",{parentName:"td"},"text"),")")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'plot.text("Text object", "Hello world!", 1757699100000, 115000, 10, "#00C8FF", 0.5);\nplot.straightLine(`${namePrefix} Open`, level.timeStart, level.open, level.timeEnd, level.open, color);\nplot.circle(`${namePrefix} High`, level.timeStart, level.high, 3, color);\n')),Object(b.b)("p",null,"На графіку можна відобразити не більше ніж ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"3000"))," фігур."),Object(b.b)("h3",{id:"серії-даних"},"Серії даних"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"lineSeries(title, values, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(b.b)("td",{parentName:"tr",align:null},"Лінійний графік")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"barSeries(title, values, fill, opacity)")),Object(b.b)("td",{parentName:"tr",align:null},"Гістограма")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"candleSeries(title, openValues, closeValues, highValues, lowValues, fill, opacity)")),Object(b.b)("td",{parentName:"tr",align:null},"Свічки")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"areaSeries(title, values, fill, opacity, stroke, strokeOpacity, strokeWidth, base)")),Object(b.b)("td",{parentName:"tr",align:null},"Область із заливкою між лінією та рівнем ",Object(b.b)("inlineCode",{parentName:"td"},"base")," (за замовчуванням — низ графіка)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bandSeries(title, upperValues, lowerValues, fill, opacity, stroke, strokeOpacity, strokeWidth, step)")),Object(b.b)("td",{parentName:"tr",align:null},"Заливка між двома серіями, у кожної свічки свій колір і прозорість")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"profile(title, values, options)")),Object(b.b)("td",{parentName:"tr",align:null},"Гістограма за ціною для видимих свічок, як профіль обсягу, див. ",Object(b.b)("a",{parentName:"td",href:"#%D0%BF%D1%80%D0%BE%D1%84%D1%96%D0%BB%D1%96"},"Профілі"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"histogram(title, rows, options)")),Object(b.b)("td",{parentName:"tr",align:null},"Готова карта цін, намальована як профіль, див. ",Object(b.b)("a",{parentName:"td",href:"#%D0%B3%D1%96%D1%81%D1%82%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%B8"},"Гістограми"))))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Параметр"),Object(b.b)("th",{parentName:"tr",align:null},"Тип даних"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"values"),", ",Object(b.b)("inlineCode",{parentName:"td"},"upperValues"),", ",Object(b.b)("inlineCode",{parentName:"td"},"lowerValues")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"(number \\| null)[]")),Object(b.b)("td",{parentName:"tr",align:null},"Одне значення на свічку, ",Object(b.b)("inlineCode",{parentName:"td"},"null")," приховує свічку")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fill"),", ",Object(b.b)("inlineCode",{parentName:"td"},"stroke")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")," (hex) або ",Object(b.b)("inlineCode",{parentName:"td"},"function")),Object(b.b)("td",{parentName:"tr",align:null},"Колір або функція, що повертає колір свічки: ",Object(b.b)("inlineCode",{parentName:"td"},"(value, i)")," для ",Object(b.b)("inlineCode",{parentName:"td"},"lineSeries"),", ",Object(b.b)("inlineCode",{parentName:"td"},"barSeries"),", ",Object(b.b)("inlineCode",{parentName:"td"},"candleSeries"),", ",Object(b.b)("inlineCode",{parentName:"td"},"areaSeries"),", ",Object(b.b)("inlineCode",{parentName:"td"},"(upper, lower, i)")," для ",Object(b.b)("inlineCode",{parentName:"td"},"bandSeries"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"opacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")," (0–1) або ",Object(b.b)("inlineCode",{parentName:"td"},"function")),Object(b.b)("td",{parentName:"tr",align:null},"Прозорість заливки, функція ",Object(b.b)("inlineCode",{parentName:"td"},"(value, i)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"(upper, lower, i)")," для ",Object(b.b)("inlineCode",{parentName:"td"},"areaSeries")," / ",Object(b.b)("inlineCode",{parentName:"td"},"bandSeries"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"base")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")," ","|"," ",Object(b.b)("inlineCode",{parentName:"td"},"null")),Object(b.b)("td",{parentName:"tr",align:null},"Базовий рівень ",Object(b.b)("inlineCode",{parentName:"td"},"areaSeries"),", ",Object(b.b)("inlineCode",{parentName:"td"},"null")," = низ графіка")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"step")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"boolean")),Object(b.b)("td",{parentName:"tr",align:null},"Стиль ",Object(b.b)("inlineCode",{parentName:"td"},"bandSeries"),": ",Object(b.b)("inlineCode",{parentName:"td"},"true")," = колонка на свічку (за замовчуванням), ",Object(b.b)("inlineCode",{parentName:"td"},"false")," = неперервний полігон")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'plot.lineSeries("EMA", ta.ema(closes, 20), "#00C8FF");\n// every candle keeps its own color: green where the close is above the EMA, red below it\nplot.lineSeries("Close", closes, (v, i) => v > ema[i] ? colorBuy : colorSell);\nplot.barSeries("Premium %", premiumPercents, ((d) => d > 0 ? color1 : color2), 1);\nplot.candleSeries(\n "Candles",\n opens, closes, highs, lows,\n (v, i) => {\n return opens?.[i] > closes?.[i] ? colorBuy : colorSell\n }\n);\nplot.areaSeries("Volume", volumes, "#00C8FF", 0.3);\n// area colored per candle, more opaque on the bigger candles\nplot.areaSeries("Delta", deltas, (v, i) => v >= 0 ? colorBuy : colorSell, (v, i) => Math.min(1, Math.abs(v) / maxDelta));\n\n// pressure band between the close and 1% below it, colored and shaded by the imbalance ratio of the candle\nplot.bandSeries(\n "Bid pressure",\n closes,\n closes.map(c => c * 0.99),\n (upper, lower, i) => ratios[i] > 0 ? bidColor : askColor,\n (upper, lower, i) => Math.abs(ratios[i]) / 100\n);\n')),Object(b.b)("p",null,"На графіку можна відобразити не більше ніж ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"20"))," серій даних."),Object(b.b)("h3",{id:"профілі"},"Профілі"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"plot.profile(title, values, options?)")," малює гістограму за ціною, як вбудований профіль обсягу. ",Object(b.b)("inlineCode",{parentName:"p"},"values[i]")," — карта цін свічки ",Object(b.b)("inlineCode",{parentName:"p"},"i")," з ",Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()"),": ",Object(b.b)("inlineCode",{parentName:"p"},"{ price: value }")," або ",Object(b.b)("inlineCode",{parentName:"p"},"{ price: { buy, sell } }")," (",Object(b.b)("inlineCode",{parentName:"p"},"data")," запису ",Object(b.b)("inlineCode",{parentName:"p"},"clusters()")," чи ",Object(b.b)("inlineCode",{parentName:"p"},"liquidations()")," можна передати як є), або ",Object(b.b)("inlineCode",{parentName:"p"},"null")," для свічки без рядків. Рядки ",Object(b.b)("strong",{parentName:"p"},"видимих на графіку")," свічок підсумовуються за кроком ціни прямо на графіку, тому профіль слідує за прокруткою, масштабом і підвантаженням історії без нового запуску. Поодинокі значення малюються одним кольором (від'ємне значення йде у ",Object(b.b)("inlineCode",{parentName:"p"},"fill2"),"), пари ділять стовпчик на частини купівель і продажів і дозволяють режим дельти. ",Object(b.b)("inlineCode",{parentName:"p"},"profile()")," не повертає хендл алерту."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Опція"),Object(b.b)("th",{parentName:"tr",align:null},"Типово"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"step")),Object(b.b)("td",{parentName:"tr",align:null},"тік графіка"),Object(b.b)("td",{parentName:"tr",align:null},"висота рядка в одиницях ціни, ціни округлюються вниз до неї")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"orient")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"right"')),Object(b.b)("td",{parentName:"tr",align:null},"край, від якого ростуть стовпчики, ",Object(b.b)("inlineCode",{parentName:"td"},'"right"')," або ",Object(b.b)("inlineCode",{parentName:"td"},'"left"'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"width")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"30")),Object(b.b)("td",{parentName:"tr",align:null},"найширший рядок у відсотках ширини графіка")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fill")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"#26a69a"')),Object(b.b)("td",{parentName:"tr",align:null},"колір значення або частини купівель")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fill2")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"#ef5350"')),Object(b.b)("td",{parentName:"tr",align:null},"колір частини продажів")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"opacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0.6")),Object(b.b)("td",{parentName:"tr",align:null},"прозорість стовпчиків")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"delta")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"малювати ",Object(b.b)("inlineCode",{parentName:"td"},"buy - sell")," замість суми, лише для пар")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"poc")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true")),Object(b.b)("td",{parentName:"tr",align:null},"лінія на рядку з найбільшим значенням")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"valueArea")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"70")),Object(b.b)("td",{parentName:"tr",align:null},"відсоток суми навколо POC з повною непрозорістю, ",Object(b.b)("inlineCode",{parentName:"td"},"false")," — вимкнути")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"valueAreaOpacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0.3")),Object(b.b)("td",{parentName:"tr",align:null},"прозорість рядків поза value area")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"labels")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true")),Object(b.b)("td",{parentName:"tr",align:null},"суми рядків на стовпчиках, коли є місце")))),Object(b.b)("p",null,"Обмеження: ",Object(b.b)("strong",{parentName:"p"},"3")," профілі за запуск, ",Object(b.b)("strong",{parentName:"p"},"300")," рядків на свічку, ",Object(b.b)("strong",{parentName:"p"},"200000")," рядків на профіль. Зайві рядки відкидаються, запуск пише про це в лог."),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// volume profile of the chart, the same picture as the built-in tool\nconst rows = await source.clusters();\nplot.profile("Volume", rows.map((r) => r?.data ?? null), { step: 5 });\n\n// only large trades, delta coloured, on the left edge\nconst minSize = input.number("Min trade size", 50, 0, 100000, 1);\nconst big = rows.map((r) => {\n if (!r?.data) return null;\n const out = {};\n for (const [price, c] of Object.entries(r.data)) {\n if (price === "totalBuy" || price === "totalSell") continue;\n if (c.buy + c.sell >= minSize) out[price] = { buy: c.buy, sell: c.sell };\n }\n return out;\n});\nplot.profile("Large trades", big, { step: 5, delta: true, orient: "left" });\n')),Object(b.b)("h3",{id:"гістограми"},"Гістограми"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"plot.histogram(title, rows, options?)")," малює гістограму, яку ви вже побудували: ",Object(b.b)("strong",{parentName:"p"},"одну карту цін на весь графік"),", по свічках нічого не підсумовується. Використовуйте ",Object(b.b)("inlineCode",{parentName:"p"},"profile()"),", коли рядки належать свічкам і картинка має слідувати за видимим діапазоном, і ",Object(b.b)("inlineCode",{parentName:"p"},"histogram()"),", коли рядки остаточні: знімок стакана, рівні, обчислені скриптом, дані іншого ринку."),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"rows")," має ті самі формати, що й запис свічки в ",Object(b.b)("inlineCode",{parentName:"p"},"profile()"),": ",Object(b.b)("inlineCode",{parentName:"p"},"{ price: value }"),", ",Object(b.b)("inlineCode",{parentName:"p"},"{ price: { buy, sell } }")," або список рядків ",Object(b.b)("inlineCode",{parentName:"p"},"[price, buy, sell]"),". Поодиноке значення малюється одним кольором (від'ємне йде у ",Object(b.b)("inlineCode",{parentName:"p"},"fill2"),"), пари ділять стовпчик на частини купівель і продажів і дозволяють режим дельти. Опції ті самі, що в ",Object(b.b)("inlineCode",{parentName:"p"},"profile()"),", див. таблицю вище."),Object(b.b)("p",null,"Гістограма датується останньою свічкою запуску, і графік зберігає ",Object(b.b)("strong",{parentName:"p"},"найновішу")," гістограму з даним заголовком, тому часткові запуски по старіших свічках (підвантаження історії) ніколи не замінюють поточну. Вона перемальовується з кожним оновленням скрипта, тож гістограма стакана слідує за живим стаканом. ",Object(b.b)("inlineCode",{parentName:"p"},"histogram()")," не повертає хендл алерту."),Object(b.b)("p",null,"Обмеження: ",Object(b.b)("strong",{parentName:"p"},"3")," гістограми за запуск, ",Object(b.b)("strong",{parentName:"p"},"5000")," рядків. Зайві рядки відкидаються, запуск пише про це в лог."),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад, стакан:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// the live order book as a profile on the right edge: bids in the buy colour, asks in the sell colour\nconst book = await source.orderbook();\nconst rows = {};\nfor (const [price, qty] of Object.entries(book.bids)) rows[price] = { buy: qty };\nfor (const [price, qty] of Object.entries(book.asks)) rows[price] = { sell: qty };\nplot.histogram("Order book", rows, { step: 5, width: 25, valueArea: false, poc: false });\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад, власні рівні:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// your own histogram: cluster volume of the last 100 candles, recent candles weigh more\nconst rows = await source.clusters();\nconst weighted = {};\nrows.slice(-100).forEach((r, i, arr) => {\n if (!r?.data) return;\n const weight = (i + 1) / arr.length;\n for (const [price, c] of Object.entries(r.data)) {\n if (price === "totalBuy" || price === "totalSell") continue;\n const cell = weighted[price] || (weighted[price] = { buy: 0, sell: 0 });\n cell.buy += (c.buy || 0) * weight;\n cell.sell += (c.sell || 0) * weight;\n }\n});\nplot.histogram("Weighted volume", weighted, { step: 5, orient: "left", delta: true });\n')),Object(b.b)("h3",{id:"таблиці"},"Таблиці"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"plot.table(title, rows, options?)")," малює невелику сітку в куті панелі графіка: зведення за кількома таймфреймами, статистику завантаженого діапазону, панелі сигналів. ",Object(b.b)("inlineCode",{parentName:"p"},"rows")," — масив рядків, рядок — масив комірок, комірка — рядок, число або ",Object(b.b)("inlineCode",{parentName:"p"},"{ text, color, bg, align, bold }"),". Таблиці одного кута складаються по порядку. Таблиця датується останньою свічкою запуску, і графік зберігає ",Object(b.b)("strong",{parentName:"p"},"найновішу")," таблицю з даним заголовком, тому часткові запуски по старіших свічках (підвантаження історії) ніколи не замінюють поточну. На графіках вужчих за 500 px таблиці не малюються. Таблицю можна перетягнути мишею: позиція зберігається разом із робочим простором і скидається, коли скрипт змінює свою опцію ",Object(b.b)("inlineCode",{parentName:"p"},"position"),". ",Object(b.b)("inlineCode",{parentName:"p"},"table()")," не повертає хендл алерту."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Опція"),Object(b.b)("th",{parentName:"tr",align:null},"Типово"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"position")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"top-right"')),Object(b.b)("td",{parentName:"tr",align:null},"кут панелі: ",Object(b.b)("inlineCode",{parentName:"td"},'"top-right"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"top-left"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"bottom-right"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"bottom-left"'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"header")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"перший рядок жирним на затіненій смузі")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fontSize")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"11")),Object(b.b)("td",{parentName:"tr",align:null},"розмір тексту в px, від 8 до 16")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"color"),", ",Object(b.b)("inlineCode",{parentName:"td"},"bg"),", ",Object(b.b)("inlineCode",{parentName:"td"},"border")),Object(b.b)("td",{parentName:"tr",align:null},"за темою"),Object(b.b)("td",{parentName:"tr",align:null},"кольори тексту, панелі та сітки за замовчуванням; комірка може перевизначити ",Object(b.b)("inlineCode",{parentName:"td"},"color")," і ",Object(b.b)("inlineCode",{parentName:"td"},"bg"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"opacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0.85")),Object(b.b)("td",{parentName:"tr",align:null},"прозорість панелі")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"align")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"left"')),Object(b.b)("td",{parentName:"tr",align:null},"вирівнювання комірок за замовчуванням, ",Object(b.b)("inlineCode",{parentName:"td"},'"left"'),", ",Object(b.b)("inlineCode",{parentName:"td"},'"center"')," або ",Object(b.b)("inlineCode",{parentName:"td"},'"right"'))))),Object(b.b)("p",null,"Обмеження: ",Object(b.b)("strong",{parentName:"p"},"3")," таблиці за запуск, ",Object(b.b)("strong",{parentName:"p"},"50")," рядків, ",Object(b.b)("strong",{parentName:"p"},"10")," стовпців, ",Object(b.b)("strong",{parentName:"p"},"100")," символів у комірці. Довший текст обрізається з трикрапкою, стовпець займає не більше 30% ширини графіка."),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const candles = await source.ohlcv();\nconst closes = candles.map((c) => c.close);\nconst rsi = ta.rsi(closes, 14);\nconst last = rsi.at(-1);\nconst change = (closes.at(-1) / closes.at(-25) - 1) * 100;\n\nplot.table("Stats", [\n ["Metric", "Value"],\n ["RSI 14", { text: last.toFixed(1), color: last > 70 ? "#ef5350" : last < 30 ? "#26a69a" : undefined }],\n ["Change 24 bars", { text: change.toFixed(2) + "%", align: "right" }],\n ["Volume", candles.slice(-24).reduce((s, c) => s + c.volume, 0).toFixed(0)],\n], { position: "top-right", header: true });\n')),Object(b.b)("h2",{id:"технічний-аналіз"},"Технічний аналіз"),Object(b.b)("p",null,"Клас ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"ta"))," реалізує функції ",Object(b.b)("inlineCode",{parentName:"p"},"ta.*")," з PineScript v5. Pine рахує побарово, а тут кожна функція приймає цілі серії (масиви, одне значення на свічку, від старих до нових) і повертає серію тієї ж довжини, яку можна одразу вивести на графік. Поки період не заповнений, значення дорівнюють ",Object(b.b)("inlineCode",{parentName:"p"},"null"),", а ",Object(b.b)("inlineCode",{parentName:"p"},"null")," у вхідних даних поширюється далі, як ",Object(b.b)("inlineCode",{parentName:"p"},"na")," у Pine. Функції Pine, які неявно читають ",Object(b.b)("inlineCode",{parentName:"p"},"high"),", ",Object(b.b)("inlineCode",{parentName:"p"},"low"),", ",Object(b.b)("inlineCode",{parentName:"p"},"close")," або ",Object(b.b)("inlineCode",{parentName:"p"},"volume"),", приймають ці масиви аргументами."),Object(b.b)("p",null,"Функції, що повертають кілька серій (",Object(b.b)("inlineCode",{parentName:"p"},"bb"),", ",Object(b.b)("inlineCode",{parentName:"p"},"kc"),", ",Object(b.b)("inlineCode",{parentName:"p"},"macd"),", ",Object(b.b)("inlineCode",{parentName:"p"},"stoch"),", ",Object(b.b)("inlineCode",{parentName:"p"},"dmi"),", ",Object(b.b)("inlineCode",{parentName:"p"},"supertrend"),"), повертають масив з іменованими властивостями: ",Object(b.b)("inlineCode",{parentName:"p"},"const [middle, upper, lower] = ta.bb(closes, 20, 2)")," або ",Object(b.b)("inlineCode",{parentName:"p"},"ta.bb(closes, 20, 2).upper"),"."),Object(b.b)("h3",{id:"допоміжні-функції"},"Допоміжні функції"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"highest(values, length)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"lowest(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Максимум / мінімум за ",Object(b.b)("inlineCode",{parentName:"td"},"length")," барів")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"highestbars(values, length)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"lowestbars(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Зміщення (0 або від'ємне) до бару з максимумом / мінімумом")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"max(values)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"min(values)")),Object(b.b)("td",{parentName:"tr",align:null},"Історичний максимум / мінімум на кожен бар")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"range(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"highest - lowest"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"change(values, length = 1)")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"values[i] - values[i - length]"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"mom(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Моментум")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"roc(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Швидкість зміни, %")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cum(values)")),Object(b.b)("td",{parentName:"tr",align:null},"Накопичена сума")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"rising(values, length)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"falling(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Значення вище / нижче кожного з попередніх ",Object(b.b)("inlineCode",{parentName:"td"},"length")," значень")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"variance(values, length, biased = true)")),Object(b.b)("td",{parentName:"tr",align:null},"Дисперсія")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"stdev(values, length, biased = true)")),Object(b.b)("td",{parentName:"tr",align:null},"Стандартне відхилення")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"dev(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Середнє абсолютне відхилення")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"median(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Медіана")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"mode(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Найчастіше значення (при рівності — найменше)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"percentile_linear_interpolation(values, length, percentage)")),Object(b.b)("td",{parentName:"tr",align:null},"Перцентиль, лінійна інтерполяція між двома найближчими рангами")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"percentile_nearest_rank(values, length, percentage)")),Object(b.b)("td",{parentName:"tr",align:null},"Перцентиль, метод найближчого рангу")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"percentrank(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"% попередніх ",Object(b.b)("inlineCode",{parentName:"td"},"length")," значень, менших або рівних поточному")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"correlation(series1, series2, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Коефіцієнт кореляції")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"crossover(series1, series2)")),Object(b.b)("td",{parentName:"tr",align:null},"Перетин угору (будь-який аргумент може бути числом: ",Object(b.b)("inlineCode",{parentName:"td"},"ta.crossover(rsi, 70)"),")")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"crossunder(series1, series2)")),Object(b.b)("td",{parentName:"tr",align:null},"Перетин униз")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cross(series1, series2)")),Object(b.b)("td",{parentName:"tr",align:null},"Будь-який перетин")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"barssince(condition)")),Object(b.b)("td",{parentName:"tr",align:null},"Барів з моменту, коли ",Object(b.b)("inlineCode",{parentName:"td"},"condition")," (масив boolean) востаннє був true")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"valuewhen(condition, values, occurrence = 0)")),Object(b.b)("td",{parentName:"tr",align:null},"Значення ",Object(b.b)("inlineCode",{parentName:"td"},"values")," у барі, де ",Object(b.b)("inlineCode",{parentName:"td"},"condition")," був true ",Object(b.b)("inlineCode",{parentName:"td"},"occurrence")," разів тому")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"pivothigh(values, leftbars, rightbars)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"pivotlow(...)")),Object(b.b)("td",{parentName:"tr",align:null},"Значення півота на підтверджуючому барі, сам півот на ",Object(b.b)("inlineCode",{parentName:"td"},"rightbars")," барів раніше")))),Object(b.b)("h3",{id:"ковзні-середні"},"Ковзні середні"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"sma(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Проста ковзна середня")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"ema(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Експоненціальна ковзна середня")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"rma(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Ковзна середня Уайлдера (використовується в RSI / ATR)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"wma(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Зважена ковзна середня")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"hma(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Ковзна середня Галла")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"alma(values, length, offset = 0.85, sigma = 6, floor = false)")),Object(b.b)("td",{parentName:"tr",align:null},"Ковзна середня Арно Легу")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"swma(values)")),Object(b.b)("td",{parentName:"tr",align:null},"Симетрично зважена ковзна середня по 4 барах")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"vwma(values, volumes, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Середня, зважена за обсягом")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"linreg(values, length, offset = 0)")),Object(b.b)("td",{parentName:"tr",align:null},"Крива лінійної регресії")))),Object(b.b)("h3",{id:"осцилятори"},"Осцилятори"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"rsi(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Індекс відносної сили")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cmo(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Осцилятор моментуму Чанде")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cog(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Центр ваги")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"mfi(values, volumes, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Індекс грошового потоку (",Object(b.b)("inlineCode",{parentName:"td"},"values")," зазвичай hlc3)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tsi(values, shortLength, longLength)")),Object(b.b)("td",{parentName:"tr",align:null},"Індекс істинної сили, -1..1")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"wpr(highs, lows, closes, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Williams %R")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"stoch(highs, lows, closes, period = 14, smoothK = 3, smoothD = 3)")),Object(b.b)("td",{parentName:"tr",align:null},"Стохастик ",Object(b.b)("inlineCode",{parentName:"td"},"[k, d]"),", ",Object(b.b)("inlineCode",{parentName:"td"},"smoothK = 1")," дає незгладжене значення")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cci(values, length)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"cci(highs, lows, closes, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Індекс товарного каналу (у другій формі — за типовою ціною)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"macd(values, fast = 12, slow = 26, signalPeriod = 9)")),Object(b.b)("td",{parentName:"tr",align:null},"MACD ",Object(b.b)("inlineCode",{parentName:"td"},"[macd, signal, histogram]"))))),Object(b.b)("h3",{id:"смуги-та-канали"},"Смуги та канали"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bb(values, length = 20, mult = 2)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"bollinger(...)")),Object(b.b)("td",{parentName:"tr",align:null},"Смуги Боллінджера ",Object(b.b)("inlineCode",{parentName:"td"},"[middle, upper, lower]"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bbw(values, length, mult)")),Object(b.b)("td",{parentName:"tr",align:null},"Ширина смуг Боллінджера ",Object(b.b)("inlineCode",{parentName:"td"},"(upper - lower) / middle"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"kc(values, highs, lows, closes, length = 20, mult = 2, useTrueRange = true)")),Object(b.b)("td",{parentName:"tr",align:null},"Канали Кельтнера ",Object(b.b)("inlineCode",{parentName:"td"},"[middle, upper, lower]"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"kcw(values, highs, lows, closes, length, mult, useTrueRange)")),Object(b.b)("td",{parentName:"tr",align:null},"Ширина каналів Кельтнера ",Object(b.b)("inlineCode",{parentName:"td"},"(upper - lower) / middle"))))),Object(b.b)("h3",{id:"тренд-і-волатильність"},"Тренд і волатильність"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tr(highs, lows, closes, handleNa = false)")),Object(b.b)("td",{parentName:"tr",align:null},"Істинний діапазон (",Object(b.b)("inlineCode",{parentName:"td"},"handleNa = true")," дає ",Object(b.b)("inlineCode",{parentName:"td"},"high - low")," на першому барі)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"atr(highs, lows, closes, period = 14)")),Object(b.b)("td",{parentName:"tr",align:null},"Середній істинний діапазон")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"dmi(highs, lows, closes, diLength = 14, adxSmoothing = 14)")),Object(b.b)("td",{parentName:"tr",align:null},"Індекс спрямованого руху ",Object(b.b)("inlineCode",{parentName:"td"},"[plus, minus, adx]"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"adx(highs, lows, closes, period = 14)")),Object(b.b)("td",{parentName:"tr",align:null},"Середній індекс спрямованого руху")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"sar(highs, lows, closes, start = 0.02, inc = 0.02, max = 0.2)")),Object(b.b)("td",{parentName:"tr",align:null},"Параболік SAR")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"supertrend(highs, lows, closes, factor = 3, atrPeriod = 10)")),Object(b.b)("td",{parentName:"tr",align:null},"Supertrend ",Object(b.b)("inlineCode",{parentName:"td"},"[supertrend, direction]"),", direction ",Object(b.b)("inlineCode",{parentName:"td"},"-1")," — висхідний тренд, ",Object(b.b)("inlineCode",{parentName:"td"},"1")," — низхідний")))),Object(b.b)("h3",{id:"обсяг"},"Обсяг"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"vwap(values, volumes, anchor?)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"vwap(highs, lows, closes, volumes, anchor?)")),Object(b.b)("td",{parentName:"tr",align:null},"Накопичувальний VWAP (у другій формі — за типовою ціною), скидається на барах, де ",Object(b.b)("inlineCode",{parentName:"td"},"anchor")," (масив boolean) дорівнює true")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"obv(closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"Балансовий обсяг (OBV)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"accdist(highs, lows, closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"Накопичення / розподіл")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"iii(highs, lows, closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"Індекс внутрішньоденної інтенсивності")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"pvt(closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"Тренд ціни та обсягу")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"nvi(closes, volumes)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"pvi(closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"Індекс негативного / позитивного обсягу")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"wad(highs, lows, closes)")),Object(b.b)("td",{parentName:"tr",align:null},"Накопичення / розподіл Вільямса")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"wvad(opens, highs, lows, closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"Змінне накопичення / розподіл Вільямса")))),Object(b.b)("h3",{id:"помічники-для-стакана"},"Помічники для стакана"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"orderbook")," — це ",Object(b.b)("inlineCode",{parentName:"p"},"source.orderbook()")," або ",Object(b.b)("inlineCode",{parentName:"p"},"source.depths()[i].data"),": ",Object(b.b)("inlineCode",{parentName:"p"},"{asks: {price: quantity}, bids: {price: quantity}}"),"."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"orderbookSide(orderbook, side)")),Object(b.b)("td",{parentName:"tr",align:null},"Одна сторона (",Object(b.b)("inlineCode",{parentName:"td"},"'bids'")," / ",Object(b.b)("inlineCode",{parentName:"td"},"'asks'"),") у вигляді ",Object(b.b)("inlineCode",{parentName:"td"},"[[price, quantity], ...]"),", найкраща ціна першою")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bestBid(orderbook)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"bestAsk(orderbook)")),Object(b.b)("td",{parentName:"tr",align:null},"Найкраща ціна біда / аска (",Object(b.b)("inlineCode",{parentName:"td"},"null")," для порожнього стакана)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"sumBids(orderbook, percent, price, inQuote)")),Object(b.b)("td",{parentName:"tr",align:null},"Сумарний обсяг бідів між ",Object(b.b)("inlineCode",{parentName:"td"},"price")," (за замовчуванням найкращий бід) і ",Object(b.b)("inlineCode",{parentName:"td"},"price * (1 - percent / 100)"),", ",Object(b.b)("inlineCode",{parentName:"td"},"inQuote = true")," підсумовує ",Object(b.b)("inlineCode",{parentName:"td"},"price * quantity"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"sumAsks(orderbook, percent, price, inQuote)")),Object(b.b)("td",{parentName:"tr",align:null},"Сумарний обсяг асків між ",Object(b.b)("inlineCode",{parentName:"td"},"price")," (за замовчуванням найкращий аск) і ",Object(b.b)("inlineCode",{parentName:"td"},"price * (1 + percent / 100)"))))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nconst rsiValues = ta.rsi(closes, 14);\nplot.lineSeries("RSI", rsiValues, "#00C8FF");\n')),Object(b.b)("h2",{id:"алерти"},"Алерти"),Object(b.b)("p",null,"Користувачі можуть створювати алерти для вашого індикатора у вкладці ",Object(b.b)("strong",{parentName:"p"},"Алерти")," в налаштуваннях індикатора на графіку.\nАлерти регулярно перевіряються на боці сервера, сповіщення надсилаються в ",Object(b.b)("strong",{parentName:"p"},"Telegram")," та/або на вказаний користувачем ",Object(b.b)("strong",{parentName:"p"},"Webhook URL"),"."),Object(b.b)("h3",{id:"налаштування-алерту--alertinput"},"Налаштування алерту — ",Object(b.b)("inlineCode",{parentName:"h3"},"alertInput")),Object(b.b)("p",null,"Клас ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"alertInput"))," оголошує налаштування алертів. Він працює так само, як ",Object(b.b)("inlineCode",{parentName:"p"},"input"),", але поля відображаються у вкладці ",Object(b.b)("strong",{parentName:"p"},"Алерти"),", і кожен користувач задає власні значення для свого алерту."),Object(b.b)("p",null,"Скрипти без оголошень ",Object(b.b)("inlineCode",{parentName:"p"},"alertInput")," не можна використовувати для алертів."),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number(title, defaultValue, min, max, step)")),Object(b.b)("td",{parentName:"tr",align:null},"Числове введення")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"range(title, defaultValue, min, max, step)")),Object(b.b)("td",{parentName:"tr",align:null},"Введення з діапазону")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"select(title, defaultValue, values)")),Object(b.b)("td",{parentName:"tr",align:null},"Випадний список")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"color(title, defaultValue)")),Object(b.b)("td",{parentName:"tr",align:null},"Вибір кольору")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"boolean(title, defaultValue)")),Object(b.b)("td",{parentName:"tr",align:null},"Двійкова змінна")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const alertVolumeThreshold = alertInput.number("Volume threshold", 1000, 0, 10000000, 1);\n')),Object(b.b)("h3",{id:"спрацьовування-алертів--alertfire"},"Спрацьовування алертів — ",Object(b.b)("inlineCode",{parentName:"h3"},"alert.fire")),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"Метод"),Object(b.b)("th",{parentName:"tr",align:null},"Опис"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fire(title, message, date)")),Object(b.b)("td",{parentName:"tr",align:null},"Надсилає сповіщення алерту")))),Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},"Усі три параметри ",Object(b.b)("strong",{parentName:"li"},"обов’язкові")," — виклик без ",Object(b.b)("inlineCode",{parentName:"li"},"title"),", ",Object(b.b)("inlineCode",{parentName:"li"},"message")," або ",Object(b.b)("inlineCode",{parentName:"li"},"date")," пропускається (у лог записується попередження)."),Object(b.b)("li",{parentName:"ul"},"Використовуйте ",Object(b.b)("strong",{parentName:"li"},"сталий title"),", не генеруйте унікальні назви. Кожен title спрацьовує лише один раз за запуск (максимум ",Object(b.b)("strong",{parentName:"li"},"20")," назв за запуск)."),Object(b.b)("li",{parentName:"ul"},Object(b.b)("inlineCode",{parentName:"li"},"date")," — це ",Object(b.b)("inlineCode",{parentName:"li"},"startTime")," свічки, до якої належить сигнал: той самий title сповістить знову лише тоді, коли спрацює для ",Object(b.b)("strong",{parentName:"li"},"новішої")," свічки. Сигнали зі свічок, старших за момент створення алерту користувачем, ігноруються (захист від спаму).")),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"Приклад:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'if (candle.volume > alertVolumeThreshold) {\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n}\n')),Object(b.b)("h3",{id:"алерти-фігур--plotфігураalert"},"Алерти фігур — ",Object(b.b)("inlineCode",{parentName:"h3"},"plot.<фігура>(...).alert(...)")),Object(b.b)("p",null,"Усі геометричні фігури (",Object(b.b)("inlineCode",{parentName:"p"},"box"),", ",Object(b.b)("inlineCode",{parentName:"p"},"square"),", ",Object(b.b)("inlineCode",{parentName:"p"},"diamond"),", ",Object(b.b)("inlineCode",{parentName:"p"},"triangle"),", ",Object(b.b)("inlineCode",{parentName:"p"},"circle"),", ",Object(b.b)("inlineCode",{parentName:"p"},"straightLine"),", ",Object(b.b)("inlineCode",{parentName:"p"},"horizontalLine"),", ",Object(b.b)("inlineCode",{parentName:"p"},"verticalLine"),", ",Object(b.b)("inlineCode",{parentName:"p"},"text"),") повертають об’єкт із методом ",Object(b.b)("inlineCode",{parentName:"p"},".alert()"),".\nАлерт спрацьовує з ",Object(b.b)("inlineCode",{parentName:"p"},"date1")," фігури автоматично, тому захист від спаму працює без додаткового коду — це рекомендований спосіб для сигналів на окремих свічках."),Object(b.b)("p",null,"Дві форми:"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// simple: fires every time the shape is plotted for a new date\nplot.box(...).alert("High volume", `vol ${candle.volume}`);\n\n// callback: return nothing to skip, [title, message] to fire\nplot.box(...).alert((shape) => {\n if (candle.volume > alertVolumeThreshold)\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n});\n')),Object(b.b)("p",null,"Колбек отримує дані фігури (",Object(b.b)("inlineCode",{parentName:"p"},"date1"),", ",Object(b.b)("inlineCode",{parentName:"p"},"price1"),", ",Object(b.b)("inlineCode",{parentName:"p"},"date2"),", ",Object(b.b)("inlineCode",{parentName:"p"},"price2"),", ...)."),Object(b.b)("h3",{id:"алерти-серій--plotсеріяalert"},"Алерти серій — ",Object(b.b)("inlineCode",{parentName:"h3"},"plot.<серія>(...).alert(...)")),Object(b.b)("p",null,"Серії даних (",Object(b.b)("inlineCode",{parentName:"p"},"lineSeries"),", ",Object(b.b)("inlineCode",{parentName:"p"},"barSeries"),", ",Object(b.b)("inlineCode",{parentName:"p"},"candleSeries"),", ",Object(b.b)("inlineCode",{parentName:"p"},"areaSeries"),", ",Object(b.b)("inlineCode",{parentName:"p"},"bandSeries"),") також повертають об’єкт із методом ",Object(b.b)("inlineCode",{parentName:"p"},".alert()"),".\nКолбек отримує ",Object(b.b)("strong",{parentName:"p"},"останню точку даних")," і дату останньої свічки, алерт спрацьовує з цією датою."),Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},Object(b.b)("inlineCode",{parentName:"li"},"lineSeries")," / ",Object(b.b)("inlineCode",{parentName:"li"},"barSeries")," / ",Object(b.b)("inlineCode",{parentName:"li"},"areaSeries")," — колбек отримує останнє ",Object(b.b)("strong",{parentName:"li"},"значення")," (число)"),Object(b.b)("li",{parentName:"ul"},Object(b.b)("inlineCode",{parentName:"li"},"candleSeries")," — колбек отримує останню свічку ",Object(b.b)("inlineCode",{parentName:"li"},"{open, close, high, low}")),Object(b.b)("li",{parentName:"ul"},Object(b.b)("inlineCode",{parentName:"li"},"bandSeries")," — колбек отримує останні ",Object(b.b)("inlineCode",{parentName:"li"},"{upper, lower}"))),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'plot.lineSeries("RSI", rsiValues, color).alert((rsi, date) => {\n if (rsi > alertRsiThreshold) alert.fire("RSI high", `RSI ${rsi.toFixed(1)}`, latestCandle.startTime);\n});\n')),Object(b.b)("p",null,"Умова, що залишається істинною, сповіщає один раз на кожну ",Object(b.b)("strong",{parentName:"p"},"нову свічку"),". Для одноразових сигналів використовуйте умови перетину (",Object(b.b)("inlineCode",{parentName:"p"},"ta.crossover"),")."),Object(b.b)("h3",{id:"повний-приклад"},"Повний приклад"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Volume alerts";\nconst description = "Shows boxes on high-volume candles";\ndefine(title, description, "onchart", true, true);\n\nconst color = style.color("Color", "#00C8FF");\nconst volumeThreshold = input.number("Volume threshold", 1000, 0, 10000000, 1);\nconst alertVolumeThreshold = alertInput.number("Alert volume threshold", 5000, 0, 10000000, 1);\nconst alertCloseThreshold = alertInput.number("Alert close threshold", 100000, 0, 10000000, 1);\n\nconst candles = source.ohlcv();\nconst latestCandle = candles.at(-1);\nconst closes = candles.map(c => c.close);\n\n// series alert: checks the latest close\nplot.lineSeries("Closes", closes, color).alert((close, date) => {\n if (close > alertCloseThreshold) alert.fire("Close above threshold", `close ${close}`, latestCandle.startTime);\n});\n\nfor (let i = 0; i < candles.length; i++) {\n const candle = candles[i];\n\n if (candle.volume > volumeThreshold) {\n const right = i < candles.length - 1 ? candles[i + 1].startTime : candle.startTime + 60000;\n\n // shape alert: checked against the user\'s alert threshold\n plot.box(`Volume ${i}`, candle.startTime, candle.high, right, candle.low, "#00C8FF", 0.3)\n .alert(() => {\n if (candle.volume > alertVolumeThreshold)\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n });\n }\n}\n')),Object(b.b)("h2",{id:"приклади-індикаторів"},"Приклади індикаторів"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Your first indicator";\nconst description = "Shows closes lines on the chart";\nconst indicatorType = "onchart";\n\ndefine(title, description, indicatorType, true, true);\n\nconst color = input.color("Line Color", "#00C8FF");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nplot.lineSeries("Closes", closes, color);\n\n')),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'define("Example Indicator", "Demonstrates basic plotting", "onchart", true, true);\n\nconst color = input.color("Line Color", "#00FF99");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\n\nconst ema20 = ta.ema(closes, 20);\nplot.lineSeries("EMA 20", ema20, color);\n\n')),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Colored Volume Bars"; \nconst description = "Volumes colored based on candle direction."; \nconst indicatorType = "onchart"; \nconst isPublic = true; \nconst isPublicCode = true; \n\ndefine(title, description, indicatorType, isPublic, isPublicCode); \n\n// Get OHLC candles\nconst candles = source.ohlcv(); \n\nconst colorUp = style.color("Color 1", "#2BB462"); // Greenish color for rising prices\nconst colorDown = style.color("Color 2", "#FB4C51"); // Reddish color for falling prices\nconst volumes = candles.map(candle => candle.volume); \n\nplot.barSeries("Volume", volumes, (value, index) => {\n const currentCandle = candles[index]; \n return currentCandle.close >= currentCandle.open ? colorUp : colorDown; \n});\n\n')),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},"define('Coinbase Premium Index', 'Coinbase Premium Index', 'offchart', true, false);\n\nconst color1 = style.color(\"Color 1\", \"#2BB462\");\nconst color2 = style.color(\"Color 2\", \"#FB4C51\");\n\n// Get OHLC candles\nconst cbCandles = source.ohlcv('coinbase', 'BTC-USD');\nconst binanceCandles = source.ohlcv('binance', 'BTCUSDT');\n\n// Extract closes\nconst cbCloses = cbCandles.map(c => c.close);\nconst binanceCloses = binanceCandles.map(c => c.close);\n\n// --- Coinbase Premium Index calculation ---\nconst premiumPercent = cbCloses.map((cb, i) => {\n const b = binanceCloses[i];\n return ((cb - b) / b) * 100;\n});\n\n// Plot premium index\nplot.barSeries(\"Premium %\", premiumPercent, ((d) => d > 0 ? color1 : color2)) // Percentage difference\n\n")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Candles";\nconst description = "Simple candles draw";\nconst indicatorType = "offchart";\nconst isPublic = true;\nconst isPublicCode = true;\ndefine(title, description, indicatorType, isPublic, isPublicCode);\n\nconst colorBuy = style.color("Buy Color", "#2BB462");\nconst colorSell = style.color("Sell Color", "#7a3d3f");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nconst opens = candles.map(c => c.open);\nconst highs = candles.map(c => c.high);\nconst lows = candles.map(c => c.low);\nplot.candleSeries(\n "Candles",\n opens, closes, highs, lows,\n (v, i) => {\n return opens?.[i] > closes?.[i] ? colorBuy : colorSell\n }\n);\n\n')),Object(b.b)("p",null,"Order Book Pressure (смуги дисбалансу глибини бідів / асків навколо ціни, як оверлеї «Order Book Pressure» у торгових терміналах):"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Order Book Pressure";\nconst description = "Bid / ask depth imbalance bands around the price";\ndefine(title, description, "onchart", true, true);\n\nconst minBidRatio = input.number("Min bid ratio %", 20, 0, 100, 1);\nconst minAskRatio = input.number("Min ask ratio %", 20, 0, 100, 1);\nconst depthFrom = input.select("Depth from", "0%", ["0%", "1%", "2.5%", "5%"]);\nconst depthTo = input.select("Depth to", "5%", ["1%", "2.5%", "5%", "10%"]);\n\nconst bidColor = style.color("Bid fill color", "#a5d6a7");\nconst askColor = style.color("Ask fill color", "#f1627e");\nconst extremeColor = style.color("Extreme color", "#ffff00");\nconst highlight = style.boolean("Highlight extremes", true);\nconst showRef = style.boolean("Show reference lines", true);\n\nconst alertMinRatio = alertInput.number("Alert min |ratio| %", 40, 0, 100, 1);\n\nconst bounds = [1, 2.5, 5, 10]; // depth bands in % from the close\nconst from = parseFloat(depthFrom);\nconst to = parseFloat(depthTo);\n\nconst candles = source.ohlcv();\nconst depths = source.depths();\nconst liveBook = source.orderbook();\n\n// orderbook of every candle: depths()[i] is the snapshot of candles[i] (the biggest limit orders), the latest candle uses the live book\nconst lastIndex = candles.length - 1;\nconst books = candles.map((c, i) => {\n if (!c) return null;\n if (i === lastIndex && ta.bestBid(liveBook)) return liveBook;\n return depths[i]?.data || null;\n});\nconst closes = candles.map(c => c ? c.close : null);\n\n// imbalance ratio of every band in % (positive = bids dominate, negative = asks dominate)\nconst ratios = bounds.map((upper, b) => {\n const lower = b === 0 ? 0 : bounds[b - 1];\n return candles.map((c, i) => {\n const book = books[i];\n if (!c || !book) return null;\n const bid = ta.sumBids(book, upper, c.close) - ta.sumBids(book, lower, c.close);\n const ask = ta.sumAsks(book, upper, c.close) - ta.sumAsks(book, lower, c.close);\n const total = bid + ask;\n return total > 0 ? ((bid - ask) / total) * 100 : 0;\n });\n});\n\n// a stronger ratio -> a more opaque band, extreme ratios get the extreme color\nconst bandOpacity = (ratio) => Math.min(0.95, Math.abs(ratio || 0) / 70 * 0.95);\nconst bandColor = (ratio) => highlight && Math.abs(ratio || 0) >= 63 ? extremeColor : (ratio >= 0 ? bidColor : askColor);\n\nbounds.forEach((upper, b) => {\n const lower = b === 0 ? 0 : bounds[b - 1];\n if (from > lower || upper > to) return; // the band is outside of the selected depth range\n\n const bidUpper = closes.map(c => c != null ? c * (1 - lower / 100) : null);\n const bidLower = closes.map(c => c != null ? c * (1 - upper / 100) : null);\n const askLower = closes.map(c => c != null ? c * (1 + lower / 100) : null);\n const askUpper = closes.map(c => c != null ? c * (1 + upper / 100) : null);\n\n if (showRef) {\n plot.lineSeries(`Bid ${upper}%`, bidLower, bidColor, 0.4);\n plot.lineSeries(`Ask ${upper}%`, askUpper, askColor, 0.4);\n }\n\n // bid pressure: the band is filled only on the candles where bids dominate by more than the min ratio\n plot.bandSeries(\n `Bid pressure ${lower}-${upper}%`,\n bidUpper.map((v, i) => ratios[b][i] >= minBidRatio ? v : null),\n bidLower,\n (upper, lower, i) => bandColor(ratios[b][i]),\n (upper, lower, i) => bandOpacity(ratios[b][i])\n );\n\n // ask pressure\n plot.bandSeries(\n `Ask pressure ${lower}-${upper}%`,\n askUpper.map((v, i) => ratios[b][i] <= -minAskRatio ? v : null),\n askLower,\n (upper, lower, i) => bandColor(ratios[b][i]),\n (upper, lower, i) => bandOpacity(ratios[b][i])\n );\n\n // alert on the latest candle\n const latestRatio = ratios[b][lastIndex];\n if (latestRatio != null && Math.abs(latestRatio) >= alertMinRatio) {\n alert.fire(`Pressure ${lower}-${upper}%`, `ratio ${latestRatio.toFixed(1)}%`, candles[lastIndex].startTime);\n }\n});\n\n')))}void 0!==m&&m&&m===Object(m)&&Object.isExtensible(m)&&!Object.prototype.hasOwnProperty.call(m,"__filemeta")&&Object.defineProperty(m,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/components/uk/Scripting.mdx"}}),m.isMDXComponent=!0}}]); //# sourceMappingURL=26d873e3-96a9ec9f6861a6fe52a1.js.map