(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{Awda: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/ru/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 обращений")," к источникам данных."),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"),", рассчитывается частично, поэтому добавьте флаг в существующие накопительные скрипты при их редактировании."),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)("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')),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)("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)("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"},"coinbase"),", ...")),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)("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)("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"},"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)("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)("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/ru/Scripting.mdx"}}),m.isMDXComponent=!0}}]); //# sourceMappingURL=component---src-components-ru-scripting-mdx-9cd4856138074f28a2cf.js.map