Exciting Update: Version 1.0.0 is now available, introducing high-performance technical indicators and custom drawing tools. Read more
Version: 1.0.0

Getting started

Requirements

Backtestx Charts™ is a client-side rendering library designed for high-performance financial graphics, operating within browsers and lightweight web runtimes.

The library code targets the ES2020 language specification. Therefore, the browsers you work with should support this language revision. Consider the following table to ensure the browser compatibility.

Browser Minimum Version
Chrome 87
Firefox 78
Safari 14
Edge 88
Opera 73

If you need to support previous browser versions, you can transpile the library bundle scripts using tools such as Babel. If you encounter any bugs, open a technical ticket in our GitHub issues.

Installation

The library is distributed as a series of optimized bundle modules. Include the core scripting bundles in your HTML file:

HTML
<!-- Charting Library Loader Bundles -->
<script src="./src/charting_library/bundles/0.d72fc8a0.js"></script>
<script src="./src/charting_library/bundles/29.59c1212b.js"></script>
<script src="./src/charting_library/bundles/37.3a5c00b5.js"></script>

<!-- Developer Customizations & App Code -->
<script src="./datafeed.js"></script>
<script src="./App.js"></script>

Alternatively, if you're installing via package managers for bundling:

npm install backtestx-charts

License and attribution

Backtestx Charts is licensed under the Apache License 2.0. You are free to use it for both commercial and non-commercial products without royalties.

Creating a chart

Initialize the data feed and pass it to the BacktestxChart constructor along with options like the target container element ID, default symbol, and timeframe resolution:

JAVASCRIPT
// 1. Initialize datafeed helper
const datafeed = new window.Datafeed();

// 2. Create the chart mount inside element ID "chart-mount"
const chart = new window.BacktestxChart('chart-mount', {
  symbol: 'BTCUSD',
  resolution: '30m',
  datafeed: datafeed
});

// Expose globally for toolbar access
window.chart = chart;

Customizing renderers

Assign custom candle render engines to chart.customDrawCandles to switch between style configurations:

JAVASCRIPT
// Apply Heikin-Ashi candle rendering style
chart.customDrawCandles = window.ChartingAPI.getCandleRenderer('heikin_ashi');
chart.render();

// Apply OHLC Bars rendering style
chart.customDrawCandles = window.ChartingAPI.getCandleRenderer('bar');
chart.render();

// Reset back to standard high-performance candlestick rendering
chart.customDrawCandles = null;
chart.render();

Register custom rendering functions dynamically by extending ChartingAPI.registerCandleType in custom-candle-type.js:

JAVASCRIPT
window.ChartingAPI.registerCandleType('my_custom_candles', function(ctx, visibleBars, slot, bodyW, chartH, priceToY, themeColors, xOffset, chartInstance) {
  ctx.save();
  ctx.strokeStyle = '#ff9800';
  ctx.lineWidth = 1.5;
  
  visibleBars.forEach((bar, index) => {
    const x = xOffset + index * slot + slot / 2;
    const yOpen = priceToY(bar.open);
    const yClose = priceToY(bar.close);
    
    ctx.beginPath();
    ctx.moveTo(x, yOpen);
    ctx.lineTo(x, yClose);
    ctx.stroke();
  });
  ctx.restore();
});

Datafeed architecture

The data layer communicates through a provider implementing four lifecycle methods:

  • resolveSymbol(symbolName) - Resolves configuration parameters (exchange, minmov, price precision).
  • getBars(symbolName, resolution, from, to, onResult) - Loads historical pricing candlesticks.
  • subscribeBars(symbolName, resolution, onTick, subscriberUID) - Connects live tick streams (e.g. WebSockets).
  • unsubscribeBars(subscriberUID) - Disconnects live streams when chart shifts.

Custom drawing tools

Extend default charting vectors by registering new shapes inside custom-drawings.js. Define drawing coordinates, canvas strokes, and click target regions:

JAVASCRIPT
window.ChartingAPI.registerCustomDrawing('buy_marker', {
  clicks: 1,
  render: function(chart, ctx, d, minPrice, maxPrice, isSelected) {
    const x = chart.barToX(d.p1.idx);
    const y = chart.priceToY(d.p1.price, minPrice, maxPrice);
    
    ctx.save();
    ctx.fillStyle = isSelected ? '#ff9800' : '#26a69a';
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x - 8, y + 12);
    ctx.lineTo(x + 8, y + 12);
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  },
  hitTest: function(chart, mouseX, mouseY, d, minPrice, maxPrice) {
    const x = chart.barToX(d.p1.idx);
    const y = chart.priceToY(d.p1.price, minPrice, maxPrice);
    if (mouseX >= x - 8 && mouseX <= x + 8 && mouseY >= y && mouseY <= y + 12) {
      return 'p1';
    }
    return null;
  }
});

Custom intervals

Register new chart candle time resolutions inside custom-interval.js:

JAVASCRIPT
// Register custom resolutions (suffix matches s/m/H/D/W/M)
window.ChartingAPI.registerCustomInterval('2m');
window.ChartingAPI.registerCustomInterval('3m');
window.ChartingAPI.registerCustomInterval('17m');

Custom watermarks

Format dynamic ticker background graphics inside custom-watermark.js:

JAVASCRIPT
window.ChartingAPI.setWatermark({
  show: true,
  watermarkMode: 'always',
  showWatermarkTicker: true,
  showWatermarkDescription: true,
  showWatermarkInterval: true,
  showWatermarkReplay: true,
  symbol: 'BTC',
  description: 'Bitcoin / U.S. Dollar',
  interval: '3m'
});