Introducing QFChart: TypeScript Financial Charting for Candlesticks and Indicators

Building a trading platform or financial dashboard shouldn’t require reinventing the charting wheel. Yet most developers face a tough choice: embed third-party charting solutions that lock you into their ecosystem, or build everything from scratch using low-level canvas APIs.

We built QFChart to eliminate that trade-off.

What is QFChart?

QFChart is a lightweight, high-performance financial charting library built on Apache ECharts. It provides an intuitive API specifically designed for OHLCV candlestick charts, technical indicators, and interactive drawing tools ; everything you need to build professional trading interfaces.

The library is open-source (Apache 2.0), written in TypeScript, and works seamlessly with PineTS for a complete Pine Script execution and visualization stack, though it’s fully independent and can be used with any data provider or technical indicator library.

Why We Built QFChart

When we created PineTS to run Pine Script outside TradingView, we faced an obvious next challenge: how do you visualize the results? General-purpose charting libraries like Chart.js and D3.js are powerful, but they’re not built for the specific needs of financial charting:

  • Time-series with gaps: Markets close. Weekends happen. Financial charts need to handle non-continuous time series elegantly.
  • Multi-pane layouts: Indicators like RSI and MACD need their own panes below the main chart, each with independent scaling.
  • Overlay indicators: Moving averages and Bollinger Bands need to render directly on top of candlesticks.
  • Real-time updates: Trading bots and dashboards need incremental updates without full chart re-renders.
  • Drawing tools: Traders need trend lines, Fibonacci retracements, and measurement tools.

QFChart solves all of these problems with a clean, developer-friendly API.

Core Features

Professional Candlestick Charts

High-performance rendering of OHLCV data with customizable colors and automatic scaling:

import { QFChart } from '@qfo/qfchart';

const chart = new QFChart(container, {
    title: 'BTC/USDT',
    height: '600px',
    backgroundColor: '#1e293b',
    upColor: '#00da3c',
    downColor: '#ec0000',
});

chart.setMarketData([
    {
        time: 1620000000000,
        open: 50000,
        high: 51000,
        low: 49000,
        close: 50500,
        volume: 100000,
    },
    // ... more candles
]);

Multi-Pane Indicator Support

Stack indicators in separate panes with customizable heights and independent scaling:

const macdPlots = {
    histogram: {
        data: [
            { time: 1748217600000, value: 513.11, options: { color: '#26A69A' } },
            // ...
        ],
        options: { style: 'histogram', color: '#26A69A' },
    },
    macd: {
        data: [/* ... */],
        options: { style: 'line', color: '#2962FF' },
    },
    signal: {
        data: [/* ... */],
        options: { style: 'line', color: '#FF6D00' },
    },
};

chart.addIndicator('MACD', macdPlots, {
    isOverlay: false,
    height: 15, // Percentage of chart height
    controls: { collapse: true, maximize: true },
});

Overlay Indicators

Add indicators directly on top of the main chart:

const smaPlots = {
    sma: {
        data: [
            { time: 1620000000000, value: 50200 },
            // ...
        ],
        options: {
            style: 'line',
            color: '#2962FF',
            linewidth: 2,
        },
    },
};

chart.addIndicator('SMA_20', smaPlots, {
    isOverlay: true,
});

Rich Plot Styles

QFChart supports multiple visualization styles for rendering technical indicators:

  • line: Classic line charts for moving averages and trends
  • step: Step-line charts for discrete value changes
  • histogram: Vertical bars for volume-like data
  • columns: Grouped vertical bars
  • circles: Scatter plots with circular markers
  • cross: Cross-shaped markers for signals
  • background: Fills background areas based on conditions (like bgcolor() in Pine Script)
  • shape: Arrows, triangles, labels with custom positioning
  • bar/candle: OHLC rendering for indicators like Heikin Ashi (equivalent to plotbar() and plotcandle())
  • barcolor: Colors main chart candlesticks based on conditions (equivalent to barcolor() in Pine Script)

Each style supports per-point customization for advanced visualizations.

Real-Time Updates

For live trading applications, updateData() provides incremental updates without full re-renders:

// Keep reference to indicator
const macdIndicator = chart.addIndicator('MACD', macdPlots, {
    isOverlay: false,
    height: 15,
});

// WebSocket callback
function onNewTick(bar, indicators) {
    // Update indicator data first
    macdIndicator.updateData(indicators);
    
    // Update chart data (triggers re-render)
    chart.updateData([bar]);
}

This approach is significantly faster than calling setMarketData() and is essential for real-time trading dashboards.

Interactive Drawing Tools (Plugin System)

QFChart includes an extensible plugin system for adding interactive tools:

import { LineTool, FibonacciTool, MeasureTool } from '@qfo/qfchart';

chart.registerPlugin(new LineTool());
chart.registerPlugin(new FibonacciTool());
chart.registerPlugin(new MeasureTool());

Currently available plugins:

  • Line Drawing: Draw trend lines and support/resistance levels
  • Fibonacci Retracements: Interactive Fibonacci levels with automatic ratio calculations
  • Measure Tool: Measure price and time distances between any two points

The plugin architecture makes it easy to build custom tools specific to your trading strategy.

Flexible Layouts

Configurable data displays that don’t obstruct the chart:

const chart = new QFChart(container, {
    title: 'BTC/USDT',
    databox: {
        position: 'right', // or 'left', 'floating'
    },
});

The databox displays current OHLCV values and can be positioned to fit your UI design.

Full Customization

Every visual aspect of the chart can be customized:

const chart = new QFChart(container, {
    title: 'BTC/USDT',
    backgroundColor: '#1e293b',
    upColor: '#00da3c',
    downColor: '#ec0000',
    fontColor: '#cbd5e1',
    fontFamily: 'sans-serif',
    padding: 0.2, // Vertical padding for auto-scaling
    dataZoom: {
        visible: true,
        position: 'top',
        height: 6,
        start: 0,
        end: 100,
    },
    watermark: true, // Show "QFChart" watermark
    controls: {
        collapse: true,
        maximize: true,
        fullscreen: true,
    },
});

Perfect Pairing: QFChart + PineTS

QFChart was designed to work seamlessly with PineTS. Together, they provide a complete solution for running and visualizing Pine Script indicators:

import { PineTS, Provider } from 'pinets';
import { QFChart } from '@qfo/qfchart';

// Execute Pine Script indicator
const pineTS = new PineTS(Provider.Binance, 'BTCUSDT', '1h', 500);

const pineScript = `
//@version=6
indicator("EMA Cross")
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
plot(fast, "Fast EMA", color.blue)
plot(slow, "Slow EMA", color.red)
`;

const { plots, marketData } = await pineTS.run(pineScript);

// Visualize with QFChart
const chart = new QFChart(container, { title: 'BTC/USDT' });
chart.setMarketData(marketData);
chart.addIndicator('EMA_Cross', plots, { isOverlay: true });

This combination gives you the power to run any Pine Script indicator and render it exactly as it would appear in TradingView—but in your own application, under your control.

Installation

NPM

npm install @qfo/qfchart echarts

Browser (UMD)

<!-- 1. Include ECharts (Required) -->
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>

<!-- 2. Include QFChart -->
<script src="https://cdn.jsdelivr.net/npm/@qfo/qfchart/dist/qfchart.min.browser.js"></script>

Quick Start Example

Here’s a complete working example in less than 20 lines:

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@qfo/qfchart/dist/qfchart.min.browser.js"></script>
</head>
<body>
    <div id="chart" style="width: 100%; height: 600px;"></div>
    
    <script>
        const chart = new QFChart.QFChart(
            document.getElementById('chart'),
            { title: 'BTC/USDT' }
        );
        
        const data = [
            { time: 1620000000000, open: 50000, high: 51000, low: 49000, close: 50500, volume: 100 },
            // ... add more candles
        ];
        
        chart.setMarketData(data);
    </script>
</body>
</html>

Documentation & Resources

Use Cases

QFChart is perfect for:

  • Trading Platforms: Build custom charting interfaces for your users
  • Portfolio Dashboards: Visualize asset performance and indicators
  • Backtesting Visualizations: Display strategy results with indicators overlaid
  • Research Tools: Analyze market data with technical indicators
  • Educational Platforms: Teach technical analysis with interactive charts
  • Trading Bots: Monitor live strategy performance in real-time

What’s Next

We’re actively developing QFChart alongside PineTS. Upcoming features include:

  • Additional drawing tools (trend channels, rectangles, text annotations)
  • Enhanced customization options
  • Performance optimizations for massive datasets
  • More plugin examples and templates

Get Involved

QFChart is open-source and community-driven. We welcome contributions, bug reports, and feature requests:

The Complete Stack

QFChart is one piece of the QuantForge ecosystem:

  • PineTS: Run Pine Script indicators in JavaScript/TypeScript
  • QFChart: Visualize financial data and technical indicators
  • Together: A complete solution for building professional trading platforms

Whether you’re building a trading bot, a portfolio dashboard, or a full-fledged trading platform, QFChart gives you the charting foundation you need—without the vendor lock-in.


QFChart is open-source software licensed under Apache 2.0. Built with ❤️ by QuantForge.

Leave a Reply

Your email address will not be published. Required fields are marked *