Write Custom TypeScript Indicators
This guide shows how to add your own TypeScript indicator and render it in the TradeJS chart.
Custom TradeJS indicators are authored as TypeScript plugins. Standalone Pine indicator plugins are not currently supported; Pine support is limited to strategy modules.
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.