Referencia de la API

Superficie pública de las clases de nivel superior: Chart, ChartWidget, ChartWidgetGrid y ChartGrid.

Chart

Renderizador sin interfaz. Tú pones la UI, te suscribes a los eventos y modificas el estado de forma imperativa.

Creación

new Chart(host: HTMLElement, options?: ChartOptions)

Datos

MétodoFunción
setData(data)Sustituye la serie completa.
appendBar(bar)Añade una barra nueva; se desplaza automáticamente si está activado.
appendBars(bars)Añade en lote; recalcula los indicadores una sola vez.
updateLastBar(bar)Modifica la barra en formación.
updateLastBarFromTick(tick)Fusiona un tick en la última barra.
getData()Lee la serie OHLC sin procesar.

Tipo de gráfico y tema

MétodoFunción
setChartType(type)Uno de los 18 tipos; consulta Tipos de gráfico.
setTheme(name)Cambia entre los temas integrados.
setTimeframe(tf)Cambia la temporalidad activa; reconecta el flujo en vivo.

Renderizador

MétodoPropósito
Opción renderer'canvas' (predeterminado), 'webgl' o 'auto' (WebGL solo con una GPU de hardware).
setRenderer(mode)Cambia en tiempo de ejecución. Devuelve lo que dibuja ahora: 'canvas' si no hay WebGL 2.
getRenderer()'canvas' o 'webgl'.

Qué dibuja la GPU, y las cifras: Rendimiento → Renderizador WebGL.

Indicadores

MétodoFunción
addIndicator(id, params?, position?)Añade un indicador superpuesto o en panel. Devuelve el id de la instancia.
updateIndicator(instanceId, params)Modifica un indicador activo.
removeIndicator(instanceId)Lo quita y libera sus recursos.

Ejes y escala

El eje de precio (franja derecha) y el eje de tiempo (franja inferior) admiten interacción directa con el puntero, con los gestos que los traders ya conocen:

GestoEfecto
Arrastrar el eje de precio arriba / abajoComprime / expande el rango vertical de precios (desactiva la escala automática).
Arrastrar el eje de tiempo a izquierda / derechaAcerca / aleja el eje de tiempo.
Doble clic en el eje de precioReactiva la escala automática.
Doble clic en el eje de tiempoAjusta todos los datos a la vista.

Zona horaria. Las etiquetas del eje de tiempo y la etiqueta de hora de la cruz siguen por defecto la zona local del navegador; cambia a un desfase UTC fijo (o vuelve a la hora local) desde la hoja de configuración o directamente:

chart.setTimezoneOffset(-300)  // EST (UTC-5), in minutes
chart.setTimezoneOffset(330)   // IST (UTC+5:30)
chart.setTimezoneOffset(null)  // back to browser-local

Los mismos efectos también están disponibles por código:

chart.setAutoScale(false)  // freeze the current price range
chart.setLogScale(true)    // switch to logarithmic price scale
chart.setInvertScale(true) // upside down (Alt+I in the widget)
chart.fitContent()         // zoom out to all data
chart.scrollToEnd()
chart.setVisibleRangePreset('3M')       // 1D 5D 1M 3M 6M YTD 1Y 5Y All
chart.goToTime(Date.UTC(2025, 0, 1))    // centre that bar (Alt+G in the widget)

Modos de la escala de precio. Además de normal y logarítmica, el eje puede recalcular sus etiquetas respecto a la primera barra visible: percentage muestra el cambio en %, indexedTo100 fija la base en 100. Los modos normal, porcentaje e indexado comparten la misma geometría lineal; solo cambian las etiquetas. Se configura desde el panel de configuración del gráfico o directamente:

chart.setScaleMode('percentage')   // axis labels: +12.34% from first visible bar
chart.setScaleMode('indexedTo100') // first visible bar reads as 100
chart.setScaleMode('logarithmic')
chart.getScaleMode()

Formatos de precio y de hora

Los precios pueden mostrarse a tu manera, o en fracciones de punto, como se cotizan los bonos y sus futuros (101'16 es 101 y 16/32). El formato llega a todo lo que muestra un precio en la escala de precio: eje, cruz, etiqueta del último precio, leyenda, información emergente, órdenes, alertas y etiquetas de los dibujos; el eje coloca sus marcas en fracciones enteras y roundPrice redondea a ellas. Los paneles de indicadores conservan sus propios números. Las horas también pueden mostrarse a tu manera; al formateador se le indica qué tipo de etiqueta es.

new Chart(host, { priceFormat: { denominator: 32 } })                    // 101'16
chart.setPriceFormat({ denominator: 32, subDenominator: 2 })            // 101'165: 16½ 32nds
chart.setPriceFormat((p) => '$' + p.toFixed(2))
chart.setPriceFormat(null)                                              // decimals again

chart.setTimeFormatter((time, { kind, timeZone }) =>
  // kind: 'date' (a daily bar), 'day' (a new day), 'time' (within a day), 'crosshair'
  new Intl.DateTimeFormat('en-GB', { timeZone: timeZone ?? undefined, hour: '2-digit', minute: '2-digit' }).format(time))

Comparar símbolos

El cambio porcentual de otro símbolo en la escala de precio (addCompareSymbol), o su precio en una escala propia, en un panel propio, o el diferencial o el ratio entre el cierre del gráfico y ese símbolo; estos últimos son indicadores (compareSymbol, spread), con leyenda, etiquetas de valor, alertas y diseños guardados como cualquier otro. Las barras del otro símbolo se alinean con las del gráfico por tiempo. El gráfico pide las barras que necesita; vuelve a dárselas tras un cambio de temporalidad.

chart.addCompareSymbol('eth', 'ETHUSDT', ethBars, '#7c4dff')   // percent change, on this scale
chart.addIndicator('compareSymbol', { symbol: 'ETHUSDT' }, 'bottom', { scale: 'left' })  // own scale
chart.addIndicator('spread', { symbol: 'ETHUSDT', mode: 'ratio' })                      // own pane

chart.on('symbolSeriesRequest', async ({ payload }) =>
  chart.setSymbolSeries(payload.symbol, await adapter.fetchHistory(payload.symbol, '1h', 1000)))
chart.getRequiredSymbols()                           // what to fetch again on a new interval
chart.setPaneScale(spreadId, { percent: true })     // a pane in percent of its first value

En ChartWidget, el botón de comparar del árbol de objetos pide un símbolo y luego cómo mostrarlo: cambio porcentual, escala propia, panel propio, diferencial o ratio.

Exportar datos

Las barras en CSV o JSON, con cada línea de indicador en su propia columna y con el nombre que le da la leyenda. ChartWidget tiene Exportar datos (CSV) en el menú del clic derecho del gráfico.

chart.exportAllData('csv', 'btc-1h.csv')                 // every bar loaded
chart.exportVisibleData('json', undefined, { indicators: false })
const text = chart.getExportText('csv', { range: 'visible' })
const { bars, columns } = chart.getExportData()          // columns: { name, values }[]

Perfil de volumen

Histograma horizontal del volumen negociado, agrupado por precio, sobre el rango visible. Desactivado por defecto; actívalo por código o desde la hoja de configuración del widget:

chart.setVolumeProfileVisible(true)
chart.setVolumeProfileConfig({
  buckets: 48,        // resolution of the histogram
  widthRatio: 0.18,   // % of chart width
  opacity: 0.32,
  highlightPoC: true, // mark the highest-volume bucket
})

Marcadores de swing (pivotes)

Marca los máximos y mínimos de swing fractales con pequeños triángulos (▼ sobre un pivote alto confirmado, ▲ bajo un pivote bajo). La fuerza indica cuántas barras deben quedar por debajo a cada lado. Actívalo desde la hoja de configuración o así:

chart.setPivotMarkersVisible(true)
chart.setPivotMarkersConfig({ left: 5, right: 5, showLabels: true })

// market-structure labels (HH / HL / LH / LL) instead of price
chart.setPivotMarkersConfig({ structureLabels: true })

// pure detection + classification are exported
import { findPivots, classifyPivots } from '@tradecanvas/core'
const pivots = findPivots(bars, 5, 5)        // [{ index, price, type }]
const structure = classifyPivots(pivots)     // adds label: 'HH'|'LH'|'HL'|'LL'

Sombreado de sesión (horario regular de negociación)

Atenúa las barras fuera de la sesión regular (preapertura, poscierre o la pausa nocturna) para que la sesión principal destaque. Por defecto usa el horario regular de la renta variable de EE. UU. (09:30–16:00, hora de Nueva York, con horario de verano incluido); configura la ventana en minutos del día y la zona horaria del mercado. Un símbolo cuya fuente de datos informa de sus sesiones las configura por sí mismo.

chart.setSessionShadingVisible(true)
chart.setSessionShadingConfig({
  startMinute: 9 * 60 + 30,     // 09:30
  endMinute: 16 * 60,           // 16:00 (end-exclusive; end < start wraps midnight)
  timeZone: 'America/New_York', // or tzOffsetMinutes: -300 for a fixed offset
})

Horario extendido. Al desactivarlo, las barras fuera del horario regular del símbolo (SymbolInfo.sessions en su timezone) salen del gráfico; se guardan aparte, también las barras en vivo y las páginas del historial, y vuelven al activarlo. Las barras de un día o más se quedan como están.

chart.setSymbolInfo({ symbol: 'AAPL', timezone: 'America/New_York', sessions: [{ start: '09:30', end: '16:00' }] })
chart.setExtendedHours(false)     // or new Chart(host, { extendedHours: false })
chart.isExtendedHoursVisible()

Niveles del periodo anterior (PDH / PDL / PDC)

Dibuja el máximo, el mínimo y el cierre del día (o la semana) anterior, más la apertura del periodo actual, como líneas horizontales con etiqueta: los niveles de soporte y resistencia que vigilan los traders intradía. Actívalo desde la hoja de configuración o directamente:

chart.setPeriodLevelsVisible(true)
chart.setPeriodLevelsPeriod('week')   // 'day' (PDH/PDL/PDC) | 'week' (PWH/PWL/PWC)

// pure computation is exported
import { computePeriodLevels } from '@tradecanvas/core'
const levels = computePeriodLevels(bars, 'day')  // [{ id, label, price }]

Perfil de mercado (TPO)

Un histograma de tiempo por precio: cada barra aporta un TPO a cada tramo de precio que tocó su rango, lo que revela el punto de control (el precio más concurrido) y el área de valor (≈70% de los TPO). Es distinto del perfil de volumen —pondera por tiempo, no por volumen— y se ancla a la izquierda para que ambos puedan mostrarse a la vez. Desactivado por defecto; actívalo desde la hoja de configuración o directamente:

chart.setMarketProfileVisible(true)
chart.setMarketProfileConfig({
  buckets: 48,
  widthRatio: 0.18,
  opacity: 0.32,
  valueAreaPct: 0.7,  // fraction of TPOs in the value area
  highlightPoC: true, // dashed line at the point of control
})

// split into one mini-profile per calendar-day session
chart.setMarketProfileConfig({ splitBySession: true })

// classic TPO letters per session (when zoomed in enough to be legible)
chart.setMarketProfileConfig({ splitBySession: true, letters: true })

// pure computation is exported too
import { computeMarketProfile, computeSessionProfiles } from '@tradecanvas/core'
const profile = computeMarketProfile(bars, priceMin, priceMax, { buckets: 48 })
const sessions = computeSessionProfiles(bars, priceMin, priceMax)  // per-day TPO

Táctil y móvil

GestoAcción
Arrastrar con 1 dedo (área del gráfico)Desplazar y mover la cruz
Pellizcar con 2 dedosZoom alrededor del punto medio
Mantener pulsado (~500 ms)Fija la información OHLC en la barra (el equivalente móvil de Alt + clic)
Arrastrar con 1 dedo dentro de la franja del eje de precio / tiempoEscala el eje correspondiente

Los cuadros modales (configuración, hoja de atajos, paleta de comandos, búsqueda de símbolos) pasan automáticamente a una hoja inferior con asa de arrastre y márgenes que respetan el área segura en pantallas de menos de 640 px.

Herramienta de medición

Mantén pulsado Shift y arrastra sobre el gráfico para medir barras × precio entre dos puntos: la capa muestra el Δ de precio (absoluto y %), el número de barras y el intervalo de tiempo. La capa desaparece en cuanto sueltas el ratón; no se guarda en el estado persistido.

Eventos

Todos los eventos están tipados mediante ChartEventMap:

chart.on('orderPlace', e => /* OrderPlacePayload */)
chart.on('orderModify', e => /* OrderModifyPayload */)
chart.on('signalMarkerAdd', e => /* { marker } */)
chart.on('tradeZoneAdd', e => /* { zone } */)
chart.on('dataUpdate', e => /* { length } */)
chart.on('ordersChange', e => /* { orders } */)
chart.on('positionsChange', e => /* { positions } */)
chart.on('executionFill', e => /* { side, price, quantity, reason, pnl } */)
chart.on('chartContextMenu', e => /* { area, x, y, price, time } */)
chart.on('stateChange', () => /* pueden haber cambiado los dibujos, indicadores, alertas, el tipo de gráfico o el tema */)
chart.on('paneChange', e => /* { instanceId, change: 'collapsed' | 'maximized' | 'order' } */)
chart.on('chartTypeChange', e => /* { type, previous } */)
chart.on('symbolChange', e => /* { symbol, previous } */)
chart.on('timeframeChange', e => /* { timeframe, previous } */)
chart.on('historyChange', e => /* { canUndo, canRedo } */)
chart.on('drawingSelect', e => /* { ids, primary } */)
chart.on('rendererChange', e => /* { renderer: 'canvas' | 'webgl', reason?: 'unsupported' | 'contextLost' } */)

Deshacer tus propios cambios

recordUndo pone un cambio tuyo en el historial de deshacer del gráfico, junto con sus dibujos e indicadores: Ctrl/Cmd+Z llama a undo y rehacer llama a redo. Los cambios sobre el mismo subject hechos seguidos cuentan como un solo paso. ChartWidget registra así su configuración y su tipo de gráfico.

const before = panel.color
panel.color = 'red'
chart.recordUndo({ subject: 'panel-color', undo: () => (panel.color = before), redo: () => (panel.color = 'red') })

Teclado y lectores de pantalla

Un gráfico con el foco se desplaza con las flechas (Mayús para diez barras), hace zoom con ↑/↓ o +/− y va al principio y al final con Inicio y Fin. Para los lectores de pantalla es una aplicación con un resumen (símbolo, tipo, temporalidad, último precio); cuando las teclas mueven la vista, dice lo que hay en pantalla, y la coma y el punto leen las barras una a una. a11y.labels lo pone en tu idioma; a11y: false lo quita. scrollBars(n) y selectDrawing(id) hacen desde el código lo que hacen las teclas y un clic.

new Chart(host, { a11y: { labels: { role: 'gráfico', summary: '{what}. Último precio {close}.' } } })

Los precios que vienen del puntero se pueden ajustar a la cuadrícula del mercado con chart.roundPrice(price): a un múltiplo del minTick del símbolo o, si no lo tiene, a su precisión. Los menús y el ticket de orden de ChartWidget lo hacen.

ChartWidget

Envuelve Chart en una interfaz completa. La misma instancia está disponible en widget.chart.

import { ChartWidget } from '@tradecanvas/chart/widget'

const widget = new ChartWidget(host, {
  symbol: 'BTCUSDT',
  timeframe: '5m',
  theme: 'dark',
  adapter: new BinanceAdapter(),
  historyLimit: 500,
  trading: true,
  features: { drawings: true, indicators: true },
  onReady: (chart) => { /* ... */ },
})

widget.chart.setData(...)
widget.destroy()

Atajos de teclado del widget

AtajoAcción
Ctrl / ⌘ + KPaleta de comandos (indicadores, tipos de gráfico, dibujos…)
Ctrl / ⌘ + PBúsqueda de símbolos: selector difuso sobre la lista de símbolos configurada
Ctrl / ⌘ + SGuarda el diseño (pide un nombre la primera vez)
0–9Escribe una temporalidad (5, 15m, 1h, 1D) y pulsa Enter (intervalTyping: false lo desactiva)
Alt + T / H / J / V / C / FLínea de tendencia, línea horizontal, rayo horizontal, línea vertical, línea en cruz, retroceso de Fibonacci
?Muestra la hoja de atajos de teclado
Alt + clic en el gráficoFija la información OHLC en la barra bajo el cursor (muestra la diferencia con la cruz en vivo)
EscDesfija la información / cancela el dibujo
Clic en el símbolo de la barra de herramientasAbre el cuadro de búsqueda de símbolos
Clic en reproducir en la barra de herramientasAbre el control de repetición de barras (reproducir/avanzar/buscar/velocidad)

Actualiza el catálogo de búsqueda en tiempo de ejecución con widget.setSymbols(['BTCUSDT', 'ETHUSDT', …]).

Ventana de datos

Un panel flotante con los valores exactos de O/H/L/C/V, el cambio de la barra y el valor de cada indicador activo en la barra bajo el cursor; se actualiza en vivo al mover la cruz. Actívalo desde la paleta de comandos (Ctrl/⌘ K → "Mostrar/ocultar ventana de datos").

Vista compartible (enlaces profundos)

Codifica la vista completa —símbolo, temporalidad, tipo de gráfico, escala de precio, indicadores (con sus parámetros) y dibujos— en una cadena compacta y apta para URL, para crear enlaces profundos. Con shareUrl: true el widget restaura un hash #tcw=… al cargar, y la acción "Compartir vista" de la paleta de comandos copia un enlace al portapapeles.

const widget = new ChartWidget(host, { shareUrl: true })

const token = widget.exportState()      // portable string
await widget.importState(token)         // restore a view
await widget.copyShareLink()            // copy "<url>#tcw=<token>"

Diseños con nombre

El botón de diseño de la barra de herramientas guarda el gráfico con un nombre: símbolo, temporalidad, escala de precio, tipo de gráfico, indicadores, dibujos y alertas (no el tema, que sigue siendo el de quien mira). Abre, renombra y elimina diseños desde su menú; el diseño abierto se guarda solo a medida que cambia, y Ctrl/⌘ S lo guarda. Los diseños viven en el localStorage de este navegador salvo que indiques un storage: cuatro llamadas, y cada una puede devolver una promesa.

import { ChartWidget, type LayoutStorage } from '@tradecanvas/chart/widget'

const server: LayoutStorage = {
  list: () => api.get('/layouts'),              // [{ id, name, symbol, timeframe, updatedAt }]
  load: (id) => api.get(`/layouts/${id}`),     // { ...summary, content } o null
  save: (layout) => api.put(`/layouts/${layout.id}`, layout),
  remove: (id) => api.delete(`/layouts/${id}`),
}

const widget = new ChartWidget(host, {
  layouts: { storage: server, autoSave: true, openLast: true },  // o false para ninguno
})

const layouts = widget.getLayoutSession()!
await layouts.saveAs('Swing BTC')
await layouts.open(id)
layouts.current()          // { id, name, … } o null
layouts.setAutoSave(false)

// Solo el contenido, para guardarlo donde quieras
const json = widget.getLayoutContent()
await widget.applyLayoutContent(json)

localStorageLayouts(prefix) y memoryLayouts() son los dos almacenamientos incluidos. El contenido guardado se lee de forma defensiva: un diseño que no se puede interpretar se rechaza, en lugar de aplicarse a medias. Cada diseño registra su kind ('chart' o 'grid'), así que un widget y una cuadrícula pueden compartir un mismo almacenamiento y cada uno lista solo los suyos. Guardar, abrir y el guardado automático se ejecutan de uno en uno, así que un guardado nunca acaba en un diseño abierto después de él.

Diseños por símbolo

Por separado, guarda automáticamente en localStorage, por símbolo, los indicadores, dibujos, alertas y el tipo de gráfico:

new ChartWidget(host, {
  symbol: 'BTCUSDT',
  symbols: ['BTCUSDT', 'ETHUSDT', 'SOLUSDT'],
  adapter: new BinanceAdapter(),
  persistLayouts: true,  // or { keyPrefix: 'myapp:', debounceMs: 2000 }
})

// Reset a single symbol's layout
widget.clearSavedLayout('BTCUSDT')

Los diseños se guardan al cambiar de símbolo y al destruir el widget, así que no se pierde nada cuando el usuario sale de la página.

Importación de datos con arrastrar y soltar

Suelta un archivo CSV o JSON sobre el gráfico para cargarlo al instante. Activado por defecto; desactívalo con dragDropImport: false. El analizador reconoce las disposiciones de columnas habituales (time, open, high, low, close, volume), las marcas de tiempo ISO 8601 y los segundos/ms de Unix.

// Programmatic use
import { parseOHLCV } from '@tradecanvas/chart'

const { data, rowCount, skipped } = parseOHLCV(csvText)
chart.setData(data)

Remuestreo de temporalidades

Pasa al widget tu serie de mayor resolución con widget.setData() y los botones de temporalidad de la barra de herramientas la agregan en el cliente: un solo conjunto de datos alimenta todas las resoluciones, sin volver a descargar nada. Está activo siempre que no haya un adaptador en vivo conectado; desactívalo con resampleTimeframes: false. Los tramos semanales empiezan el lunes por defecto (weekStartsOn: 0 para el domingo).

const widget = new ChartWidget(host, {
  symbol: 'BTCUSDT',
  timeframe: '1h',
  timeframes: ['5m', '15m', '1h', '4h', '1d', '1w'],
})
widget.setData(oneMinuteBars)   // base series; clicking 4h/1d/1w resamples it

// Or use the pure function directly
import { resampleOHLCV, inferTimeframeMs } from '@tradecanvas/chart'

const hourly = resampleOHLCV(oneMinuteBars, '1h')   // OHLC merged, volume summed
const fourHour = resampleOHLCV(oneMinuteBars, '4h', { weekStartsOn: 1 })

Agrupación según el calendario: las temporalidades intradía y diarias se alinean con los límites de la época UTC, las semanas con el inicio de semana configurado y los meses / trimestres / años con los límites del calendario. Las barras de entrada nunca se modifican.

Listas de seguimiento

Un panel a la derecha con listas de símbolos; cada fila lleva el último precio, el % de cambio y un minigráfico. Las listas se cambian, crean, renombran y borran desde su menú; los símbolos se añaden desde la búsqueda de símbolos (+), se quitan y se reordenan arrastrando o con Alt+↑/↓. Las filas toman las cotizaciones del subscribeQuotes del adaptador, de una fuente de cotizaciones tuya o de lo que tú envíes.

const widget = new ChartWidget(host, {
  symbol: 'BTCUSDT',
  adapter: new BinanceAdapter(),               // its quotes fill the rows
  watchlist: {
    lists: [
      { id: 'majors', name: 'Majors', symbols: ['BTCUSDT', 'ETHUSDT'] },
      { id: 'alts', name: 'Alts', symbols: ['SOLUSDT', 'ADAUSDT'] },
    ],
    persist: true,                             // kept in this browser
    onChange: (lists, active) => save(lists),  // or keep them yourself
  },
})

widget.addToWatchlist('BNBUSDT', 'alts')
widget.setActiveWatchlist('alts')
widget.setQuotes([{ symbol: 'AAPL', last: 190.2, prevClose: 188.1 }])   // from your own feed
widget.getQuote('AAPL')

watchlist: true muestra una sola lista de symbols, como antes; setWatchlistEntry sigue enviando el precio, la variación y el minigráfico de una fila.

Información del símbolo

Un panel que se abre con el botón ⓘ de la barra de herramientas (o desde la paleta de comandos): los nombres del símbolo, el último precio y su variación, el estado del mercado con la cuenta atrás hasta la próxima apertura o cierre, la apertura del día, el rango, el volumen, el cierre anterior, compra y venta, el tamaño del tick, la moneda, la zona y el horario de negociación, y noticias. La barra de estado indica cuándo el mercado está cerrado.

new ChartWidget(host, {
  symbol: 'AAPL',
  news: (symbol, limit) => api.headlines(symbol, limit),   // or the adapter's fetchNews
})
widget.toggleSymbolInfo(true)

Navegación, deshacer y dirección

Los botones sobre el gráfico (alejar y acercar, desplazarse hacia atrás y hacia delante, que siguen mientras los mantienes pulsados, y restablecer) aparecen mientras el ratón está encima (navigation: false los quita). Los cambios de configuración y de tipo de gráfico se deshacen con Ctrl/Cmd+Z, junto con los dibujos y los indicadores. En árabe, hebreo, persa o urdu el widget se refleja (dir: 'auto'; o 'rtl' / 'ltr'); el gráfico mantiene el tiempo de izquierda a derecha.

Herramientas de dibujo favoritas

Fija las herramientas de dibujo que más usas en una franja en la parte superior de la barra lateral. Haz clic derecho en cualquier herramienta (en el menú de su grupo o en la propia franja) para fijarla o desfijarla; la selección se guarda en localStorage. Define los favoritos iniciales con drawingFavorites:

new ChartWidget(host, {
  drawingFavorites: ['trendLine', 'horizontalLine', 'fibRetracement', 'rectangle'],
})

Estilo de dibujo y plantillas

El botón de paleta de la barra lateral de dibujo abre un menú de estilo: elige el color, el grosor y el estilo de línea del próximo dibujo (y del seleccionado), y guarda plantillas con nombre en localStorage para reutilizarlas con un clic. Equivalentes por código:

chart.setDrawingStyle({ color: '#e8505b', lineWidth: 2, lineStyle: 'dashed' })
chart.getDrawingStyle()
chart.setSelectedDrawingStyle({ color: '#1fa874' })  // restyle the selected drawing

Árbol de objetos

El botón de capas de la barra de herramientas abre un panel con el árbol de objetos, que lista todos los indicadores y dibujos activos. Los indicadores se pueden quitar; cada dibujo se puede mostrar / ocultar, bloquear / desbloquear, configurar y eliminar, y los grupos aparecen con sus dibujos debajo. Activado por defecto; desactívalo con objectTree: false. Los controles de dibujo corresponden a:

chart.getDrawings()                 // DrawingState[] (id, type, visible, locked)
chart.setDrawingVisible(id, false)  // hide a single drawing
chart.setDrawingLocked(id, true)    // lock it from edits
chart.removeDrawing(id)
chart.groupDrawings(ids, 'Weekly levels')  // se ocultan, bloquean y seleccionan juntos
chart.renameDrawingGroup(groupId, 'Old highs')
chart.getActiveIndicators()         // active indicator instances
chart.updateIndicator(instanceId, { period: 50 })  // re-tune params live
chart.removeIndicator(instanceId)

Configuración y menú del dibujo

Haz doble clic en un dibujo, o usa su engranaje en el árbol de objetos, para abrir su configuración: el estilo, la configuración propia de la herramienta (niveles de Fibonacci, extensiones, etiquetas…) y sus puntos en la zona horaria del gráfico. Haz clic derecho en un dibujo para ver su menú: configuración, una alerta en su línea, orden, agrupar, bloquear, ocultar, duplicar y eliminar. La barra lateral también tiene un borrador, una herramienta de zoom y un imán que puede estar desactivado, débil o fuerte. Consulta Herramientas de dibujo para ver la API que hay debajo.

El botón de engranaje de cada fila de indicador abre un cuadro de configuración que examina los parámetros del indicador (números, interruptores, colores) y aplica los cambios en vivo mediante updateIndicator: no hace falta quitarlo y volver a añadirlo para cambiar un periodo o un color.

La sección Comparar del árbol de objetos superpone otros símbolos como líneas normalizadas. Con un adaptador en vivo, el botón + abre el selector de símbolos, descarga el historial de ese símbolo mediante adapter.fetchHistory y lo añade en modo porcentaje (para que símbolos con precios muy distintos compartan un eje). Las comparaciones se vuelven a descargar automáticamente al cambiar de temporalidad. Equivalentes por código:

widget.addCompareSymbol('ETHUSDT')   // fetches + overlays (needs an adapter)

// or drive the chart directly with your own data
chart.addCompareSymbol('ETHUSDT', 'ETH', ethBars, '#627eea')
chart.setCompareMode('percent')      // 'percent' | 'absolute'
chart.removeCompareSymbol('ETHUSDT')

Alertas de precio

Además de un nivel, una alerta puede comparar una línea con otra (el precio cruzando una media móvil, el MACD cruzando su señal), saltar con un movimiento de cierto porcentaje en cierto número de barras (de 2 a 500), mirar solo las barras cerradas (sin saltar por una mecha que vuelve) y vencer. El panel de alertas del widget tiene todo esto; desde código son el último argumento de addAlert. Las alertas se comprueban con cada precio, venga de setCurrentPrice o de una fuente conectada, junto con las líneas que vigilan:

const ema = chart.addIndicator('ema', { period: 50 })
const rsi = chart.addIndicator('rsi')
chart.addAlert(NaN, 'crossingUp', 'above the 50 EMA', 'price', undefined, { target: `${ema}:value` })
chart.addAlert(NaN, 'movesUp', 'pump', 'price', undefined, { percent: 5, bars: 12 })
chart.addAlert(70, 'greaterThan', 'RSI closed above 70', `${rsi}:value`, 'RSI', { onBarClose: true })
chart.addAlert(64_000, 'crossing', 'today only', 'price', undefined, { expiresAt: Date.now() + 86_400_000 })

chart.on('alertExpired', (e) => e.payload)   // it reached its time without firing
chart.on('alertTriggered', (e) => e.payload)  // { id, condition, channel, target?, percent?, bars?, … }

La campana de la barra de herramientas abre un panel flotante para añadir, listar y eliminar alertas de precio; cuando una se activa aparece un aviso. Las líneas de alerta también se pueden arrastrar: toma una en el gráfico y deslízala para cambiar su precio (al mover una alerta se vuelve a armar). Activado por defecto; desactívalo con alerts: false. Contrólalo por código con la API de Chart y los eventos de alerta tipados:

// Add from code (condition: 'crossing' | 'crossingUp' | 'crossingDown'
//                          | 'greaterThan' | 'lessThan')
const id = chart.addAlert(64200, 'crossingUp', 'breakout')
chart.removeAlert(id)
chart.getAlerts()      // PriceAlert[]
chart.saveAlerts('tcw:alerts:BTCUSDT')   // localStorage persistence
chart.loadAlerts('tcw:alerts:BTCUSDT')

// React to triggers
chart.on('alertTriggered', (e) => {
  console.log('hit', e.payload.price, e.payload.message)
})
// also: 'alertAdd' / 'alertRemove' / 'alertUpdate' (fired on drag)

// Indicator alerts: bind to an indicator line via channel '<instanceId>:<key>'.
// In the widget, the alerts panel's source dropdown lists every active line.
const ema = chart.addIndicator('rsi')
chart.addAlert(70, 'crossingUp', 'RSI overbought', `${ema}:rsi`, 'RSI')

Activa un sonido y/o una notificación de escritorio cuando salte una alerta (ambos desactivados por defecto). sound: true reproduce un pitido integrado; pasa una URL para usar uno propio. desktop: true usa la Notification API y pide permiso la primera vez.

new ChartWidget(host, {
  alertNotifications: { sound: true, desktop: true },
})

Tus propios botones y entradas de menú

Añade botones a la barra de herramientas (un icono integrado o un elemento tuyo, texto, un interruptor) y entradas a los menús del clic derecho del gráfico, después de las del propio widget.

const news = widget.addToolbarButton({
  id: 'news',
  label: 'News',
  icon: 'bell',            // o un elemento <svg>; o text: 'News'
  side: 'right',           // 'left' se coloca junto a los controles del gráfico
  toggle: true,
  onClick: () => news?.setActive(togglePanel()),
})
news?.setText('3')
news?.remove()

new ChartWidget(host, {
  chartMenuItems: ({ area, price, time }) => area === 'plot' && price !== undefined
    ? [{ label: `Copy ${price.toFixed(2)}`, icon: 'check', onSelect: () => copy(price) }]
    : [],
})

ChartWidgetGrid

Varios widgets de gráfico uno junto a otro, cada uno con su propio símbolo, temporalidad, indicadores y dibujos. Una barra encima de ellos elige la disposición, vincula los gráficos y guarda toda la cuadrícula como un diseño con nombre. El último gráfico pulsado es el activo (con contorno).

import { ChartWidgetGrid } from '@tradecanvas/chart/widget'

const grid = new ChartWidgetGrid(host, {
  layout: '2x2',                                   // '1x1' '1x2' '2x1' '2x2' '1x3' '3x1' '2x3' '3x2'
  widget: { timeframe: '1h' },                    // todos los gráficos
  adapter: () => new BinanceAdapter(),            // uno por gráfico: un adaptador mantiene un único flujo
  cells: [{ symbol: 'BTCUSDT' }, { symbol: 'ETHUSDT' }, { symbol: 'SOLUSDT' }, { symbol: 'BNBUSDT' }],
  sync: { crosshair: true, time: false, symbol: false, interval: false, drawings: false, replay: false },
})

grid.setLayout('1x2')
grid.setSync({ interval: true })   // alinea los demás con el gráfico activo
grid.getActiveWidget().getChart()
grid.getLayoutSession()?.saveAs('Majors')

// Cada gráfico según se crea (al inicio y al crecer la cuadrícula)
new ChartWidgetGrid(host, {
  onChartAdd: (widget, index) => widget.getChart().addIndicator('ema', { period: 21 }),
})

La sincronización de la cruz muestra en todos los gráficos la hora bajo el puntero; la del tiempo desplaza y amplía los demás junto con el gráfico que se está usando; los dibujos se copian a los gráficos que muestran el mismo símbolo (al activarla se juntan sus dibujos, sin perder ninguno); la de la repetición lleva a los demás a la misma hora que el gráfico que se está repitiendo (un gráfico con barras más largas que los pasos de la repetición muestra entera la barra que contiene esa hora). Los gráficos que sobran cuando la cuadrícula se reduce se guardan aparte, se conservan en el diseño guardado y vuelven tal como estaban cuando crece de nuevo; un gráfico totalmente nuevo se abre con el símbolo y la temporalidad del gráfico activo cuando estos están sincronizados.

ChartGrid

Disposiciones de varios gráficos sin interfaz (sin barra de herramientas) sincronizados; consulta ChartWidgetGrid para la interfaz completa.

import { ChartGrid } from '@tradecanvas/chart'

const grid = new ChartGrid(host, { layout: '2x2', theme: 'dark' })
// Un adaptador por gráfico: un adaptador mantiene un único flujo
await grid.connectAll(() => new BinanceAdapter(), ['BTCUSDT','ETHUSDT','SOLUSDT','BNBUSDT'], '5m')
grid.setLayout('1x2')

Disposiciones: '1x1', '1x2', '2x1', '2x2', '1x3', '3x1', '2x3', '3x2'.