Use secondary market data
Load secondary bars in your application and pass them when you add or update the indicator. Inside the indicator, call security(...) to read the aligned series. This keeps data access in one place: your existing datafeed.
Secondary indicator data is not a chart comparison. It does not add a comparison series, open the Compare Symbols dialog, or change chart state; the supplied bars are available only inside that indicator's calculation.
Dataflow
The indicator declares the symbol input. Your application decides how that symbol maps to a venue and loads the matching bars.
Minimal working pair
Indicator — declare the symbol and read the supplied series:
import { indicator, input, plot, close, security } from '@tradescript/pro/sdk/indicators'
export default indicator('Secondary close', () => {
const other = input.symbol('Other', 'ETHUSDT', { id: 'other' })
plot.line(close, { key: 'main', title: 'Main' })
plot.line(security(other, 'close', { map: 'continuous' }), {
key: 'other',
title: 'Other',
})
}, { pane: 'price' })
Application — register, load, attach:
import { registerCustomIndicator, loadSecuritiesForIndicator } from '@tradescript/pro/sdk'
import secondaryClose from './indicators/secondaryClose'
const name = registerCustomIndicator(secondaryClose)
const securities = await loadSecuritiesForIndicator(secondaryClose, mainBars, { other: 'ETHUSDT' }, loadBars)
chart.addIndicator({
name,
paneId: 'candle_pane',
inputs: { other: 'ETHUSDT' },
securities,
})
Result: the main close and secondary close render on the same pane. With map: 'continuous', the most recent secondary value is used between secondary bars.
The four things that matter
Symbol ownership
- Your application resolves every
input.symbolvalue and loads the bars. Indicators only read the supplied series.
Interval alignment
- Secondary bars are matched to main-series bars by timestamp. The
mapoption onsecurity(...)decides what happens when timestamps disagree:
| Mode | Behavior |
|---|---|
precise (default) | Exact timestamp match only; missing bars → NaN |
continuous | Latest secondary bar at or before main time; if none, next later bar |
Missing data
- With
precise, every unmatched main bar yieldsNaNin the secondary series — plots show gaps. Withcontinuous, values carry forward, so a slow-updating secondary interval renders as steps. Warm-up positions of derivedta.*series areNaNeither way.
Refreshing data
- Reload and pass secondary bars again when the chart symbol, interval, or the secondary-symbol input changes. Remove the indicator normally when it is no longer needed.
Application helpers
Exported from @tradescript/pro/sdk:
| Helper | Role |
|---|---|
symbolInputsOf(indicator) | input.symbol specs |
resolveSymbolMap(indicator, overrides) | Resolved ticker strings |
loadSecuritiesForIndicator(indicator, mainBars, overrides, loadBars, options?) | Build Record<string, SecuritySeries> |
attachSecuritiesToIndicatorInstance(instance, securities) | Write the typed instance.securities field |
runIndicatorWithSecurities(...) | Load + indicator.run convenience |
runtimeWithSecurities(securities, base?) | Context object for direct indicator calls |
Full load example
import {
registerCustomIndicator,
loadSecuritiesForIndicator,
} from '@tradescript/pro/sdk';
import secondaryCloseIndicator from './indicators/secondaryCloseIndicator';
const ci = secondaryCloseIndicator;
const name = registerCustomIndicator(ci);
const mainBars = chartDataAsAuthoringBars(chart.getDataList());
const overrides = { other: 'SPOT:BINANCE:ETHUSDT' };
const securities = await loadSecuritiesForIndicator(
ci,
mainBars,
overrides,
async (request) => {
// request.symbol, request.key, request.mainBars, request.from, request.to
const history = await datafeed.loadBars(
{ ticker: request.symbol },
'15m',
{ startTime: request.from!, endTime: request.to!, barCount: mainBars.length },
);
return history.bars.map((b, index) => ({
time: b.time,
open: b.open,
high: b.high,
low: b.low,
close: b.close,
volume: b.volume ?? 0,
index,
}));
},
);
// Chart path: pass the resolved secondary series through IndicatorDefinition.securities
chart.addIndicator({
name,
paneId: 'candle_pane',
inputs: overrides,
securities,
});
Time-scale extension
Set canExtendTimeScale: true on the indicator when you plot values at future timestamps. The chart reserves room to the right of the latest bar for those values without adding artificial bars. Ordinary plots and markers remain aligned with the chart bars.