Write Custom Indicators
This guide shows how to add your own indicator and render it in the TradeJS chart.
TradeJS supports two indicator paths:
- TypeScript indicator plugins (this page)
- Pine
plotindicators inside Pine strategies
1. Create an Indicator Plugin Package
TradeJS loads indicator plugins through tradejs.config.ts.
In your plugin package, export indicatorEntries:
import type { IndicatorPluginEntry } from '@tradejs/types';
import { defineIndicatorPlugin } from '@tradejs/core/config';
export const indicatorEntries = defineIndicatorPlugin({
indicatorEntries: [
{
indicator: {
id: 'sandboxMomentum',
label: 'Sandbox Momentum',
enabled: false,
},
historyKey: 'sandboxMomentum',
compute: ({ data }) => {
const last = data[data.length - 1];
const prev = data[data.length - 2];
if (!last || !prev || prev.close === 0) {
return null;
}
return ((last.close - prev.close) / prev.close) * 100;
},
renderer: {
shortName: 'SBX MOM',
minHeight: 120,
figures: [
{
key: 'sandboxMomentum',
title: 'Sandbox Momentum: ',
type: 'line',
color: '#f59e0b',
},
{
key: 'sandboxMomentumZero',
title: 'Zero: ',
type: 'line',
color: '#94a3b8',
dashed: true,
constant: 0,
},
],
},
} satisfies IndicatorPluginEntry,
],
}).indicatorEntries;
2. Connect Plugin in tradejs.config.ts
import { defineConfig } from '@tradejs/core/config';
import { basePreset } from '@tradejs/base';
export default defineConfig(basePreset, {
indicators: ['@your-scope/tradejs-indicators-pack'],
});
3. Reload Your Runtime/UI
Restart your TradeJS runtime/UI so plugin registry changes are picked up.
4. Show Indicator in Chart UI
Define renderer inside indicatorEntries; the UI pipeline then wires it automatically:
- Backend returns indicator
renderersin the indicators metadata endpoint. - Frontend stores renderer metadata in indicator state.
- Chart layer creates pane/figures from renderer description.
Minimal working setup:
{
historyKey: 'sandboxMomentum',
compute: ({ data }) => {
const last = data[data.length - 1];
const prev = data[data.length - 2];
if (!last || !prev || prev.close === 0) return null;
return ((last.close - prev.close) / prev.close) * 100;
},
renderer: {
shortName: 'SBX MOM',
paneId: 'sandbox_momentum_pane',
minHeight: 120,
figures: [
{ key: 'sandboxMomentum', type: 'line', color: '#f59e0b' },
{ key: 'sandboxMomentumZero', type: 'line', constant: 0, dashed: true },
],
},
}
renderer.figures[].keymust match keys present in candles (usually yourhistoryKey).- Use
constantfor horizontal levels so no extra compute output is needed. - Then just enable the indicator in UI (Indicators); pane and lines are created automatically.
5. Debug Checklist
- Indicator does not appear:
verify plugin package is listed in
indicators. - Values are empty:
check
computereturns finite numbers and handles warmup bars. - Draw looks wrong:
validate
renderer.figures[].keymatches produced history keys.