Skip to main content

Custom Indicators

Custom indicators let you create your own technical analysis tools beyond the built-in indicators. You can define custom calculations and visualize them on your chart in various ways.

Quick Start

Here's the simplest way to create a custom indicator:

// Step 1: Register your custom indicator
chartApi.registerCustomIndicator({
name: 'Custom_SMA',
displayName: 'Simple Moving Average',
description: 'A custom moving average indicator',
category: 'trend',

// Define adjustable parameters
inputs: [
{
name: 'length',
type: 'number',
defaultValue: 14,
min: 1,
max: 100,
step: 1,
description: 'Number of periods to average'
}
],

// Define the calculation logic
calculate: (getRealBar, getDerivedBar, index, options) => {
const length = options.length || 14;
const currentBar = getRealBar(index);

// Not enough data yet
if (!currentBar || index < length - 1) return null;

// Calculate the average
let sum = 0;
for (let j = 0; j < length; j++) {
const bar = getRealBar(index - j);
if (bar) sum += bar.close;
}

return { value: sum / length };
},

// Define how it looks on the chart
renderLayers: [
{
type: 'line',
dataKey: 'value',
color: '#2196F3',
lineWidth: 2
}
],

// Where to display it
pane: 'main',
categoryType: 'overlay'
});

// Step 2: Add it to your chart
chartApi.addIndicator('Custom_SMA');

Understanding the Basics

What is a Custom Indicator?

A custom indicator is a formula you create to analyze price data. It consists of three parts:

  1. Inputs - Settings users can adjust (like period length)
  2. Calculate - The math that processes the data
  3. Render Layers - How the results appear on the chart

The Three Parts Explained

1. Inputs (Settings)

Inputs are the knobs and dials users can adjust. Each input has:

  • name - Internal name used in your code
  • type - What kind of value: 'number', 'string', 'boolean', or 'color'
  • defaultValue - Starting value
  • min/max - Allowed range (for numbers)
  • step - How much it changes when adjusted
  • description - Help text for users

Example:

inputs: [
{
name: 'period',
type: 'number',
defaultValue: 20,
min: 5,
max: 50,
step: 1,
description: 'Number of bars to calculate'
},
{
name: 'color',
type: 'color',
defaultValue: '#FF0000',
description: 'Line color'
}
]

2. Calculate Function (The Math)

This is where you define what your indicator does. The function runs once for each bar on the chart.

What you receive:

  • getRealBar(index) - Get price data (open, high, low, close, volume) at any bar index
  • getDerivedBar(index) - Get previous calculation results (useful for indicators that build on themselves, like EMA)
  • index - Current bar number being calculated
  • options - The user's current input settings

What you return:

  • Return an object with your calculated values: { value: 123.45 }
  • Return null if you don't have enough data yet

Simple Example:

calculate: (getRealBar, getDerivedBar, index, options) => {
// Get current bar's data
const bar = getRealBar(index);

// Check if we have valid data
if (!bar) return null;

// Calculate something (example: double the close price)
const result = bar.close * 2;

// Return the result
return { value: result };
}

Advanced Example (using previous results):

calculate: (getRealBar, getDerivedBar, index, options) => {
const bar = getRealBar(index);
if (!bar) return null;

// First bar - just use the close price
if (index === 0) {
return { ema: bar.close };
}

// Get the previous EMA value
const prevResult = getDerivedBar(index - 1);
if (!prevResult) return null;

// Calculate new EMA using previous value
const multiplier = 2 / (options.length + 1);
const ema = (bar.close - prevResult.ema) * multiplier + prevResult.ema;

return { ema: ema };
}

3. Render Layers (The Visual)

Render layers control how your indicator looks on the chart. You can have multiple layers for complex indicators.

Available Layer Types:

  1. line - A continuous line
  2. area - Filled area under a line
  3. histogram - Vertical bars from zero line
  4. column - Vertical bars
  5. scatter - Individual dots
  6. candle - Candlestick representation
  7. bgcolor - Background color highlighting
  8. fill - Fill between two lines

Layer Properties:

  • type - Visual style (see types above)
  • dataKey - Which value from your calculate function to display
  • color - Line/fill color (hex code like '#FF0000')
  • lineWidth - Thickness of lines (1-5)
  • opacity - Transparency (0.0 to 1.0)
  • fill - Fill color (for area type)
  • secondaryKey - Second data key (for fill type - fills between two lines)
  • dashPattern - Dashed line pattern (for line type)

Examples:

// Simple line
renderLayers: [
{
type: 'line',
dataKey: 'value',
color: '#2196F3',
lineWidth: 2
}
]

// Multiple lines (like MACD)
renderLayers: [
{
type: 'histogram',
dataKey: 'histogram',
color: '#999999',
opacity: 0.5
},
{
type: 'line',
dataKey: 'macd',
color: '#2196F3',
lineWidth: 2
},
{
type: 'line',
dataKey: 'signal',
color: '#FF5722',
lineWidth: 2
}
]

// Fill between two lines (like Bollinger Bands)
renderLayers: [
{
type: 'fill',
dataKey: 'upper',
secondaryKey: 'lower',
color: '#2196F3',
opacity: 0.1
},
{ type: 'line', dataKey: 'upper', color: '#2196F3', lineWidth: 1 },
{ type: 'line', dataKey: 'middle', color: '#FF9800', lineWidth: 2 },
{ type: 'line', dataKey: 'lower', color: '#2196F3', lineWidth: 1 }
]

// Background coloring
renderLayers: [
{
type: 'bgcolor',
dataKey: 'highlight',
color: '#FFEB3B',
opacity: 0.2
}
]

Where to Display Your Indicator

Pane Options

  • 'main' - Overlay on the main price chart (for indicators that work with price)
  • 'new' - Create a separate panel below the chart (for oscillators and indicators with different scales)

Category Types

  • 'overlay' - Draws on top of price candles/bars
  • 'oscillator' - Independent indicator with its own scale

Examples:

// Moving average - overlays on price
{
pane: 'main',
categoryType: 'overlay'
}

// RSI - separate panel
{
pane: 'new',
categoryType: 'oscillator'
}

Managing Your Indicators

Adding to Chart

After registering, add the indicator to your chart:

chartApi.addIndicator('Custom_SMA');

With custom options:

chartApi.addIndicator('Custom_SMA', { length: 50 });

Removing from Chart

chartApi.removeIndicator(indicatorId);

Hiding/Showing

// Hide indicator (paneId is usually 0 for main, 1+ for sub-panels)
chartApi.setIndicatorVisibility(indicatorId, false, 0);

// Show indicator
chartApi.setIndicatorVisibility(indicatorId, true, 0);

Updating Settings

chartApi.updateIndicator(indicatorId, {
inputs: { length: 30 }
}, 0);

Listening for Events

Get notified when indicators are added:

chartApi.onIndicatorAdded((indicator) => {
console.log('New indicator added:', indicator.name);
});