(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{buIY:function(e,t,a){"use strict";a.r(t),a.d(t,"_frontmatter",(function(){return c})),a.d(t,"default",(function(){return p}));var n=a("Fcif"),l=a("dV/x"),r=(a("mXGw"),a("/FXl")),b=a("TjRS"),i=a("wCAC");a("l1C2");const o=["components"],c={};void 0!==c&&c&&c===Object(c)&&Object.isExtensible(c)&&!Object.prototype.hasOwnProperty.call(c,"__filemeta")&&Object.defineProperty(c,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/components/es/Scripting.mdx"}});const d={_frontmatter:c},s=b.a;function p(e){let{components:t}=e,a=Object(l.a)(e,o);return Object(r.b)(s,Object(n.a)({},d,a,{components:t,mdxType:"MDXLayout"}),Object(r.b)("h1",{id:"api-de-indicadores-personalizados"},"API de indicadores personalizados"),Object(r.b)(i.e,{mdxType:"Lead"},"Escribe tus propios indicadores en JavaScript, ejecútalos en un sandbox seguro junto al gráfico y compártelos con otros usuarios. La API te da datos de mercado (velas, libros de órdenes, clústeres, liquidaciones, datos de derivados), primitivas de dibujo, funciones de análisis técnico y alertas."),Object(r.b)("h2",{id:"genera-indicadores-con-ia"},"Genera indicadores con IA"),Object(r.b)("p",null,"Toda la API también está disponible como un único archivo de texto para modelos de lenguaje: ",Object(r.b)("a",{parentName:"p",href:"../../public/AI-scripting.txt"},"AI-scripting.txt"),". Adjúntalo a ChatGPT, Claude, Gemini o cualquier otro LLM y describe el indicador que quieres."),Object(r.b)("p",null,"Ejemplo de prompt:"),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"sandbox-y-límites"},"Sandbox y límites"),Object(r.b)(i.b,{type:"warning",title:"Límites actuales",mdxType:"Callout"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Los scripts se ejecutan en un sandbox de JavaScript seguro."),Object(r.b)("li",{parentName:"ul"},"Un script tiene un límite de tiempo de ejecución de ",Object(r.b)("inlineCode",{parentName:"li"},"1500ms"),"."),Object(r.b)("li",{parentName:"ul"},"Los arrays de datos devueltos están limitados a ",Object(r.b)("strong",{parentName:"li"},"5000")," elementos, por lo que un indicador no puede mirar más allá de ",Object(r.b)("strong",{parentName:"li"},"5000 velas"),"."),Object(r.b)("li",{parentName:"ul"},"Se permiten hasta ",Object(r.b)("strong",{parentName:"li"},"8 solicitudes de fuentes de datos")," dentro de un mismo indicador."),Object(r.b)("li",{parentName:"ul"},"Se permiten hasta ",Object(r.b)("strong",{parentName:"li"},"3 solicitudes HTTP")," (",Object(r.b)("inlineCode",{parentName:"li"},"http.get")," / ",Object(r.b)("inlineCode",{parentName:"li"},"http.post"),") en una sola ejecución, consulta ",Object(r.b)("strong",{parentName:"li"},"Solicitudes HTTP"),"."))),Object(r.b)("h2",{id:"desarrollo-de-indicadores"},"Desarrollo de indicadores"),Object(r.b)("p",null,"El desarrollo de indicadores se realiza en un widget aparte, que puedes colocar junto al gráfico en el que se activará el indicador."),Object(r.b)(i.f,{src:"../../public/chart_code.png",mdxType:"Screenshot"}),Object(r.b)("h2",{id:"crear-un-indicador"},"Crear un indicador"),Object(r.b)("h3",{id:"definetitle-description-type-ispublic-ispubliccode-options"},Object(r.b)("inlineCode",{parentName:"h3"},"define(title, description, type, isPublic, isPublicCode, options)")),Object(r.b)("p",null,"Registra el indicador en el sistema."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Parámetro"),Object(r.b)("th",{parentName:"tr",align:null},"Tipo"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"title")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"string")),Object(r.b)("td",{parentName:"tr",align:null},"Nombre del indicador")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"description")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"string")),Object(r.b)("td",{parentName:"tr",align:null},"Descripción breve")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"type")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"'onchart'")," ","|"," ",Object(r.b)("inlineCode",{parentName:"td"},"'offchart'")),Object(r.b)("td",{parentName:"tr",align:null},"Ubicación del indicador (en el gráfico o en un panel aparte)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"isPublic")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"true")," ","|"," ",Object(r.b)("inlineCode",{parentName:"td"},"false")),Object(r.b)("td",{parentName:"tr",align:null},"Si el indicador es público")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"isPublicCode")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"true")," ","|"," ",Object(r.b)("inlineCode",{parentName:"td"},"false")),Object(r.b)("td",{parentName:"tr",align:null},"Si el código fuente es público")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"options")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"object")," (opcional)"),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"{ fullRange, warmup }"),", ver más abajo")))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-js"},'define("My Indicator", "Shows EMA line", "onchart", true, false);\n')),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Rango de cálculo.")," Por defecto, un script calcula solo la parte del gráfico que lo necesita: las barras cargadas al desplazarte hacia atrás, o las últimas barras en una actualización, más ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"warmup"))," barras de historial anteriores (500 por defecto) que los cálculos necesitan pero que no se devuelven. Declara ",Object(r.b)("inlineCode",{parentName:"p"},"warmup")," cuando tu indicador necesite más o menos historial, p. ej. ",Object(r.b)("inlineCode",{parentName:"p"},"{ warmup: 200 }")," para una EMA(200). Un script cuyos valores o formas dependen de ",Object(r.b)("strong",{parentName:"p"},"todo el rango visible")," (VWAP desde la primera vela visible, delta acumulado, una etiqueta en el máximo de la ventana, niveles dibujados a lo ancho del gráfico) debe declarar ",Object(r.b)("inlineCode",{parentName:"p"},"{ fullRange: true }"),"; de lo contrario, sus resultados serán incorrectos después de cargar más historial. El modo se lee de ",Object(r.b)("inlineCode",{parentName:"p"},"define()")," cada vez que se guarda el script: un script guardado sin ",Object(r.b)("inlineCode",{parentName:"p"},"fullRange")," se calcula parcialmente, así que añade la opción a tus scripts acumulativos existentes cuando los edites. Los scripts parciales también se cargan por partes: cuando activas uno sobre un historial largo, el gráfico solicita primero las 500 velas más recientes (o ",Object(r.b)("inlineCode",{parentName:"p"},"warmup")," velas si es un número mayor) y las partes más antiguas llegan después, una solicitud a la vez, de modo que la parte visible aparece de inmediato. Los scripts con ",Object(r.b)("inlineCode",{parentName:"p"},"fullRange")," siempre se calculan en una sola solicitud sobre todo el rango."),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-js"},'define("Window max", "Label at the highest visible high", "onchart", true, true, { fullRange: true });\n')),Object(r.b)("p",null,"Ubicación del indicador para ",Object(r.b)("strong",{parentName:"p"},"onchart")," y ",Object(r.b)("strong",{parentName:"p"},"offchart"),":"),Object(r.b)(i.f,{src:"../../public/onchart_offchart.png",mdxType:"Screenshot"}),Object(r.b)("h2",{id:"parámetros-de-entrada"},"Parámetros de entrada"),Object(r.b)("p",null,"Las clases ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"input"))," y ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"style"))," te permiten crear ajustes configurables por el usuario (similar a ",Object(r.b)("inlineCode",{parentName:"p"},"input()")," en PineScript)."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number(title, defaultValue, min, max, step)")),Object(r.b)("td",{parentName:"tr",align:null},"Entrada numérica")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"range(title, defaultValue, min, max, step)")),Object(r.b)("td",{parentName:"tr",align:null},"Entrada de rango")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"select(title, defaultValue, values)")),Object(r.b)("td",{parentName:"tr",align:null},"Selección desplegable")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"color(title, defaultValue)")),Object(r.b)("td",{parentName:"tr",align:null},"Selector de color")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"boolean(title, defaultValue)")),Object(r.b)("td",{parentName:"tr",align:null},"Entrada booleana")))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo (input) para los parámetros principales:")),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"O (style) para los parámetros visuales:")),Object(r.b)("pre",null,Object(r.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(r.b)(i.f,{src:"../../public/input_style.png",mdxType:"Screenshot"}),Object(r.b)("h2",{id:"fuentes-de-datos"},"Fuentes de datos"),Object(r.b)("p",null,"La clase ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"source"))," obtiene datos de mercado del servidor. Los métodos basados en velas reciben los mismos parámetros; las dos instantáneas en vivo son diferentes: ",Object(r.b)("inlineCode",{parentName:"p"},"orderbook()")," recibe un exchange y un ticker, ",Object(r.b)("inlineCode",{parentName:"p"},"levels()")," un exchange y un objeto de ajustes."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Parámetro"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"exchange"),", ",Object(r.b)("inlineCode",{parentName:"td"},"ticker"),", ",Object(r.b)("inlineCode",{parentName:"td"},"timeframe")),Object(r.b)("td",{parentName:"tr",align:null},"Por defecto, los del gráfico en el que está abierto el indicador. Pasa otros valores para obtener datos de otro mercado.")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"lookback")),Object(r.b)("td",{parentName:"tr",align:null},"Número de barras de historial desde la fecha actual, ",Object(r.b)("strong",{parentName:"td"},"no más de 5000"),".")))),Object(r.b)(i.b,{type:"note",title:"Los datos se alinean con las velas del gráfico",mdxType:"Callout"},Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"ohlcv()"),", ",Object(r.b)("inlineCode",{parentName:"p"},"depths()"),", ",Object(r.b)("inlineCode",{parentName:"p"},"clusters()"),", ",Object(r.b)("inlineCode",{parentName:"p"},"liquidations()")," y ",Object(r.b)("inlineCode",{parentName:"p"},"moreData()")," de la temporalidad del gráfico devuelven ",Object(r.b)("strong",{parentName:"p"},"una entrada por vela del gráfico"),": ",Object(r.b)("inlineCode",{parentName:"p"},"depths()[i]")," es el libro de órdenes de ",Object(r.b)("inlineCode",{parentName:"p"},"ohlcv()[i]"),", ",Object(r.b)("inlineCode",{parentName:"p"},"moreData()[i]")," contiene sus datos de derivados, etc. Cuando una fuente no tiene registro para una vela (por ejemplo, el historial del libro de órdenes es más corto que el de velas), la entrada es ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"null")),", así que compruébalo siempre. Los datos solicitados con ",Object(r.b)("inlineCode",{parentName:"p"},"lookback")," o para otra temporalidad se devuelven tal cual y deben emparejarse por ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"startTime")),". ",Object(r.b)("inlineCode",{parentName:"p"},"ohlcv()")," del mercado del gráfico contiene solo las velas que el servidor ya ha cargado, nunca ",Object(r.b)("inlineCode",{parentName:"p"},"null"),"; mientras el historial más antiguo todavía se está cargando, el indicador se recalcula automáticamente.")),Object(r.b)("h3",{id:"ohlcvexchange-ticker-timeframe-lookback"},Object(r.b)("inlineCode",{parentName:"h3"},"ohlcv(exchange, ticker, timeframe, lookback?)")),Object(r.b)("p",null,"Datos de velas."),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"depthsexchange-ticker-timeframe-lookback"},Object(r.b)("inlineCode",{parentName:"h3"},"depths(exchange, ticker, timeframe, lookback?)")),Object(r.b)("p",null,"Instantáneas históricas del libro de órdenes, una por vela. Solo se guardan las órdenes límite más grandes (los datos detrás del mapa de calor)."),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"clustersexchange-ticker-timeframe-lookback"},Object(r.b)("inlineCode",{parentName:"h3"},"clusters(exchange, ticker, timeframe, lookback?)")),Object(r.b)("p",null,"Datos de clústeres (footprint): volumen de compra y de venta en cada nivel de precio de la vela."),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"liquidationsexchange-ticker-timeframe-lookback"},Object(r.b)("inlineCode",{parentName:"h3"},"liquidations(exchange, ticker, timeframe, lookback?)")),Object(r.b)("p",null,"Volumen liquidado en cada nivel de precio de la vela (solo mercados de futuros). Mismo formato que ",Object(r.b)("inlineCode",{parentName:"p"},"clusters()"),"."),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"moredataexchange-ticker-timeframe-lookback"},Object(r.b)("inlineCode",{parentName:"h3"},"moreData(exchange, ticker, timeframe, lookback?)")),Object(r.b)("p",null,"Datos de derivados por vela: tasa de financiación, vela de interés abierto, ratios long/short (solo mercados de futuros)."),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"orderbookexchange-ticker"},Object(r.b)("inlineCode",{parentName:"h3"},"orderbook(exchange, ticker)")),Object(r.b)("p",null,"Instantánea en vivo del libro de órdenes: el libro completo actual, no vinculado a las velas."),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"Los niveles no están ordenados; usa las funciones de libro de órdenes de ",Object(r.b)("inlineCode",{parentName:"p"},"ta")," (",Object(r.b)("inlineCode",{parentName:"p"},"ta.bestBid"),", ",Object(r.b)("inlineCode",{parentName:"p"},"ta.sumBids"),", ...) para trabajar con el libro.\nLos libros históricos de las velas provienen de ",Object(r.b)("inlineCode",{parentName:"p"},"depths()"),": ",Object(r.b)("inlineCode",{parentName:"p"},"depths()[i].data")," tiene el mismo formato, pero allí solo se guardan las órdenes límite más grandes."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"levelsexchange-settings"},Object(r.b)("inlineCode",{parentName:"h3"},"levels(exchange, settings?)")),Object(r.b)("p",null,"Los niveles del ",Object(r.b)("strong",{parentName:"p"},"Screener de liquidez"),": las grandes órdenes límite en espera de un exchange, filtradas con los mismos ajustes que la página del screener. Datos en vivo, no vinculados a las velas. Sin plan, la cercanía se limita al 1%, la antigüedad a 60 minutos y el resultado a 200 niveles; con un plan, hasta 2000 niveles. Las órdenes más grandes van primero. Cuenta como una solicitud de fuente de datos."),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ajustes")," (todos opcionales):"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Ajuste"),Object(r.b)("th",{parentName:"tr",align:null},"Por defecto"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"tickers")),Object(r.b)("td",{parentName:"tr",align:null},"todos los tickers"),Object(r.b)("td",{parentName:"tr",align:null},"solo estos tickers del exchange")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"exclude")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"[]")),Object(r.b)("td",{parentName:"tr",align:null},"tickers que se omiten")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"type")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},'"all"')),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},'"all"'),", ",Object(r.b)("inlineCode",{parentName:"td"},'"bids"')," o ",Object(r.b)("inlineCode",{parentName:"td"},'"asks"'))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"nearness")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"5")),Object(r.b)("td",{parentName:"tr",align:null},"distancia máxima al precio actual, en porcentaje")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"size")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"100000")),Object(r.b)("td",{parentName:"tr",align:null},"tamaño mínimo de la orden en la moneda de cotización")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"lifespan")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"0")),Object(r.b)("td",{parentName:"tr",align:null},"minutos mínimos que la orden lleva en el libro")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"touches"),", ",Object(r.b)("inlineCode",{parentName:"td"},"currentTouches")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"0")),Object(r.b)("td",{parentName:"tr",align:null},"toques mínimos del nivel / de la orden actual")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"filled")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"0")),Object(r.b)("td",{parentName:"tr",align:null},"parte ejecutada mínima de la orden, en porcentaje")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"strength"),", ",Object(r.b)("inlineCode",{parentName:"td"},"diversity")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"0")),Object(r.b)("td",{parentName:"tr",align:null},"fuerza (en porcentaje) y diversidad mínimas, como en el screener")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"continuousOnly")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"false")),Object(r.b)("td",{parentName:"tr",align:null},"omite las órdenes que desaparecieron y volvieron")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"volume1h")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"0")),Object(r.b)("td",{parentName:"tr",align:null},"volumen mínimo de 1h del ticker en la moneda de cotización")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"spotAndFutures")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"false")),Object(r.b)("td",{parentName:"tr",align:null},"solo tickers que existen tanto en el mercado spot como en el de futuros")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"limit")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"500")),Object(r.b)("td",{parentName:"tr",align:null},"número máximo de niveles, los más grandes primero (máx. 2000)")))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"solicitudes-http"},"Solicitudes HTTP"),Object(r.b)("p",null,"La clase ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"http"))," envía solicitudes a APIs HTTP externas y devuelve la respuesta, de modo que un indicador puede usar datos que no están disponibles en ",Object(r.b)("inlineCode",{parentName:"p"},"source"),": tu propio servidor, una API REST pública, un proveedor de métricas on-chain, ...\nAl igual que ",Object(r.b)("inlineCode",{parentName:"p"},"source.*"),", las llamadas se escriben como funciones síncronas, no hace falta ",Object(r.b)("inlineCode",{parentName:"p"},"await"),"."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"get(url, options?)")),Object(r.b)("td",{parentName:"tr",align:null},"Solicitud GET")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"post(url, body?, options?)")),Object(r.b)("td",{parentName:"tr",align:null},"Solicitud POST. Un ",Object(r.b)("inlineCode",{parentName:"td"},"body")," de tipo objeto o array se envía como JSON (",Object(r.b)("inlineCode",{parentName:"td"},"Content-Type: application/json"),"), una cadena se envía tal cual")))),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"options")," es ",Object(r.b)("inlineCode",{parentName:"p"},"{ headers: { name: value } }"),": hasta ",Object(r.b)("strong",{parentName:"p"},"10")," cabeceras personalizadas (por ejemplo, ",Object(r.b)("inlineCode",{parentName:"p"},"Authorization")," o ",Object(r.b)("inlineCode",{parentName:"p"},"x-api-key"),")."),Object(r.b)("p",null,"Ambos métodos devuelven el mismo objeto de respuesta y ",Object(r.b)("strong",{parentName:"p"},"nunca lanzan excepciones"),":"),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-js"},'{\n ok: true, // status 200–299\n status: 200, // HTTP status, 0 when the request was not sent\n headers: { "content-type": "application/json", ... },\n data: { ... }, // response body parsed as JSON, null when the body is not JSON\n text: "...", // raw response body\n error: null // reason when the request failed: "timeout", "url not allowed", "too many requests", ...\n}\n')),Object(r.b)(i.b,{type:"warning",title:"Límites y seguridad",mdxType:"Callout"},Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Hasta ",Object(r.b)("strong",{parentName:"li"},"3 solicitudes")," por ejecución del script y ",Object(r.b)("strong",{parentName:"li"},"60 solicitudes por minuto")," por usuario."),Object(r.b)("li",{parentName:"ul"},"Solo URLs públicas ",Object(r.b)("inlineCode",{parentName:"li"},"http://")," / ",Object(r.b)("inlineCode",{parentName:"li"},"https://"),". Las solicitudes a ",Object(r.b)("inlineCode",{parentName:"li"},"localhost"),", redes privadas y direcciones de metadatos de la nube se rechazan; las redirecciones ",Object(r.b)("strong",{parentName:"li"},"no se siguen")," (una respuesta ",Object(r.b)("inlineCode",{parentName:"li"},"3xx")," se devuelve tal cual)."),Object(r.b)("li",{parentName:"ul"},"Las solicitudes se envían desde los servidores proxy de MobChart: la API de destino ve la dirección del proxy y nunca tu IP."),Object(r.b)("li",{parentName:"ul"},"Tiempo de espera de ",Object(r.b)("strong",{parentName:"li"},"5 segundos"),", cuerpo de la solicitud de hasta ",Object(r.b)("strong",{parentName:"li"},"64 KB"),", respuesta de hasta ",Object(r.b)("strong",{parentName:"li"},"512 KB")," (las respuestas más grandes fallan con ",Object(r.b)("inlineCode",{parentName:"li"},"response too large"),")."),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"Host"),", ",Object(r.b)("inlineCode",{parentName:"li"},"Cookie"),", ",Object(r.b)("inlineCode",{parentName:"li"},"Proxy-*"),", ",Object(r.b)("inlineCode",{parentName:"li"},"X-Forwarded-*")," y otras cabeceras de conexión no se pueden establecer; ",Object(r.b)("inlineCode",{parentName:"li"},"Set-Cookie")," nunca se devuelve."),Object(r.b)("li",{parentName:"ul"},"Las comprobaciones de alertas ejecutan tu script en el servidor con regularidad: la API se llama en cada comprobación, ten en cuenta los límites de frecuencia de la API de destino."),Object(r.b)("li",{parentName:"ul"},"El código de un indicador público (",Object(r.b)("inlineCode",{parentName:"li"},"isPublicCode = true"),") es visible para todos: nunca pongas claves de API en código público."))),Object(r.b)("p",null,"Valores posibles de ",Object(r.b)("inlineCode",{parentName:"p"},"error"),": ",Object(r.b)("inlineCode",{parentName:"p"},"invalid url"),", ",Object(r.b)("inlineCode",{parentName:"p"},"url not allowed"),", ",Object(r.b)("inlineCode",{parentName:"p"},"invalid headers"),", ",Object(r.b)("inlineCode",{parentName:"p"},"invalid body"),", ",Object(r.b)("inlineCode",{parentName:"p"},"body too large"),", ",Object(r.b)("inlineCode",{parentName:"p"},"response too large"),", ",Object(r.b)("inlineCode",{parentName:"p"},"timeout"),", ",Object(r.b)("inlineCode",{parentName:"p"},"too many requests"),", ",Object(r.b)("inlineCode",{parentName:"p"},"rate limit"),", ",Object(r.b)("inlineCode",{parentName:"p"},"busy"),", ",Object(r.b)("inlineCode",{parentName:"p"},"proxy unavailable"),", ",Object(r.b)("inlineCode",{parentName:"p"},"network error"),"."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo (GET):")),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo (POST):")),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"variables-globales"},"Variables globales"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Variable"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"),Object(r.b)("th",{parentName:"tr",align:null},"Ejemplo"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"currentExchange")),Object(r.b)("td",{parentName:"tr",align:null},"Exchange actual del gráfico"),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"binance"),", ",Object(r.b)("inlineCode",{parentName:"td"},"binanceFutures"),", ",Object(r.b)("inlineCode",{parentName:"td"},"coinbase"),", ...")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"currentTicker")),Object(r.b)("td",{parentName:"tr",align:null},"Ticker actual del gráfico (el formato depende del exchange)"),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"BTCUSDT"),", ",Object(r.b)("inlineCode",{parentName:"td"},"ADA-USD"),", ",Object(r.b)("inlineCode",{parentName:"td"},"BTC/USDC"),", ...")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"currentTimeframe")),Object(r.b)("td",{parentName:"tr",align:null},"Temporalidad actual del gráfico"),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"1m"),", ",Object(r.b)("inlineCode",{parentName:"td"},"5m"),", ",Object(r.b)("inlineCode",{parentName:"td"},"15m"),", ...")))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-js"},"const candles = source.ohlcv(currentExchange, currentTicker, currentTimeframe);\nconst closes = candles.map(c => c.close);\n")),Object(r.b)("h2",{id:"registro-logging"},"Registro (logging)"),Object(r.b)("p",null,"La clase ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"logger"))," se usa para mostrar información y depurar."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"log(...args)")),Object(r.b)("td",{parentName:"tr",align:null},"Añade una entrada al registro (con límites de longitud y cantidad)")))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nlogger.log("First candle:", candles?.[0]);\n')),Object(r.b)(i.f,{src:"../../public/code_editor_log.png",mdxType:"Screenshot"}),Object(r.b)("h2",{id:"visualización"},"Visualización"),Object(r.b)("p",null,"La clase ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"plot"))," se encarga de dibujar elementos gráficos y series de datos."),Object(r.b)("h3",{id:"formas-geométricas"},"Formas geométricas"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"box(title, date1, price1, date2, price2, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(r.b)("td",{parentName:"tr",align:null},"Rectángulo")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"square(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(r.b)("td",{parentName:"tr",align:null},"Cuadrado")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"diamond(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(r.b)("td",{parentName:"tr",align:null},"Rombo")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"triangle(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(r.b)("td",{parentName:"tr",align:null},"Triángulo")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"circle(title, date1, price1, radius = 10, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(r.b)("td",{parentName:"tr",align:null},"Círculo")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"text(title, value, date1, price1, fontSize, fill, opacity)")),Object(r.b)("td",{parentName:"tr",align:null},"Texto en el gráfico")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"table(title, rows, options)")),Object(r.b)("td",{parentName:"tr",align:null},"Tabla fijada en una esquina del gráfico, consulta ",Object(r.b)("a",{parentName:"td",href:"#tablas"},"Tablas"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"straightLine(title, date1, price1, date2, price2, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(r.b)("td",{parentName:"tr",align:null},"Línea recta")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"horizontalLine(title, price1, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(r.b)("td",{parentName:"tr",align:null},"Línea horizontal a lo ancho de todo el gráfico")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"verticalLine(title, date1, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(r.b)("td",{parentName:"tr",align:null},"Línea vertical a lo alto de todo el gráfico")))),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Parámetro"),Object(r.b)("th",{parentName:"tr",align:null},"Tipo de dato"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"title")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"string")),Object(r.b)("td",{parentName:"tr",align:null},"Nombre del elemento (identificador único en el gráfico)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"date1")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")," (timestamp, ms)"),Object(r.b)("td",{parentName:"tr",align:null},"Marca de tiempo inicial")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"price1")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")),Object(r.b)("td",{parentName:"tr",align:null},"Precio inicial (coordenada del eje Y)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"date2")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")," (timestamp, ms)"),Object(r.b)("td",{parentName:"tr",align:null},"Marca de tiempo final (para líneas y rectángulos)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"price2")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")),Object(r.b)("td",{parentName:"tr",align:null},"Precio final (para líneas y rectángulos)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"size")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")),Object(r.b)("td",{parentName:"tr",align:null},"Tamaño de la forma (en píxeles)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"radius")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")),Object(r.b)("td",{parentName:"tr",align:null},"Radio del círculo (10 por defecto)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"fill")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"string")," (hex, p. ej., ",Object(r.b)("inlineCode",{parentName:"td"},'"#FF0000"'),")"),Object(r.b)("td",{parentName:"tr",align:null},"Color de relleno de la forma")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"opacity")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")," (0–1)"),Object(r.b)("td",{parentName:"tr",align:null},"Opacidad del relleno")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"stroke")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"string")," (hex, p. ej., ",Object(r.b)("inlineCode",{parentName:"td"},'"#000000"'),")"),Object(r.b)("td",{parentName:"tr",align:null},"Color del trazo")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"strokeOpacity")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")," (0–1)"),Object(r.b)("td",{parentName:"tr",align:null},"Opacidad del trazo")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"strokeWidth")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")),Object(r.b)("td",{parentName:"tr",align:null},"Grosor del trazo (en píxeles)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"strokeDasharray")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"array")," (p. ej., ",Object(r.b)("inlineCode",{parentName:"td"},"[5,5]"),")"),Object(r.b)("td",{parentName:"tr",align:null},"Estilo de línea discontinua")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"fontSize")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")),Object(r.b)("td",{parentName:"tr",align:null},"Tamaño del texto (en píxeles)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"value")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"string")),Object(r.b)("td",{parentName:"tr",align:null},"Valor del texto (para el método ",Object(r.b)("inlineCode",{parentName:"td"},"text"),")")))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"No se pueden mostrar más de ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"3000"))," formas en el gráfico."),Object(r.b)("h3",{id:"series-de-datos"},"Series de datos"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"lineSeries(title, values, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(r.b)("td",{parentName:"tr",align:null},"Gráfico de líneas")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"barSeries(title, values, fill, opacity)")),Object(r.b)("td",{parentName:"tr",align:null},"Gráfico de barras")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"candleSeries(title, openValues, closeValues, highValues, lowValues, fill, opacity)")),Object(r.b)("td",{parentName:"tr",align:null},"Velas")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"areaSeries(title, values, fill, opacity, stroke, strokeOpacity, strokeWidth, base)")),Object(r.b)("td",{parentName:"tr",align:null},"Área rellena entre la línea y ",Object(r.b)("inlineCode",{parentName:"td"},"base")," (por defecto: la parte inferior del gráfico)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"bandSeries(title, upperValues, lowerValues, fill, opacity, stroke, strokeOpacity, strokeWidth, step)")),Object(r.b)("td",{parentName:"tr",align:null},"Banda rellena entre dos series; cada vela conserva su propio color y opacidad")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"profile(title, values, options)")),Object(r.b)("td",{parentName:"tr",align:null},"Histograma tipo perfil de volumen de las velas visibles, consulta ",Object(r.b)("a",{parentName:"td",href:"#perfiles"},"Perfiles"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"histogram(title, rows, options)")),Object(r.b)("td",{parentName:"tr",align:null},"Un mapa de precios ya terminado dibujado como un perfil, consulta ",Object(r.b)("a",{parentName:"td",href:"#histogramas"},"Histogramas"))))),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Parámetro"),Object(r.b)("th",{parentName:"tr",align:null},"Tipo de dato"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"values"),", ",Object(r.b)("inlineCode",{parentName:"td"},"upperValues"),", ",Object(r.b)("inlineCode",{parentName:"td"},"lowerValues")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"(number \\| null)[]")),Object(r.b)("td",{parentName:"tr",align:null},"Un valor por vela, ",Object(r.b)("inlineCode",{parentName:"td"},"null")," oculta la vela")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"fill"),", ",Object(r.b)("inlineCode",{parentName:"td"},"stroke")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"string")," (hex) o ",Object(r.b)("inlineCode",{parentName:"td"},"function")),Object(r.b)("td",{parentName:"tr",align:null},"Color, o una función que devuelve el color de la vela: ",Object(r.b)("inlineCode",{parentName:"td"},"(value, i)")," para ",Object(r.b)("inlineCode",{parentName:"td"},"lineSeries"),", ",Object(r.b)("inlineCode",{parentName:"td"},"barSeries"),", ",Object(r.b)("inlineCode",{parentName:"td"},"candleSeries")," y ",Object(r.b)("inlineCode",{parentName:"td"},"areaSeries"),", ",Object(r.b)("inlineCode",{parentName:"td"},"(upper, lower, i)")," para ",Object(r.b)("inlineCode",{parentName:"td"},"bandSeries"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"opacity")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")," (0–1) o ",Object(r.b)("inlineCode",{parentName:"td"},"function")),Object(r.b)("td",{parentName:"tr",align:null},"Opacidad del relleno, una función ",Object(r.b)("inlineCode",{parentName:"td"},"(value, i)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"(upper, lower, i)")," para ",Object(r.b)("inlineCode",{parentName:"td"},"areaSeries")," / ",Object(r.b)("inlineCode",{parentName:"td"},"bandSeries"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"base")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number")," ","|"," ",Object(r.b)("inlineCode",{parentName:"td"},"null")),Object(r.b)("td",{parentName:"tr",align:null},"Nivel base de ",Object(r.b)("inlineCode",{parentName:"td"},"areaSeries"),", ",Object(r.b)("inlineCode",{parentName:"td"},"null")," = la parte inferior del gráfico")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"step")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"boolean")),Object(r.b)("td",{parentName:"tr",align:null},"Estilo de ",Object(r.b)("inlineCode",{parentName:"td"},"bandSeries"),": ",Object(r.b)("inlineCode",{parentName:"td"},"true")," = una columna por vela (por defecto), ",Object(r.b)("inlineCode",{parentName:"td"},"false")," = un polígono continuo")))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"No se pueden mostrar más de ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"20"))," series de datos en el gráfico."),Object(r.b)("h3",{id:"perfiles"},"Perfiles"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"plot.profile(title, values, options?)")," dibuja un histograma por precio, como el perfil de volumen integrado. ",Object(r.b)("inlineCode",{parentName:"p"},"values[i]")," es el mapa de precios de la vela ",Object(r.b)("inlineCode",{parentName:"p"},"i")," de ",Object(r.b)("inlineCode",{parentName:"p"},"ohlcv()"),": ",Object(r.b)("inlineCode",{parentName:"p"},"{ price: value }")," o ",Object(r.b)("inlineCode",{parentName:"p"},"{ price: { buy, sell } }")," (el ",Object(r.b)("inlineCode",{parentName:"p"},"data")," de un registro de ",Object(r.b)("inlineCode",{parentName:"p"},"clusters()")," o ",Object(r.b)("inlineCode",{parentName:"p"},"liquidations()")," se puede pasar tal cual), o ",Object(r.b)("inlineCode",{parentName:"p"},"null")," para una vela sin filas. Las filas de las velas ",Object(r.b)("strong",{parentName:"p"},"visibles en el gráfico")," se suman por paso de precio en el propio gráfico, por lo que el perfil sigue el desplazamiento, el zoom y la carga de más historial sin una nueva ejecución. Los valores simples se dibujan en un solo color (un valor negativo va a ",Object(r.b)("inlineCode",{parentName:"p"},"fill2"),"); los pares dividen la barra en una parte de compra y otra de venta y permiten el modo delta. ",Object(r.b)("inlineCode",{parentName:"p"},"profile()")," no devuelve ningún manejador de alertas."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Opción"),Object(r.b)("th",{parentName:"tr",align:null},"Por defecto"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"step")),Object(r.b)("td",{parentName:"tr",align:null},"tamaño de tick del gráfico"),Object(r.b)("td",{parentName:"tr",align:null},"altura de la fila en unidades de precio, los precios se redondean hacia abajo a este valor")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"orient")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},'"right"')),Object(r.b)("td",{parentName:"tr",align:null},"borde desde el que crecen las barras, ",Object(r.b)("inlineCode",{parentName:"td"},'"right"')," o ",Object(r.b)("inlineCode",{parentName:"td"},'"left"'))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"width")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"30")),Object(r.b)("td",{parentName:"tr",align:null},"fila más ancha como porcentaje del ancho del gráfico")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"fill")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},'"#26a69a"')),Object(r.b)("td",{parentName:"tr",align:null},"color del valor, o de la parte de compra")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"fill2")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},'"#ef5350"')),Object(r.b)("td",{parentName:"tr",align:null},"color de la parte de venta")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"opacity")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"0.6")),Object(r.b)("td",{parentName:"tr",align:null},"opacidad de las barras")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"delta")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"false")),Object(r.b)("td",{parentName:"tr",align:null},"dibuja ",Object(r.b)("inlineCode",{parentName:"td"},"buy - sell")," en lugar de la suma, solo pares")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"poc")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"true")),Object(r.b)("td",{parentName:"tr",align:null},"línea en la fila con el valor más grande")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"valueArea")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"70")),Object(r.b)("td",{parentName:"tr",align:null},"porcentaje del total alrededor del POC dibujado con opacidad completa, ",Object(r.b)("inlineCode",{parentName:"td"},"false")," para desactivarlo")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"valueAreaOpacity")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"0.3")),Object(r.b)("td",{parentName:"tr",align:null},"opacidad de las filas fuera del área de valor")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"labels")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"true")),Object(r.b)("td",{parentName:"tr",align:null},"totales de las filas sobre las barras cuando hay espacio")))),Object(r.b)("p",null,"Límites: ",Object(r.b)("strong",{parentName:"p"},"3")," perfiles por ejecución, ",Object(r.b)("strong",{parentName:"p"},"300")," filas por vela, ",Object(r.b)("strong",{parentName:"p"},"200000")," filas por perfil. Las filas que superan los límites se descartan y la ejecución registra una nota."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"histogramas"},"Histogramas"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"plot.histogram(title, rows, options?)")," dibuja un histograma que ya has construido: ",Object(r.b)("strong",{parentName:"p"},"un único mapa de precios para todo el gráfico"),", no se suma nada a partir de las velas. Usa ",Object(r.b)("inlineCode",{parentName:"p"},"profile()")," cuando las filas pertenecen a velas y la imagen debe seguir el rango visible, y ",Object(r.b)("inlineCode",{parentName:"p"},"histogram()")," cuando las filas son definitivas: una instantánea del libro de órdenes, niveles calculados por el script, datos de otro mercado."),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"rows")," admite los mismos formatos que una entrada de vela de ",Object(r.b)("inlineCode",{parentName:"p"},"profile()"),": ",Object(r.b)("inlineCode",{parentName:"p"},"{ price: value }"),", ",Object(r.b)("inlineCode",{parentName:"p"},"{ price: { buy, sell } }")," o una lista de filas ",Object(r.b)("inlineCode",{parentName:"p"},"[price, buy, sell]"),". Un valor simple se dibuja en un solo color (un valor negativo va a ",Object(r.b)("inlineCode",{parentName:"p"},"fill2"),"); los pares dividen la barra en una parte de compra y otra de venta y permiten el modo delta. Las opciones son las mismas que para ",Object(r.b)("inlineCode",{parentName:"p"},"profile()"),", consulta la tabla anterior."),Object(r.b)("p",null,"El histograma se fecha con la última vela de la ejecución y el gráfico conserva el histograma ",Object(r.b)("strong",{parentName:"p"},"más reciente")," de cada título, por lo que las ejecuciones parciales sobre velas más antiguas (al cargar historial) nunca sustituyen al actual. Se vuelve a dibujar en cada actualización del script, de modo que un histograma del libro de órdenes sigue al libro en vivo. ",Object(r.b)("inlineCode",{parentName:"p"},"histogram()")," no devuelve ningún manejador de alertas."),Object(r.b)("p",null,"Límites: ",Object(r.b)("strong",{parentName:"p"},"3")," histogramas por ejecución, ",Object(r.b)("strong",{parentName:"p"},"5000")," filas. Las filas que superan el límite se descartan y la ejecución registra una nota."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo, el libro de órdenes:")),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo, tus propios niveles:")),Object(r.b)("pre",null,Object(r.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(r.b)("h3",{id:"tablas"},"Tablas"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"plot.table(title, rows, options?)")," dibuja una pequeña cuadrícula fijada en una esquina del panel del gráfico: resúmenes multitemporalidad, estadísticas del rango cargado, paneles de señales. ",Object(r.b)("inlineCode",{parentName:"p"},"rows")," es un array de filas, una fila es un array de celdas, y una celda es una cadena, un número o ",Object(r.b)("inlineCode",{parentName:"p"},"{ text, color, bg, align, bold }"),". Las tablas de la misma esquina se apilan en orden. Una tabla se fecha con la última vela de la ejecución y el gráfico conserva la tabla ",Object(r.b)("strong",{parentName:"p"},"más reciente")," de cada título, por lo que las ejecuciones parciales sobre velas más antiguas (al cargar historial) nunca sustituyen a la actual. Las tablas no se dibujan en gráficos de menos de 500 px de ancho. Una tabla se puede arrastrar con el ratón: la posición se guarda con el espacio de trabajo y se restablece cuando el script cambia su opción ",Object(r.b)("inlineCode",{parentName:"p"},"position"),". ",Object(r.b)("inlineCode",{parentName:"p"},"table()")," no devuelve ningún manejador de alertas."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Opción"),Object(r.b)("th",{parentName:"tr",align:null},"Por defecto"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"position")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},'"top-right"')),Object(r.b)("td",{parentName:"tr",align:null},"esquina del panel: ",Object(r.b)("inlineCode",{parentName:"td"},'"top-right"'),", ",Object(r.b)("inlineCode",{parentName:"td"},'"top-left"'),", ",Object(r.b)("inlineCode",{parentName:"td"},'"bottom-right"'),", ",Object(r.b)("inlineCode",{parentName:"td"},'"bottom-left"'))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"header")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"false")),Object(r.b)("td",{parentName:"tr",align:null},"primera fila en negrita sobre una franja sombreada")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"fontSize")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"11")),Object(r.b)("td",{parentName:"tr",align:null},"tamaño del texto en px, de 8 a 16")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"color"),", ",Object(r.b)("inlineCode",{parentName:"td"},"bg"),", ",Object(r.b)("inlineCode",{parentName:"td"},"border")),Object(r.b)("td",{parentName:"tr",align:null},"según el tema"),Object(r.b)("td",{parentName:"tr",align:null},"colores por defecto del texto, del panel y de la cuadrícula; una celda puede sobrescribir ",Object(r.b)("inlineCode",{parentName:"td"},"color")," y ",Object(r.b)("inlineCode",{parentName:"td"},"bg"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"opacity")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"0.85")),Object(r.b)("td",{parentName:"tr",align:null},"opacidad del panel")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"align")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},'"left"')),Object(r.b)("td",{parentName:"tr",align:null},"alineación por defecto de las celdas, ",Object(r.b)("inlineCode",{parentName:"td"},'"left"'),", ",Object(r.b)("inlineCode",{parentName:"td"},'"center"')," o ",Object(r.b)("inlineCode",{parentName:"td"},'"right"'))))),Object(r.b)("p",null,"Límites: ",Object(r.b)("strong",{parentName:"p"},"3")," tablas por ejecución, ",Object(r.b)("strong",{parentName:"p"},"50")," filas, ",Object(r.b)("strong",{parentName:"p"},"10")," columnas, ",Object(r.b)("strong",{parentName:"p"},"100")," caracteres por celda. El texto más largo se corta con puntos suspensivos; una columna ocupa como máximo el 30% del ancho del gráfico."),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"análisis-técnico"},"Análisis técnico"),Object(r.b)("p",null,"La clase ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"ta"))," implementa las funciones ",Object(r.b)("inlineCode",{parentName:"p"},"ta.*")," de PineScript v5. Pine funciona barra a barra; aquí cada función recibe series completas (arrays, un valor por vela, de la más antigua a la más reciente) y devuelve una serie de la misma longitud que se puede dibujar directamente. Los valores son ",Object(r.b)("inlineCode",{parentName:"p"},"null")," mientras el periodo aún no se ha completado, y las entradas ",Object(r.b)("inlineCode",{parentName:"p"},"null")," se propagan como el ",Object(r.b)("inlineCode",{parentName:"p"},"na")," de Pine. Las funciones de Pine que leen ",Object(r.b)("inlineCode",{parentName:"p"},"high"),", ",Object(r.b)("inlineCode",{parentName:"p"},"low"),", ",Object(r.b)("inlineCode",{parentName:"p"},"close")," o ",Object(r.b)("inlineCode",{parentName:"p"},"volume")," de forma implícita reciben esos arrays como argumentos."),Object(r.b)("p",null,"Las funciones que devuelven varias series (",Object(r.b)("inlineCode",{parentName:"p"},"bb"),", ",Object(r.b)("inlineCode",{parentName:"p"},"kc"),", ",Object(r.b)("inlineCode",{parentName:"p"},"macd"),", ",Object(r.b)("inlineCode",{parentName:"p"},"stoch"),", ",Object(r.b)("inlineCode",{parentName:"p"},"dmi"),", ",Object(r.b)("inlineCode",{parentName:"p"},"supertrend"),") devuelven un array que además tiene propiedades con nombre: ",Object(r.b)("inlineCode",{parentName:"p"},"const [middle, upper, lower] = ta.bb(closes, 20, 2)")," o ",Object(r.b)("inlineCode",{parentName:"p"},"ta.bb(closes, 20, 2).upper"),"."),Object(r.b)("h3",{id:"funciones-auxiliares"},"Funciones auxiliares"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"highest(values, length)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"lowest(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Valor máximo / mínimo en ",Object(r.b)("inlineCode",{parentName:"td"},"length")," barras")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"highestbars(values, length)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"lowestbars(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Desplazamiento (0 o negativo) hasta la barra más alta / más baja")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"max(values)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"min(values)")),Object(r.b)("td",{parentName:"tr",align:null},"Máximo / mínimo histórico hasta cada barra")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"range(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"highest - lowest"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"change(values, length = 1)")),Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"values[i] - values[i - length]"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"mom(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Momentum")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"roc(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Tasa de cambio, %")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"cum(values)")),Object(r.b)("td",{parentName:"tr",align:null},"Suma acumulada")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"rising(values, length)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"falling(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"El valor está por encima / por debajo de cada uno de los ",Object(r.b)("inlineCode",{parentName:"td"},"length")," valores anteriores")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"variance(values, length, biased = true)")),Object(r.b)("td",{parentName:"tr",align:null},"Varianza")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"stdev(values, length, biased = true)")),Object(r.b)("td",{parentName:"tr",align:null},"Desviación estándar")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"dev(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Desviación absoluta media")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"median(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Mediana")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"mode(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Valor más frecuente (el menor en caso de empate)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"percentile_linear_interpolation(values, length, percentage)")),Object(r.b)("td",{parentName:"tr",align:null},"Percentil, interpolación lineal entre los dos rangos más cercanos")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"percentile_nearest_rank(values, length, percentage)")),Object(r.b)("td",{parentName:"tr",align:null},"Percentil, método del rango más cercano")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"percentrank(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"% de los ",Object(r.b)("inlineCode",{parentName:"td"},"length")," valores anteriores menores o iguales que el actual")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"correlation(series1, series2, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Coeficiente de correlación")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"crossover(series1, series2)")),Object(r.b)("td",{parentName:"tr",align:null},"Cruce al alza (cualquiera de los argumentos puede ser un número: ",Object(r.b)("inlineCode",{parentName:"td"},"ta.crossover(rsi, 70)"),")")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"crossunder(series1, series2)")),Object(r.b)("td",{parentName:"tr",align:null},"Cruce a la baja")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"cross(series1, series2)")),Object(r.b)("td",{parentName:"tr",align:null},"Cualquier cruce")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"barssince(condition)")),Object(r.b)("td",{parentName:"tr",align:null},"Barras desde la última vez que ",Object(r.b)("inlineCode",{parentName:"td"},"condition")," (array de booleanos) fue verdadera")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"valuewhen(condition, values, occurrence = 0)")),Object(r.b)("td",{parentName:"tr",align:null},"Valor de ",Object(r.b)("inlineCode",{parentName:"td"},"values")," cuando ",Object(r.b)("inlineCode",{parentName:"td"},"condition")," fue verdadera hace ",Object(r.b)("inlineCode",{parentName:"td"},"occurrence")," veces")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"pivothigh(values, leftbars, rightbars)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"pivotlow(...)")),Object(r.b)("td",{parentName:"tr",align:null},"Valor del pivote en la barra de confirmación; el pivote en sí está ",Object(r.b)("inlineCode",{parentName:"td"},"rightbars")," barras antes")))),Object(r.b)("h3",{id:"medias-móviles"},"Medias móviles"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"sma(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Media móvil simple")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"ema(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Media móvil exponencial")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"rma(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Media móvil de Wilder (usada por RSI / ATR)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"wma(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Media móvil ponderada")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"hma(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Media móvil de Hull")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"alma(values, length, offset = 0.85, sigma = 6, floor = false)")),Object(r.b)("td",{parentName:"tr",align:null},"Media móvil de Arnaud Legoux")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"swma(values)")),Object(r.b)("td",{parentName:"tr",align:null},"Media móvil ponderada simétricamente sobre 4 barras")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"vwma(values, volumes, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Media móvil ponderada por volumen")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"linreg(values, length, offset = 0)")),Object(r.b)("td",{parentName:"tr",align:null},"Curva de regresión lineal")))),Object(r.b)("h3",{id:"osciladores"},"Osciladores"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"rsi(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Índice de fuerza relativa (Relative Strength Index)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"cmo(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Oscilador de momentum de Chande (Chande Momentum Oscillator)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"cog(values, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Centro de gravedad (Center of Gravity)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"mfi(values, volumes, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Money Flow Index (",Object(r.b)("inlineCode",{parentName:"td"},"values")," suele ser hlc3)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"tsi(values, shortLength, longLength)")),Object(r.b)("td",{parentName:"tr",align:null},"True Strength Index, -1..1")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"wpr(highs, lows, closes, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Williams %R")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"stoch(highs, lows, closes, period = 14, smoothK = 3, smoothD = 3)")),Object(r.b)("td",{parentName:"tr",align:null},"Estocástico ",Object(r.b)("inlineCode",{parentName:"td"},"[k, d]"),", ",Object(r.b)("inlineCode",{parentName:"td"},"smoothK = 1")," da el valor sin suavizar")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"cci(values, length)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"cci(highs, lows, closes, length)")),Object(r.b)("td",{parentName:"tr",align:null},"Commodity Channel Index (del precio típico en la segunda forma)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"macd(values, fast = 12, slow = 26, signalPeriod = 9)")),Object(r.b)("td",{parentName:"tr",align:null},"MACD ",Object(r.b)("inlineCode",{parentName:"td"},"[macd, signal, histogram]"))))),Object(r.b)("h3",{id:"bandas-y-canales"},"Bandas y canales"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"bb(values, length = 20, mult = 2)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"bollinger(...)")),Object(r.b)("td",{parentName:"tr",align:null},"Bandas de Bollinger ",Object(r.b)("inlineCode",{parentName:"td"},"[middle, upper, lower]"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"bbw(values, length, mult)")),Object(r.b)("td",{parentName:"tr",align:null},"Ancho de las Bandas de Bollinger ",Object(r.b)("inlineCode",{parentName:"td"},"(upper - lower) / middle"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"kc(values, highs, lows, closes, length = 20, mult = 2, useTrueRange = true)")),Object(r.b)("td",{parentName:"tr",align:null},"Canales de Keltner ",Object(r.b)("inlineCode",{parentName:"td"},"[middle, upper, lower]"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"kcw(values, highs, lows, closes, length, mult, useTrueRange)")),Object(r.b)("td",{parentName:"tr",align:null},"Ancho de los Canales de Keltner ",Object(r.b)("inlineCode",{parentName:"td"},"(upper - lower) / middle"))))),Object(r.b)("h3",{id:"tendencia-y-volatilidad"},"Tendencia y volatilidad"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"tr(highs, lows, closes, handleNa = false)")),Object(r.b)("td",{parentName:"tr",align:null},"Rango verdadero (",Object(r.b)("inlineCode",{parentName:"td"},"handleNa = true")," da ",Object(r.b)("inlineCode",{parentName:"td"},"high - low")," en la primera barra)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"atr(highs, lows, closes, period = 14)")),Object(r.b)("td",{parentName:"tr",align:null},"Rango verdadero medio (Average True Range)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"dmi(highs, lows, closes, diLength = 14, adxSmoothing = 14)")),Object(r.b)("td",{parentName:"tr",align:null},"Movimiento direccional ",Object(r.b)("inlineCode",{parentName:"td"},"[plus, minus, adx]"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"adx(highs, lows, closes, period = 14)")),Object(r.b)("td",{parentName:"tr",align:null},"Índice direccional medio (Average Directional Index)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"sar(highs, lows, closes, start = 0.02, inc = 0.02, max = 0.2)")),Object(r.b)("td",{parentName:"tr",align:null},"SAR parabólico")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"supertrend(highs, lows, closes, factor = 3, atrPeriod = 10)")),Object(r.b)("td",{parentName:"tr",align:null},"Supertrend ",Object(r.b)("inlineCode",{parentName:"td"},"[supertrend, direction]"),", direction ",Object(r.b)("inlineCode",{parentName:"td"},"-1")," = tendencia alcista, ",Object(r.b)("inlineCode",{parentName:"td"},"1")," = tendencia bajista")))),Object(r.b)("h3",{id:"volumen"},"Volumen"),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"vwap(values, volumes, anchor?)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"vwap(highs, lows, closes, volumes, anchor?)")),Object(r.b)("td",{parentName:"tr",align:null},"VWAP acumulado (del precio típico en la segunda forma), se reinicia en las barras donde ",Object(r.b)("inlineCode",{parentName:"td"},"anchor")," (array de booleanos) es verdadero")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"obv(closes, volumes)")),Object(r.b)("td",{parentName:"tr",align:null},"On Balance Volume")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"accdist(highs, lows, closes, volumes)")),Object(r.b)("td",{parentName:"tr",align:null},"Acumulación / Distribución")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"iii(highs, lows, closes, volumes)")),Object(r.b)("td",{parentName:"tr",align:null},"Intraday Intensity Index")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"pvt(closes, volumes)")),Object(r.b)("td",{parentName:"tr",align:null},"Price-Volume Trend")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"nvi(closes, volumes)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"pvi(closes, volumes)")),Object(r.b)("td",{parentName:"tr",align:null},"Índice de volumen negativo / positivo")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"wad(highs, lows, closes)")),Object(r.b)("td",{parentName:"tr",align:null},"Acumulación / Distribución de Williams")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"wvad(opens, highs, lows, closes, volumes)")),Object(r.b)("td",{parentName:"tr",align:null},"Acumulación / Distribución variable de Williams")))),Object(r.b)("h3",{id:"funciones-del-libro-de-órdenes"},"Funciones del libro de órdenes"),Object(r.b)("p",null,Object(r.b)("inlineCode",{parentName:"p"},"orderbook")," es ",Object(r.b)("inlineCode",{parentName:"p"},"source.orderbook()")," o ",Object(r.b)("inlineCode",{parentName:"p"},"source.depths()[i].data"),": ",Object(r.b)("inlineCode",{parentName:"p"},"{asks: {price: quantity}, bids: {price: quantity}}"),"."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"orderbookSide(orderbook, side)")),Object(r.b)("td",{parentName:"tr",align:null},"Un lado (",Object(r.b)("inlineCode",{parentName:"td"},"'bids'")," / ",Object(r.b)("inlineCode",{parentName:"td"},"'asks'"),") como ",Object(r.b)("inlineCode",{parentName:"td"},"[[price, quantity], ...]"),", ordenado empezando por el mejor precio")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"bestBid(orderbook)")," / ",Object(r.b)("inlineCode",{parentName:"td"},"bestAsk(orderbook)")),Object(r.b)("td",{parentName:"tr",align:null},"Mejor precio bid / ask (",Object(r.b)("inlineCode",{parentName:"td"},"null")," para un libro vacío)")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"sumBids(orderbook, percent, price, inQuote)")),Object(r.b)("td",{parentName:"tr",align:null},"Cantidad bid acumulada entre ",Object(r.b)("inlineCode",{parentName:"td"},"price")," (por defecto: el mejor bid) y ",Object(r.b)("inlineCode",{parentName:"td"},"price * (1 - percent / 100)"),", ",Object(r.b)("inlineCode",{parentName:"td"},"inQuote = true")," suma ",Object(r.b)("inlineCode",{parentName:"td"},"price * quantity"))),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"sumAsks(orderbook, percent, price, inQuote)")),Object(r.b)("td",{parentName:"tr",align:null},"Cantidad ask acumulada entre ",Object(r.b)("inlineCode",{parentName:"td"},"price")," (por defecto: el mejor ask) y ",Object(r.b)("inlineCode",{parentName:"td"},"price * (1 + percent / 100)"))))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"alertas"},"Alertas"),Object(r.b)("p",null,"Los usuarios pueden crear alertas para tu indicador desde la pestaña ",Object(r.b)("strong",{parentName:"p"},"Alertas")," en los ajustes del indicador en el gráfico.\nLas alertas se comprueban regularmente en el servidor; las notificaciones se envían a ",Object(r.b)("strong",{parentName:"p"},"Telegram")," y/o a una ",Object(r.b)("strong",{parentName:"p"},"URL de webhook")," definida por el usuario."),Object(r.b)("h3",{id:"ajustes-de-alertas--alertinput"},"Ajustes de alertas — ",Object(r.b)("inlineCode",{parentName:"h3"},"alertInput")),Object(r.b)("p",null,"La clase ",Object(r.b)("strong",{parentName:"p"},Object(r.b)("inlineCode",{parentName:"strong"},"alertInput"))," declara los ajustes de las alertas. Funciona exactamente igual que ",Object(r.b)("inlineCode",{parentName:"p"},"input"),", pero los campos se muestran en la pestaña ",Object(r.b)("strong",{parentName:"p"},"Alertas")," y cada usuario configura sus propios valores para su alerta."),Object(r.b)("p",null,"Los scripts sin declaraciones ",Object(r.b)("inlineCode",{parentName:"p"},"alertInput")," no se pueden usar para alertas."),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"number(title, defaultValue, min, max, step)")),Object(r.b)("td",{parentName:"tr",align:null},"Entrada numérica")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"range(title, defaultValue, min, max, step)")),Object(r.b)("td",{parentName:"tr",align:null},"Entrada de rango")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"select(title, defaultValue, values)")),Object(r.b)("td",{parentName:"tr",align:null},"Selección desplegable")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"color(title, defaultValue)")),Object(r.b)("td",{parentName:"tr",align:null},"Selector de color")),Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"boolean(title, defaultValue)")),Object(r.b)("td",{parentName:"tr",align:null},"Entrada booleana")))),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-js"},'const alertVolumeThreshold = alertInput.number("Volume threshold", 1000, 0, 10000000, 1);\n')),Object(r.b)("h3",{id:"disparar-alertas--alertfire"},"Disparar alertas — ",Object(r.b)("inlineCode",{parentName:"h3"},"alert.fire")),Object(r.b)("table",null,Object(r.b)("thead",{parentName:"table"},Object(r.b)("tr",{parentName:"thead"},Object(r.b)("th",{parentName:"tr",align:null},"Método"),Object(r.b)("th",{parentName:"tr",align:null},"Descripción"))),Object(r.b)("tbody",{parentName:"table"},Object(r.b)("tr",{parentName:"tbody"},Object(r.b)("td",{parentName:"tr",align:null},Object(r.b)("inlineCode",{parentName:"td"},"fire(title, message, date)")),Object(r.b)("td",{parentName:"tr",align:null},"Dispara una notificación de alerta")))),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},"Los tres parámetros son ",Object(r.b)("strong",{parentName:"li"},"obligatorios"),": una llamada a la que le falte ",Object(r.b)("inlineCode",{parentName:"li"},"title"),", ",Object(r.b)("inlineCode",{parentName:"li"},"message")," o ",Object(r.b)("inlineCode",{parentName:"li"},"date")," se omite (se escribe una advertencia en el registro)."),Object(r.b)("li",{parentName:"ul"},"Mantén el ",Object(r.b)("strong",{parentName:"li"},"título de la alerta constante"),", no generes títulos únicos. Cada título se dispara solo una vez por ejecución (máx. ",Object(r.b)("strong",{parentName:"li"},"20")," títulos por ejecución)."),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"date")," es el ",Object(r.b)("inlineCode",{parentName:"li"},"startTime")," de la vela a la que pertenece la señal: el mismo título vuelve a notificar solo cuando se dispara para una vela ",Object(r.b)("strong",{parentName:"li"},"más reciente"),". Las señales de velas anteriores al momento en que el usuario creó su alerta se ignoran (antispam).")),Object(r.b)("p",null,Object(r.b)("strong",{parentName:"p"},"Ejemplo:")),Object(r.b)("pre",null,Object(r.b)("code",{parentName:"pre",className:"language-js"},'if (candle.volume > alertVolumeThreshold) {\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n}\n')),Object(r.b)("h3",{id:"alertas-de-formas--plotshapealert"},"Alertas de formas — ",Object(r.b)("inlineCode",{parentName:"h3"},"plot.(...).alert(...)")),Object(r.b)("p",null,"Todas las formas geométricas (",Object(r.b)("inlineCode",{parentName:"p"},"box"),", ",Object(r.b)("inlineCode",{parentName:"p"},"square"),", ",Object(r.b)("inlineCode",{parentName:"p"},"diamond"),", ",Object(r.b)("inlineCode",{parentName:"p"},"triangle"),", ",Object(r.b)("inlineCode",{parentName:"p"},"circle"),", ",Object(r.b)("inlineCode",{parentName:"p"},"straightLine"),", ",Object(r.b)("inlineCode",{parentName:"p"},"horizontalLine"),", ",Object(r.b)("inlineCode",{parentName:"p"},"verticalLine"),", ",Object(r.b)("inlineCode",{parentName:"p"},"text"),") devuelven un manejador con un método ",Object(r.b)("inlineCode",{parentName:"p"},".alert()"),".\nLa alerta se dispara automáticamente con el ",Object(r.b)("inlineCode",{parentName:"p"},"date1")," de la forma, de modo que la lógica antispam funciona sin código adicional: es la forma recomendada para señales por vela."),Object(r.b)("p",null,"Dos formas:"),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"El callback recibe los datos de la forma (",Object(r.b)("inlineCode",{parentName:"p"},"date1"),", ",Object(r.b)("inlineCode",{parentName:"p"},"price1"),", ",Object(r.b)("inlineCode",{parentName:"p"},"date2"),", ",Object(r.b)("inlineCode",{parentName:"p"},"price2"),", ...)."),Object(r.b)("h3",{id:"alertas-de-series--plotseriesalert"},"Alertas de series — ",Object(r.b)("inlineCode",{parentName:"h3"},"plot.(...).alert(...)")),Object(r.b)("p",null,"Las series de datos (",Object(r.b)("inlineCode",{parentName:"p"},"lineSeries"),", ",Object(r.b)("inlineCode",{parentName:"p"},"barSeries"),", ",Object(r.b)("inlineCode",{parentName:"p"},"candleSeries"),", ",Object(r.b)("inlineCode",{parentName:"p"},"areaSeries"),", ",Object(r.b)("inlineCode",{parentName:"p"},"bandSeries"),") también devuelven el manejador ",Object(r.b)("inlineCode",{parentName:"p"},".alert()"),".\nEl callback recibe el ",Object(r.b)("strong",{parentName:"p"},"último punto de datos")," y la fecha de la última vela; la alerta se dispara con esa fecha."),Object(r.b)("ul",null,Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"lineSeries")," / ",Object(r.b)("inlineCode",{parentName:"li"},"barSeries")," / ",Object(r.b)("inlineCode",{parentName:"li"},"areaSeries"),": el callback recibe el último ",Object(r.b)("strong",{parentName:"li"},"valor")," (un número)"),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"candleSeries"),": el callback recibe la última vela ",Object(r.b)("inlineCode",{parentName:"li"},"{open, close, high, low}")),Object(r.b)("li",{parentName:"ul"},Object(r.b)("inlineCode",{parentName:"li"},"bandSeries"),": el callback recibe el último ",Object(r.b)("inlineCode",{parentName:"li"},"{upper, lower}"))),Object(r.b)("pre",null,Object(r.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(r.b)("p",null,"Una condición que sigue siendo verdadera notifica una vez por ",Object(r.b)("strong",{parentName:"p"},"vela nueva"),". Para señales únicas usa condiciones de tipo cruce (",Object(r.b)("inlineCode",{parentName:"p"},"ta.crossover"),")."),Object(r.b)("h3",{id:"ejemplo-completo"},"Ejemplo completo"),Object(r.b)("pre",null,Object(r.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(r.b)("h2",{id:"ejemplos-de-indicadores"},"Ejemplos de indicadores"),Object(r.b)("pre",null,Object(r.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(r.b)("pre",null,Object(r.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(r.b)("pre",null,Object(r.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(r.b)("pre",null,Object(r.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(r.b)("pre",null,Object(r.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(r.b)("p",null,'Order Book Pressure (bandas de desequilibrio de profundidad bid / ask alrededor del precio, como las superposiciones "Order Book Pressure" de los terminales de trading):'),Object(r.b)("pre",null,Object(r.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!==p&&p&&p===Object(p)&&Object.isExtensible(p)&&!Object.prototype.hasOwnProperty.call(p,"__filemeta")&&Object.defineProperty(p,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/components/es/Scripting.mdx"}}),p.isMDXComponent=!0}}]); //# sourceMappingURL=component---src-components-es-scripting-mdx-19b8381ea57674b7f365.js.map