Capa de trading
Muestra posiciones, órdenes, marcadores de señales y zonas de operación directamente en el gráfico. Diseñada para integrarse tanto en flujos de trading manual como algorítmico.
Desactivar el trading
La capa de trading está activada por defecto; el menú de órdenes del clic derecho no (desde la 1.3).
// Drop the entire trading subsystem (no orders, no positions, no overlay)
new Chart(host, { features: { trading: false } })
// Opt in to the right-click "Buy / Sell here" order menu
new Chart(host, { features: { tradingContextMenu: true } })
new ChartWidget(host, { chartOptions: { features: { tradingContextMenu: true } } }) Sin el menú, el clic derecho nativo del navegador funciona en el gráfico como cabe esperar.
Posiciones
chart.addPosition({
id: 'pos-1',
side: 'long',
entry: 65_200,
quantity: 0.5,
closedQuantity: 0.1, // partial-close band on the left edge
stopLoss: 64_800,
takeProfit: 66_000,
}) Órdenes
chart.addOrder({
id: 'ord-1',
side: 'sell',
type: 'limit',
price: 65_500,
quantity: 0.25,
}) Arrastra la línea de precio para modificarla; suscríbete con chart.on('orderModify', ...).
Ejecución en vivo (conecta un adaptador)
Por defecto, el gráfico emite intenciones de orden/posición
(orderPlace, orderModify, orderCancel, positionModify, positionClose) para tu backend; nunca
opera por sí mismo. Si conectas un ExecutionAdapter, el gráfico
envía esas intenciones al adaptador y muestra las órdenes/posiciones
definitivas que este le devuelve (el adaptador es la única fuente de verdad).
import { PaperExecutionAdapter } from '@tradecanvas/chart'
chart.connectExecution(new PaperExecutionAdapter({ markPrice: 64_000 }))
chart.on('executionError', (e) => toast(e.payload.message))
// chart.disconnectExecution() Implementa ExecutionAdapter (es el equivalente de DataAdapter) para conectar un bróker / OMS real: placeOrder, modifyOrder, cancelOrder, modifyPosition, closePosition, más los eventos orders / positions / fill / error. PaperExecutionAdapter es un entorno de pruebas
con ejecuciones virtuales para demos y tests.
Actuar sobre órdenes y posiciones desde el gráfico
Las líneas de órdenes y de posiciones llevan pequeños botones en su extremo
derecho: × cancela una orden o cierra una posición, ⇅ invierte una posición, y una × en una línea de stop-loss o
take-profit la quita. Generan las mismas intenciones que la API
(orderCancel, positionClose, positionReverse, positionModify con null), así que un adaptador conectado
actúa sobre ellas y una aplicación sin adaptador recibe los eventos. Un botón actúa
cuando se suelta sobre él: una pulsación que se desliza fuera no hace nada. Desactiva
cualquiera de ellos con lineButtons en setTradingConfig.
chart.setTradingConfig({ lineButtons: { reverse: false } }) // keep cancel, close and remove-stops
chart.cancelOrderIntent('ord-1')
chart.closePositionIntent('pos-1')
chart.reversePositionIntent('pos-1') // close, then the same size the other way
chart.modifyPositionIntent('pos-1', { stopLoss: null }) // null removes the stop Un adaptador que pueda invertir en un solo paso implementa reversePosition; si no lo hace, el gráfico cierra la posición y envía
una orden de mercado en sentido contrario. Las órdenes aceptan un stopLoss, un takeProfit y un timeInForce ('gtc' o 'day') que se trasladan a la posición que abren.
Para autores de adaptadores: en PositionModifyIntent, stopLoss: null (o takeProfit: null) significa quitarlo,
mientras que un campo ausente significa dejarlo como está. Un código escrito como intent.stopLoss ?? position.stopLoss mantendría un stop que el usuario
ha quitado.
Ejecuciones en el gráfico
Cada ejecución aparece como una pequeña marca en su barra: rellena donde abrió una
posición y hueca donde la cerró. El gráfico registra las ejecuciones que informa el
adaptador y emite executionFill con el motivo ('order', 'close', 'reverse', 'stopLoss', 'takeProfit') y la ganancia o pérdida realizada.
chart.on('executionFill', (e) => {
const { side, price, quantity, reason, pnl } = e.payload
})
chart.addFill({ orderId: 'o-7', side: 'buy', price: 64_150, quantity: 1, time: Date.now() })
chart.getFills() // the latest 1000
chart.getRealisedPnl() // every fill's P&L since the last clearFills
chart.clearFills()
chart.setTradingConfig({ fillMarks: false }) // no marks Menús del clic derecho y el “+” junto al eje de precio
Un clic derecho en el gráfico emite chartContextMenu con la parte en la
que se hizo clic ('plot', 'pane', 'priceAxis' o 'timeAxis') y el precio y la hora en ese punto. Con features.priceAxisAddButton, un “+” sigue a la cruz a lo largo del eje
de precio; al pulsarlo se emite priceAxisAdd con su precio.
const chart = new Chart(host, { features: { priceAxisAddButton: true } })
chart.on('chartContextMenu', (e) => {
const { area, x, y, price, time } = e.payload
openMyMenu(x, y)
})
chart.on('priceAxisAdd', (e) => openMyMenu(e.payload.x, e.payload.y, e.payload.price)) ChartWidget construye sus menús sobre estos eventos. Haz clic derecho en el área del
gráfico para una alerta, una compra y una venta a ese precio (una orden límite en el
lado del mercado donde quedaría a la espera, una stop en el otro), un ticket de
orden, una línea horizontal, restablecer la vista y los dibujos; en el eje de precio,
para cambiar la escala; en el eje de tiempo, para restablecer la vista e ir a una
fecha. Añade tus propias entradas con chartMenuItems (consulta la referencia de la API).
Ticket de orden y panel de cuenta (ChartWidget)
El botón de recibo del widget abre un panel de cuenta bajo el gráfico: las
posiciones abiertas con su ganancia o pérdida, las órdenes pendientes y las
ejecuciones hasta el momento con el P&L realizado. Cada fila permite cerrar,
invertir o cancelar. Nueva orden abre un ticket de orden: compra o
venta, a mercado, límite o stop, cantidad, precio, un stop-loss y un take-profit
opcionales, y la vigencia. Revisa la orden mientras la rellenas (una compra límite
va por debajo del mercado, un stop-loss en el lado perdedor de la entrada…) y
muestra la relación beneficio:riesgo. Al enviarla se emite una intención orderPlace.
const widget = new ChartWidget(host, {
trading: true, // default
accountPanel: true, // default when trading is on
})
widget.getChart().connectExecution(new PaperExecutionAdapter({ markPrice: 64_000 }))
widget.toggleAccountPanel(true)
// The panel follows ordersChange, positionsChange, executionFill and each tick. Las marcas de ejecución pertenecen al símbolo del gráfico: al cambiar de símbolo en el widget, el siguiente empieza sin ninguna.
Crear órdenes arrastrando
Crea una línea de orden arrastrable, llévala a un precio y confirma: el tipo de
orden (límite o stop) se deduce de dónde la sueltas respecto al precio actual.
Combínalo con connectExecution para que un borrador confirmado se
ejecute al instante.
chart.startOrderDraft('buy') // draggable line at the latest close
chart.confirmOrderDraft() // emits orderPlace -> a connected adapter fills it
chart.cancelOrderDraft() Órdenes bracket (arrastrar para enviar)
Crea un bracket arrastrable —entrada más zonas de stop-loss y take-profit— y
arrastra las tres líneas para ajustar la entrada, el riesgo y el beneficio.
Confirma con Enter (o con el botón Enviar) y cancela con Esc. En el widget, las flechas verde/roja de la barra de
herramientas inician un bracket largo/corto. El gráfico emite un único evento bracketPlace para que tu backend actúe; nunca envía órdenes por sí
mismo.
chart.startBracket('buy') // entry defaults to the latest close
chart.startBracket('sell', 64_800) // or pin the entry price
chart.on('bracketPlace', (e) => {
const { side, entry, stopLoss, takeProfit, riskReward } = e.payload
// submit to your OMS, then reflect fills back via chart.setOrders/setPositions
})
chart.confirmBracket() // same as Enter
chart.cancelBracket() // same as Esc Escalera de profundidad (clic para operar)
Una escalera opcional de profundidad de mercado muestra el libro de órdenes
como filas de precio con columnas de tamaño de compra/venta: haz clic en una
celda de venta para comprar, o en una de compra para vender, a ese precio.
Actívala con depthLadder: true y aliméntala con el libro mediante widget.setDepth; los clics emiten intenciones orderPlace para tu OMS (el gráfico nunca opera por sí mismo). Los
mismos datos alimentan también la capa de profundidad sobre el gráfico.
const widget = new ChartWidget(host, { depthLadder: true })
widget.setDepth({
bids: [{ price: 64_190, volume: 3.1 }, { price: 64_185, volume: 5.4 }],
asks: [{ price: 64_205, volume: 2.0 }, { price: 64_210, volume: 8.7 }],
})
widget.getChart().on('orderPlace', (e) => {
// { side, type: 'limit', price } — submit to your backend
}) Mapa de calor de liquidez
Acumula instantáneas del libro de órdenes en un mapa de calor detrás de las
velas: cada instantánea es una franja vertical en la que el tamaño en espera se
ilumina por nivel de precio (compras en verde, ventas en rojo). Los muros de
liquidez que persisten en el tiempo destacan. Actívalo desde la hoja de
configuración (o con chart.setDepthHeatmapVisible); widget.setDepth registra una instantánea en cada actualización del
libro.
chart.setDepthHeatmapVisible(true)
chart.setDepthHeatmapConfig({ opacity: 0.7, capacity: 240 })
// each book update both draws the overlay/ladder and records a heatmap column
widget.setDepth(orderBook)
// low-level: chart.pushDepthSnapshot(orderBook) · chart.clearDepthHeatmap() Marcadores de señales
Las integraciones con bots o de trading por señales pueden colocar flechas direccionales sobre la capa.
chart.addSignalMarker({
id: 'sig-12',
time: bar.time,
price: bar.close,
direction: 'long',
confidence: 0.86,
source: 'momentum-bot',
label: 'EMA cross',
})
// A marker under the pointer, and a click on one
chart.on('signalMarkerHover', (e) => showNote(e.payload.marker, e.payload.x, e.payload.y)) // marker null: off it
chart.on('signalMarkerClick', (e) => openSignal(e.payload.marker)) ChartWidget muestra una nota junto al marcador que queda bajo el puntero: su etiqueta y su origen, el lado, el precio, la confianza y la hora.
Zonas de operación
Visualiza rectángulos de entrada → salida coloreados según el P&L y con distintivos de dirección.
chart.addTradeZone({
id: 'tz-1',
side: 'long',
entryTime: openedAt,
exitTime: closedAt,
entryPrice: 65_100,
exitPrice: 65_800,
status: 'closed',
}) Tokens de la etiqueta de posición
Personaliza la etiqueta de cada posición en el gráfico. positionLabel acepta una cadena de plantilla o una función que devuelva una cadena.
new ChartWidget(host, {
trading: true,
positionLabel: '{side} {qty} @ {entry} · {pnlSign}{pnlPct}%',
}) Tokens disponibles: {side}, {qty}, {openQty}, {closedQty}, {entry}, {price}, {pnl}, {pnlPct}, {pnlSign}.
Puntos del degradado de P&L
new ChartWidget(host, {
trading: true,
pnlThresholds: [
{ pnlPct: -0.02, color: '#ef4444' },
{ pnlPct: 0, color: '#94a3b8' },
{ pnlPct: 0.02, color: '#10b981' },
],
})