Loading Data ...
This demo uses the PineTS library to load the market data and calculate the indicators, and QFChart library for visualizing the results.
Loading Data ...
This indicator implements a classic dual EMA crossover system with visual background color zones to make trend identification effortless. It uses a 9-period EMA (fast) and an 18-period EMA (slow) plotted directly on the price chart. When the fast EMA crosses above the slow EMA, a blue background zone appears, signaling bullish momentum. When the fast EMA crosses below the slow EMA, an orange background zone appears, signaling bearish momentum.
The indicator consists of three simple components:
Common trading strategies using this indicator:
Exponential Moving Averages give more weight to recent prices compared to Simple Moving Averages, making them more responsive to price changes. The 9/18 EMA combination provides a good balance between responsiveness and noise filtering:
The background colors are the key innovation in this implementation. Instead of manually watching for crossovers, the colored zones make the current trend instantly visible at a glance. This is especially useful when monitoring multiple charts or making quick trading decisions.
This live demo showcases QFChart's background rendering capability combined with PineTS's real-time indicator calculations. The EMAs are continuously recalculated using PineTS's optimized incremental state management, while QFChart renders the lines and background colors as overlay plots on the main chart. The chart updates every 3 seconds with live market data from Binance, showing trend changes as they happen.
This demo demonstrates several advanced QFChart features:
PineTS.stream() to continuously fetch and process live market dataHere's the actual implementation:
const institBiasIndicator = (context) => {
const ema9 = ta.ema(close, 9);
const ema18 = ta.ema(close, 18);
const bull_bias = ema9 > ema18;
const bear_bias = ema9 < ema18;
plot(ema9, 'EMA 9', { title: 'EMA 9', color: '#2962FF', style: 'line' });
plot(ema18, 'EMA 18', { title: 'EMA 18', color: '#FF6D00', style: 'line' });
plot(bull_bias, 'Bull Bias', {
title: 'Bull Bias',
color: '#2962FF',
style: 'background',
});
bgcolor(bear_bias ? '#FF6D00' : na, { title: 'Bear Bias' });
};
You can easily modify this indicator:
To use this indicator in your own application:
// Define the indicator
const emaIndicator = (context) => {
const ema9 = ta.ema(close, 9);
const ema18 = ta.ema(close, 18);
const bull_bias = ema9 > ema18;
const bear_bias = ema9 < ema18;
plot(ema9, 'EMA 9', { color: '#2962FF', style: 'line' });
plot(ema18, 'EMA 18', { color: '#FF6D00', style: 'line' });
plot(bull_bias, 'Bull Bias', { color: '#2962FF', style: 'background' });
bgcolor(bear_bias ? '#FF6D00' : na, { title: 'Bear Bias' });
};
// Create PineTS instance and stream data
const pineTS = new PineTS(PineTS.Provider.Binance, 'BTCUSDC', '1h', 500);
const stream = pineTS.stream(emaIndicator, {
pageSize: 100,
live: true,
interval: 3000
});
// Initialize QFChart
const chart = new QFChart.QFChart(container, {
title: 'BTC/USDT',
lastPriceLine: { visible: true, showCountdown: true },
interval: 60 * 60 * 1000
});
// Handle data updates
stream.on('data', (ctx) => {
if (!chart.initialized) {
chart.setMarketData(ctx.marketData);
indicator = chart.addIndicator('EMA Crossover', ctx.plots, {
isOverlay: true
});
} else {
indicator.updateData(ctx.plots);
chart.updateData([latestBar]);
}
});