Create streaming chart and screener indicators
Declare stable types, emit causal samples and package renderer metadata with the plugin.
Reviewed 2026-10-24 · Windows & macOS
On this page
Use the streaming plugin contract#
Create an external scaffold with kind indicator or both. A chart indicator implements IChartIndicatorPlugin and creates an instrument/run-scoped IChartIndicatorStream. The host has no batch compatibility implementation to fill in missing streaming behavior. Publish the manifest-backed payload under a watched root and inspect the loaded indicator catalogue.
Keep the Type stable. Saved charts, screener columns, algorithms and templates store it. A friendly label can be edited without changing that ID; a casually renamed Type breaks existing configurations. The catalogue declares label, description, default panel and parameter definitions/ranges. Use the same identifier in runtime metadata and samples.
A minimal display-bar indicator#
This close-line probe shows the structure without pretending to implement a trading signal:
using AMM.Algorithms;
public sealed class CloseProbePlugin : IChartIndicatorPlugin
{
public string Type => "my_close_probe";
public PluginIndicatorCatalogEntry Catalog => new()
{
Type = "my_close_probe",
Label = "Close probe",
Description = "Displays the received display-bar close.",
DefaultPanelId = "main"
};
public IChartIndicatorStream CreateStream(
ChartIndicatorDefinition indicator,
IPluginIndicatorSessionCalendar? calendar) => new Stream(indicator);
private sealed class Stream : IChartIndicatorStream
{
public Stream(ChartIndicatorDefinition indicator)
{
Metadata = new PluginIndicatorSeriesMetadata
{
IndicatorId = indicator.Id, Type = "my_close_probe",
ValueLabel = "Close", ValueStyle = "line"
};
}
public PluginIndicatorSeriesMetadata Metadata { get; }
public void OnSourceBar(PluginIndicatorBar bar) { }
public PluginIndicatorSample? OnDisplayBar(PluginIndicatorBar bar) =>
new() { Timestamp = bar.Timestamp, Value = bar.Close };
}
}
Place it in the scaffold project, build using the generated README and add the discovered type to a chart. Compare the line with the candle close. The default zero warmup is appropriate for this probe because it has no rolling state. A real rolling indicator must declare sufficient history and implement parameter validation.
Source bars and display bars#
The stream receives OnSourceBar before display bars derived from that observation. Rolling indicators normally compute on display bars; session-sensitive and multi-timeframe indicators can retain source-time context. A sample must carry the current display-bar timestamp so it maps to the correct candle.
Keep multi-timeframe values causal. A completed H4 condition can persist over later lower-timeframe display bars, while a one-bar entry pulse belongs only to its exact confirmation candle. Do not shift a marker to whichever display timestamp happens to be closest. Use the provided session calendar rather than assuming midnight UTC is every instrument's day boundary.
A null sample means no sample exists and breaks a rendered line. It is appropriate before readiness, but repeated nulls after readiness can create misleading gaps. A neutral computed zero is different from unavailable. Emit ready lanes while a slower lane warms; do not blank the entire indicator until every optional higher timeframe is ready.
Separate warmup from visible context#
GetRequiredWarmupBars requests hidden seed history. GetMinimumVisibleBars requests useful painted context. A multi-month seed requirement should not force the chart to display that entire history. Test the left edge after a cold load, scrolling, changing timeframe and opening the same indicator in a screener.
Library indicators differ in partial-value behavior. SMA/EMA and several volatility calculations can emit immediately; RSI/Stochastic and other series have specific readiness rules. Preserve the formula's declared seed and smoothing. AMM's SMA-seeded EMA and first-close EMA are distinct tools; selecting either without recording the choice can change parity.
Publish generic renderer metadata#
PluginIndicatorSeriesMetadata supplies the primary label/style and named extra-value labels/styles/order. Samples supply decimal values. Use generic roles such as line, histogram, reference level, signal marker, support/resistance or background. Put an ordinary price overlay in panel main; a separate panel ID creates its own pane.
Use persistent level styles for real horizontal runs. Sparse plan prices and diagnostic event values can use presentation-only metadata instead of painting fictitious continuous levels. If a line changes colour through separate outputs, share the transition sample between outgoing and incoming segments so it remains connected.
Trade-entry markers use the shared entry role, enabling the chart's signal-visibility control to hide badges without disabling calculations, alerts or screener values. Ordinary candlestick detections should keep their reversal/continuation semantics instead of being mislabeled as entries.
Parameters, screeners and algorithms#
Declare every public parameter with a stable key, type, default and useful bounds. Test invalid values at runtime; UI bounds alone are insufficient for saved JSON/API requests. Screeners consume the plugin's numeric primary/extra outputs, so use stable output keys and explicit neutral pulses where a stale prior signal must clear.
Algorithms request a custom type through ChartIndicatorDefinition with a stable instance ID, CustomType, panel and scalar parameters. Several instances can share the same Type while using different IDs/periods. Templates must keep those instance IDs coherent with any rules referring to them.
Verify and maintain#
Test small known input sequences, warmup edges, parameter extremes, resets, source/display ordering and no-lookahead behavior. Compare same-feed, same-session observations before claiming visual or numerical parity with another platform. A research reconstruction is not automatically the protected original indicator.
Publish the complete DLL/manifest/dependency package, verify loaded identity and reopen a new run. Keep source formulas, tests and companion templates together. See Plugins, Algorithm authoring and Plugin templates for the surrounding workflow.