Indicators
Indicators
The contract surface for building indicators: the IIndicator lifecycle, the
IIndicatorContext runtime view, the IndicatorBase base class, the declaration
attributes, the cadence enums, and the optional render / interaction capability interfaces. Everything
here lives in TradeStrike.Pipeline.Indicators.
On this page
IIndicator INTERFACE
The lifecycle contract every indicator implements (it extends IDisposable). The runtime
calls the hooks; implementations never call them on each other — they communicate through child
indicators and the shared bar/series storage. Callbacks are single-threaded per instance: no two hooks
fire in parallel for the same indicator.
Lifecycle ordering: OnInit once → OnDataLoaded once (with all
historical bars already in storage) → OnBarUpdate per closed/intra-bar event at the
Calculate cadence → OnMarketData per live tick (only if
ProcessesMarketData) → OnDataSeriesReady when an added series finishes
backfill → OnDispose once. Live hooks never fire during backfill.
Properties
| Member | Description |
|---|---|
string ContentKey { get; } |
Stable identity across runs, derived from (Type, ParameterValues, InputSeriesSpecs). Two requests with the same key resolve to the same instance (diamond-dependency dedup). |
CalculationMode Calculate { get; } |
Cadence the runtime fires OnBarUpdate on the primary series. Must be stable for the indicator's lifetime. Default OnBarClose. |
bool ProcessesMarketData { get; } |
Opt into raw OnMarketData tick delivery. Default false — non-opted indicators pay zero per-tick dispatch cost. Independent of Calculate. |
bool ProcessesMarketDepth { get; } |
Opt into OnMarketDepth + OnMarketByOrder callbacks. Default-interface member, default false. |
IReadOnlyList<IPlot> Plots { get; } |
Renderable outputs — one IPlot per line (SMA = 1, MACD = 3). Stable list reference; allocate plots in the ctor/OnInit and never resize. Plot properties are mutable at runtime. |
IReadOnlyList<IIndicatorLine> Lines { get; } |
Horizontal threshold lines (RSI 30/70, ADX 20/40). Default-interface member returns empty. |
bool ShowPriceMarkers { get; } |
Master toggle overriding every plot's ShowPriceMarker. Default true (per-plot setting wins). |
int Displacement { get; } |
Purely visual horizontal shift of plots in bars (positive = right/future). The computed value series is never altered. Default 0. |
ImmutableArray<IIndicator> Children { get; } |
Live snapshot of attached child indicators in registration order. Lock-free (atomic swap). |
Lifecycle & child-tree methods
| Signature | Description |
|---|---|
void OnInit(IIndicatorContext ctx) |
Once after construction. Declare secondary series, instantiate known children, read parameters. ctx.Bars(0) is available. |
void OnDataLoaded(IIndicatorContext ctx) |
Once after all historical bars are loaded — compute historical state in a single (typically vectorised) pass. |
void OnBarUpdate(IIndicatorContext ctx) |
A live bar closed/updated on one of the indicator's series; ctx.BarsInProgress identifies which. |
void OnMarketData(in Tick tick, IIndicatorContext ctx) |
Per live tick, only when ProcessesMarketData is true. |
void OnMarketDepth(in DepthUpdate update, IIndicatorContext ctx) |
Per aggregated L2 depth event (ProcessesMarketDepth). The book is applied before this fires. Default no-op. |
void OnMarketByOrder(in MboEvent evt, IIndicatorContext ctx) |
Per Market-By-Order event (ProcessesMarketDepth). Default no-op. |
void OnDataSeriesReady(int seriesIndex, IIndicatorContext ctx) |
An AddDataSeries series finished backfilling; ctx.Bars(seriesIndex) now returns real bars. |
void OnDispose() |
Once on teardown. Release non-managed resources; children are disposed automatically. |
void AttachChild(IIndicator child) |
Called by the child's own ctor — not user code. Registers the child; thread-safe. |
void DetachChild(IIndicator child) |
Detach without disposing (call child.Dispose() instead, which routes here). No-op if not attached. |
public interface IStrategy : IIndicator extends the
lifecycle with order/position hooks (declared so consumers can type-check "indicator vs strategy"; the
execution callbacks land in a later phase). See the Strategies reference.IIndicatorContext INTERFACE
The runtime view an indicator has of its environment, passed to every lifecycle hook. Single-threaded with respect to the indicator. Do not cache it across threads or persist it past a callback. Many members are default-interface methods so test stubs and foreign hosts compile unchanged.
Series & per-callback metadata
| Member | Description |
|---|---|
IBarSeries Bars(int seriesIndex) |
Bars for a series; 0 = primary. Added series live at the indices returned by AddDataSeries. |
int SeriesCount { get; } |
Number of subscribed series (primary + added). |
int CurrentBar { get; } |
Last-bar index on the firing series (Bars(BarsInProgress).Count - 1); -1 in warmup. |
CurrentBarsAccessor CurrentBars { get; } |
Per-series last-bar indexer (ctx.CurrentBars[1]) for MTF indicators. Zero-allocation struct. |
int BarsInProgress { get; } |
Which series this callback is firing for (0 = primary; always 0 on OnDataLoaded). |
bool IsFirstTickOfBar { get; } |
True when the current tick opened a new bar on BarsInProgress. |
bool IsBarClosed { get; } |
True for a closed-bar OnBarUpdate; false intra-bar. Default true. |
long SequenceNumber { get; } |
Monotonic event sequence for deterministic logging/replay. |
bool IsHistorical { get; } |
True during backfill/catch-up (!IsLive). Gate alerts/broker calls on this. |
bool IsLive { get; } |
True during realtime dispatch. Default false (conservative). |
Resources, orderflow & instrument info
| Member | Description |
|---|---|
Task<int> AddDataSeries(BarSpecification spec) |
Subscribe an additional series. Idempotent for an already-subscribed spec; OnDataSeriesReady fires when bars are available. |
void RemoveDataSeries(int seriesIndex) |
Drop an added series. Index 0 throws InvalidOperationException. |
IIndicatorContext CreateChildContext(IBarSeries childPrimary, string childIdentity) |
Build a per-child context (called by AttachChild). Default returns this. |
IIndicatorResolver? Indicators { get; } |
Host catalog of instantiable indicator types (built-ins + plugins), or null. Tolerate null. |
ISeries<OrderFlowBar> OrderFlow(int seriesIndex) |
Per-bar orderflow. Only indicators marked [RequiresOrderFlow] may call it (else throws). |
ISeries<double> OpenInterest(int seriesIndex) |
Per-bar OI scalar series (NaN where unreported). Default empty series; read defensively. |
IOrderBook? OrderBook { get; } |
Live shared depth book, or null. Applied before depth/MBO callbacks. Default null. |
double? TickSize { get; } |
Minimum price increment, or null. Default null. |
double? PointValue { get; } |
Currency value of one full point, or null. Default null. |
TimeZoneInfo? DisplayTimeZone { get; } |
The chart's display time zone (bars are already normalized to it). Default null. |
Trading hours, rollovers & diagnostics
| Member | Description |
|---|---|
TradingHoursTemplate? TradingHours { get; } |
Session/holiday calendar for the instrument, or null (treat as 24/7). |
ISessionIterator? CreateSessionIterator(TradingHoursTemplate? template = null) |
Fresh stateful session iterator (NT's new SessionIterator(Bars)). Default null on stubs. |
bool IsFirstBarOfSession { get; } |
True when the current OnBarUpdate bar opens a new session. Default false. |
IReadOnlyList<DateTime> GetContractRolloversUtc(DateTime fromUtc, DateTime toUtc) |
Futures rollover instants in the bar timeline. Default empty. |
void Print(string message) |
Dev trace to the host log window (NT's Print()). |
void LogWarning(string message) |
Non-fatal anomaly; indicator keeps running. |
void LogError(string message, Exception? exception = null) |
Fatal-for-this-callback condition; runtime keeps dispatching. |
void Alert(string message) |
Raise a user-facing alert (live only). Message doubles as the rearm id. |
void Alert(string id, string message, string? soundPath = null, AlertSeverity severity = Info, double rearmSeconds = 0) |
Full-control alert. Same id within rearmSeconds won't re-fire. Default no-op. |
IndicatorBase BASE CLASS
The class plugin authors derive from. It implements IIndicator,
IOrderFlowResolutionAware and IInputSourceAware, and provides empty virtual
lifecycle hooks (override only what you need), lazy ContentKey, idempotent
Dispose, the parent-owned child tree, and the plot/line registration helpers.
Sma.csusing TradeStrike.Pipeline.Indicators;
using TradeStrike.Pipeline.Plots;
using TradeStrike.Pipeline.Series;
[IndicatorDescription("Simple moving average of the input series.")]
[IndicatorCategory(IndicatorCategory.Trend)]
[IndicatorInput(IndicatorInputKind.Scalar)]
[IndicatorPlot("SMA", IsOverlay = true, Kind = PlotKind.Overlay, Unit = PlotValueUnit.Price)]
public sealed class Sma : IndicatorBase
{
private readonly Plot _sma = new();
[IndicatorParameter(DisplayName = "Period", MinValue = 1, MaxValue = 500, Step = 1)]
public int Period { get; set; } = 14;
public Sma(IIndicator? parent = null, ISeries<double>? input = null)
: base(parent, input)
{
AddPlot(_sma);
}
public override void OnBarUpdate(IIndicatorContext ctx)
{
int n = Math.Min(Period, ctx.CurrentBar + 1);
double sum = 0;
for (int i = 0; i < n; i++) sum += Input[i];
_sma.Values[0] = sum / n;
}
}
Construction
Every subclass exposes one ctor of the shape Xxx(IIndicator? parent = null,
ISeries<double>? input = null, /* params */) : base(parent, input). The base ctor stores
Input/Bars and, when parent is non-null, registers as a child.
The child's own OnInit/OnDataLoaded are deferred to the first dispatch event so
the derived ctor body sets Period, plots, etc. before lifecycle math runs.
protected IndicatorBase(IIndicator? parent = null, ISeries<double>? input = null, IBarSeries? bars = null);
Public & protected members
| Member | Description |
|---|---|
ISeries<double> Input { get; set; } |
Scalar source for SMA/EMA/RSI-style indicators; null defaults to primary Bars(0).Close at init. |
IBarSeries Bars { get; set; } |
Bar source for OHLCV indicators (ATR/ADX/VWAP); null defaults to primary Bars(0). |
InputSourceDescriptor InputSource { get; set; } |
The universal "Input series" parameter backing store (surfaces in the editor only for Scalar input kind). |
OrderFlowResolution OrderFlowResolution { get; set; } |
The universal orderflow "Resolution" backing store (surfaces only for [RequiresOrderFlow] indicators). Default Auto. |
bool ShowPriceMarkers { get; set; } |
Master price-marker toggle (attributed parameter, group "Display"). |
int Displacement { get; set; } |
Visual bar shift (attributed parameter, ContentKeyDefault = 0). |
IReadOnlyList<IPlot> Plots { get; } / Lines { get; }
|
The registered plots and threshold lines. |
IIndicatorContext Context { get; } |
Protected. The most recent context the runtime supplied. Do not cache across threads. |
const int MaxChildDepth = 16 |
Maximum parent→child chain depth (cycle + depth guarded by AttachChild). |
protected void AddPlot(IPlot plot) |
Register a renderable output (append-only; earlier entries render behind later ones). |
protected void AddLine(IIndicatorLine line) |
Register a horizontal threshold line. |
protected void AddLine(string name, double value, ChartColor color, double lineWidthPx = 1.0, PlotStyle style = Line, bool participatesInAutoScale = true) |
Convenience overload constructing the default IndicatorLine. |
protected void AdvanceChildren(IIndicatorContext ctx) |
Advance attached children for the current live bar (call at the top of OnBarUpdate when you read a child's Output). |
protected virtual void OnReset(IIndicatorContext ctx) |
Reset hook for recalc: clears clearable plot series + disposes children. Override to drop custom accumulators (call base first). |
Overridable virtuals
| Signature | Description |
|---|---|
virtual void OnInit(IIndicatorContext ctx) |
Base seeds Context, resolves InputSource, and defaults Input/Bars. Call base.OnInit(ctx) first. |
virtual void OnDataLoaded(IIndicatorContext ctx) |
No-op by default. Vectorised backfill pass. |
virtual void OnBarUpdate(IIndicatorContext ctx) |
No-op by default. BIP filtering is handled by the framework wrapper. |
virtual void OnMarketData(in Tick, …) / OnMarketDepth / OnMarketByOrder / OnDataSeriesReady / OnDispose
|
All no-op by default; override what you need. |
virtual string ContentKey { get; } |
Lazily computed via IndicatorMetadata.For(GetType()).ComputeContentKey(this). |
virtual CalculationMode Calculate { get; protected set; } |
Default OnBarClose. Set in your ctor to opt into per-tick updates. |
virtual bool ProcessesMarketData { get; protected set; } / ProcessesMarketDepth
|
Default false; set in your ctor to receive tick / depth callbacks. |
CalculationMode ENUM
Frequency at which the runtime dispatches OnBarUpdate on the primary series. Mirrors
NinjaTrader's three modes. Controls only the bar-callback cadence — raw-tick delivery is the separate
ProcessesMarketData opt-in.
| Value | Meaning |
|---|---|
OnBarClose = 0 |
Fire once per closed bar (default). Lowest CPU — the right choice for EMA/SMA/RSI. |
OnPriceChange = 1 |
Fire whenever the bar's Close changes; skips repeat-price quotes. |
OnEachTick = 2 |
Fire on every tick. Highest CPU — for tick-precision VWAP, footprint, volume-reactive indicators. |
CalculationCadence STATIC HELPER
The single source of truth for "given a CalculationMode and the current update, should the
callback fire?" — shared by the indicator runtime and the strategy runner.
public static bool ShouldFire(CalculationMode mode, bool isClosed, bool closeChanged);
// OnBarClose => isClosed
// OnPriceChange => isClosed || closeChanged
// OnEachTick => true
Attributes
Class- and property-level attributes the framework reads by reflection to compute content keys, render
the parameter editor, persist values, and route data. All are Inherited = true.
IndicatorParameter (property)
Marks a property as a user-tunable parameter. Constraints are advisory (the editor enforces them; programmatic sets are not clamped).
| Member | Description |
|---|---|
string? DisplayName |
Editor label (defaults to the property name, humanised). |
string? Description |
Tooltip text. |
string? Group |
Logical group; the editor renders a group together. |
int Order |
Display order within the group (lower first; ties break by declaration order). |
object? MinValue, MaxValue, Step |
Advisory numeric bounds + spinner increment. |
object? ContentKeyDefault |
Omit-when-default sentinel: the parameter contributes no content-key term while equal to this value (keeps pre-existing keys byte-identical when adding a new parameter). |
ParameterEditorKind Editor |
Editor control hint. Default Auto. |
string? FileFilter |
Win32 dialog filter for FilePicker. |
ParameterEditorKind enum: Auto = 0 (host picks from the CLR type),
FilePicker = 1 (path field + Browse), SymbolPicker = 2 (shared instrument picker
for a benchmark/comparison symbol).
IndicatorPlot (class, repeatable)
Declares a named plot the indicator produces — one ISeries<T> per plot. An indicator
with zero declared plots is refused (no observable output).
| Member | Description |
|---|---|
string Name (ctor) |
The plot name. |
string? Description |
Optional description. |
bool IsOverlay |
Overlay on the price panel vs a separate panel. |
PlotKind Kind |
Shape (defaults to Overlay when IsOverlay, else Unspecified). |
double RangeMin, RangeMax |
Inclusive value bounds; double.NaN = unbounded (mapped to null). |
PlotValueUnit Unit |
Value unit. |
PlotBullishDirection BullishDirection |
Whether rising = bullish/bearish/neither. |
string? Reference |
Notable levels, e.g. "30/70 overbought/oversold". |
Class-level marker & metadata attributes
| Attribute | What it declares |
|---|---|
[IndicatorDescription(string)] |
Human-readable description (required on every built-in; non-empty or it throws). |
[IndicatorCategory(IndicatorCategory)] |
The indicator's family (see enum below). |
[IndicatorInput(IndicatorInputKind)] |
How the indicator consumes data: Scalar (surfaces the Input-series picker), Bars, or None. |
[RequiresOrderFlow] |
Opt into pre-aggregated orderflow delivery + the synthesized "Resolution" parameter. |
[RequiresOpenInterest] |
Opt into the per-bar Open-Interest channel (routing hint only; the channel is always reachable, all-NaN without an OI provider). |
[SingleInstancePerChart] |
At most one instance of this concrete type per chart; duplicate adds are silently ignored. |
[ParameterContainer(Type)] |
Delegate parameters to a separate settings POCO (set AllProperties = true to surface every persistable property). The indicator must also implement IParameterContainerProvider. |
Enums: IndicatorCategory = Unspecified, Trend, Momentum, Volume,
Volatility, OrderFlow, Structure, Custom. IndicatorInputKind = Scalar = 0,
Bars = 1, None = 2.
Metadata & identity
Reflection-extracted, per-type cached data driving content keys, the parameter editor, and discovery.
| Member | Description |
|---|---|
IndicatorMetadata.For(Type) / For<T>()
|
Cached metadata for a type. Synthesizes the "Input series" and orderflow "Resolution" parameters when applicable. |
string ComputeContentKey(object instance) |
Deterministic, locale-invariant content key from name-sorted parameter values (honours ContentKeyDefault). |
static object ResolveParameterTarget(object indicator, ParameterDescriptor) |
The object a descriptor's get/set targets (the indicator itself, or its [ParameterContainer] object). |
IReadOnlyList<ParameterDescriptor> Parameters / IReadOnlyList<PlotDescriptor> Plots
|
Declared parameters and plots. |
IndicatorType, Description, Category, InputKind |
Type + descriptive metadata. |
bool RequiresOrderFlow, RequiresOpenInterest, SingleInstancePerChart, IsInert |
Structural flags. IsInert = withheld premium form (empty editor, still constructs/removes). |
Records: ParameterDescriptor(PropertyInfo Property, string Name, string DisplayName,
string Description, string Group, int Order, object? MinValue, object? MaxValue, object? Step,
ParameterEditorKind Editor, string FileFilter) with init-only ContentKeyDefault;
PlotDescriptor(string Name, string Description, bool IsOverlay) with init-only
Semantics.
IParameterContainerProvider — object ParameterContainer { get; }: the live settings
instance for a [ParameterContainer] indicator.
PlotSemantics
The machine-readable meaning of a plot's value, so a consumer can interpret RSI = 71.6 vs
EMA = 5012 without recognising the indicator. PlotSemantics.Default = everything
unspecified.
public sealed record PlotSemantics(
PlotKind Kind, double? RangeMin, double? RangeMax,
PlotValueUnit Unit, PlotBullishDirection BullishDirection, string? Reference);
// bool HasRange => RangeMin.HasValue && RangeMax.HasValue;
| Enum | Values |
|---|---|
PlotKind |
Unspecified, Overlay, Oscillator, Histogram, Signal, Band |
PlotValueUnit |
Unspecified, Price, Percent, Ratio, Ticks, Raw |
PlotBullishDirection |
None, Up, Down |
Input sources
IInputSourceAware / IOrderFlowResolutionAware — backing-store contracts
(InputSourceDescriptor InputSource { get; set; } and
OrderFlowResolution OrderFlowResolution { get; set; }) that IndicatorBase
implements so the editor/codec descriptors are synthesized only for the right indicators.
InputPriceType enum (mirrors NT's price types plus channels): Close = 0, Open, High, Low,
Median, Typical, Weighted, OHLC4, Volume, OpenInterest = 9.
InputSourceDescriptor — a serializable value type describing where the scalar Input
comes from: a price type, or another indicator's plot (a private configured copy). Its canonical string
is a frozen, persisted grammar; structural equality is semantic equality.
| Member | Description |
|---|---|
static InputSourceDescriptor Close { get; } |
The default (equals default(InputSourceDescriptor)). |
static InputSourceDescriptor Price(InputPriceType type) |
A price-source descriptor. |
static InputSourceDescriptor Indicator(string catalogKey, IReadOnlyDictionary<string,string>? parameters = null, string? plotName = null) |
An indicator-plot source (parameters canonicalized). |
InputPriceType PriceType · string? IndicatorKey, IndicatorParametersText, PlotName
|
The descriptor's components. |
bool IsPrice, IsDefault |
Classification helpers. |
IReadOnlyDictionary<string,string> GetParameterMap() |
The source indicator's overrides as a name→value map. |
string ToString() / ToDisplayString()
|
Canonical (persisted) form / human-readable form. |
static InputSourceDescriptor Parse(string) / bool TryParse(string?, out …)
|
Parse from string (throwing / non-throwing). |
Optional capability interfaces
An indicator opts into extra host integration by ALSO implementing one of these alongside
IIndicator. The core indicator surface stays minimal — only the indicators that need a
capability take the dependency.
| Interface | Opts into |
|---|---|
IIndicatorPanelHint |
Default panel placement via PanelPlacement DefaultPanel { get; } (PriceOverlay or NewSubpanel). Non-implementers default to PriceOverlay. |
IChartCustomRender |
A custom paint pass on the indicator's own panel: void OnCustomRender(IIndicatorRenderContext), plus CustomRenderLayer Layer and bool SuppressDefaultBarRendering. |
IChartBackgroundRender |
An extra below-bars paint pass: void OnRenderBackground(IIndicatorRenderContext) — for dual-layer studies (volume profile backdrop + foreground). |
IPricePanelOverlayRender |
Painting onto the main price panel even from a sub-panel: void OnRenderPricePanel(IIndicatorRenderContext) + CustomRenderLayer PricePanelLayer (NT's DrawOnPricePanel). |
IBarColorSource |
Per-bar candle recolouring (NT paint-bars): bool PaintBarsEnabled { get; } and bool TryGetBarColor(int barIndex, in Bar bar, out ChartColor color). Last enabled source wins. |
IChartClickReceiver |
React to a left-click in the plot area: bool OnChartClick(ChartClickContext ctx) (return true to consume). Pairs with a custom render that drew the control. |
IChartMouseMoveReceiver |
Hover-driven decorations: void OnChartMouseMove(ChartMouseMoveContext ctx) (a NaN position = mouse left the chart). |
IRepaintNotifier |
Request a frame off-cadence (timer/async): event Action? RepaintRequested + void RequestRepaint(). The chart coalesces N requests to one paint. |
IRecalculateNotifier |
Ask the host to re-run history (not just repaint) when math-affecting state changed: event Action? RecalculateRequested. |
IIndicatorToolbarMenu |
Contribute a chart-toolbar dropdown: string MenuTitle, IReadOnlyList<ToolbarMenuItem> BuildMenu(), event Action? MenuChanged. |
IIndicatorContextMenu |
Contribute right-click menu items at a click location: IReadOnlyList<ToolbarMenuItem> BuildContextMenu(IndicatorContextMenuLocation) + event Action? ContextMenuChanged. |
Context structs: ChartClickContext(double X, double Y);
ChartMouseMoveContext(double X, double Y) with IsInside + Outside;
IndicatorContextMenuLocation(int BarIndex, double Price, DateTime Time, double PixelX, double PixelY).
CustomRenderLayer enum = BelowBars, AboveBars (default).
PanelPlacement enum = PriceOverlay, NewSubpanel.
IIndicatorRenderContext & menu items
The per-frame context passed to the render capability methods. Single-threaded (WPF UI thread); do not cache it across frames.
| Member | Description |
|---|---|
IChartRenderer Renderer { get; } |
Active renderer (DrawLine/DrawText/FillRect/…). |
ChartViewport Viewport { get; } |
Bar↔pixel + price↔pixel transforms for the current paint. |
IBarSeries? Bars { get; } |
Primary bar series being rendered (null on an empty tab). |
DateTime Now { get; } |
Wall-clock at frame start, in the bar timeline (for BarTimer-style countdowns; pinnable in tests). |
PlotAreaRect PlotArea { get; } |
Pixel rect of the candle pane (excludes axis strips). PlotAreaRect(X, Y, Width, Height) with Right/Bottom. |
double HeaderInsetPx { get; } / double ContentTopPx { get; }
|
Top chrome reserved by the legend; safe starting Y for top-anchored content. Default 0. |
TimeZoneInfo? DisplayTimeZone { get; } |
The chart's display zone (for session/news shading). Default null. |
IReadOnlyList<IDrawingTool> Drawings { get; } |
User-placed drawing tools (read-only). Default empty. |
PerfScope BeginScope(string category, string? detail = null) |
Nested perf sub-scope for the Task Manager. Default no-op. |
ToolbarMenuItem hierarchy
A closed record hierarchy (the host pattern-matches the concrete types) reused by both
IIndicatorToolbarMenu and IIndicatorContextMenu. Built fresh per open — do not
cache.
| Record | Use |
|---|---|
ToolbarMenuItem(string Label) |
Abstract base. |
ToolbarCommand(Label, Action Invoke, bool IsEnabled = true) |
Click-to-invoke action. |
ToolbarCheckItem(Label, Func<bool> IsChecked, Action<bool> Toggle, bool IsEnabled = true) |
Two-state toggle (re-queried each open). |
ToolbarSubmenu(Label, IReadOnlyList<ToolbarMenuItem> Items, Func<bool>? IsChecked = null) |
Nested submenu. |
ToolbarSeparator() |
Visual divider. |
ToolbarNumberInput(Label, Func<double> GetValue, Action<double> SetValue, double Min, double Max, int Decimals = 0, bool IsEnabled = true) |
Inline numeric field (clamped, rounded). |
ToolbarSlider(…same shape as ToolbarNumberInput…) |
Inline draggable slider. |
ToolbarTextInput(Label, Func<string> GetText, Action<string> SetText, bool IsEnabled = true) |
Inline free-text field (raw string pushed; indicator validates). |
ToolbarDescription(string Text) |
Greyed-out help line. |
ToolbarRadioGroup(Label, IReadOnlyList<ToolbarRadioOption> Options) |
Mutually-exclusive option group. ToolbarRadioOption(Label, Func<bool> IsSelected, Action Select, bool IsEnabled = true). |
ToolbarColorPicker(Label, Func<ChartColor> GetColor, Action<ChartColor> SetColor, bool IsEnabled = true) |
Reversible colour-picker row. |
Helpers
| Type | Description |
|---|---|
CurrentBarsAccessor |
Zero-allocation struct returned by ctx.CurrentBars; this[int seriesIndex] = last-bar index on that local series (-1 if empty). |
IntraBarRefreshGate |
Throttle for expensive intra-bar refresh work. ShouldRefresh(bool force = false); const int DefaultIntervalMs = 250. Single-threaded; injectable clock. |
BarTimeProjection (static) |
Time-axis math for custom rendering: FractionalBarIndex(DateTime, IReadOnlyList<DateTime> barStarts, TimeSpan barDuration), EstimateBarDuration(barStarts, int sample = 64), and the zero-copy BarStartList(IBarSeries) view. |
Factory, resolver & logger
| Type | Members |
|---|---|
IIndicatorFactory |
String-key creation for declarative consumers: bool Knows(string typeKey), IIndicator Create(string typeKey, IReadOnlyDictionary<string,string>? parameters = null). |
IIndicatorResolver |
Type-keyed catalog (built-ins + plugins): IReadOnlyList<Type> AvailableTypes, IIndicator? Create(Type, IReadOnlyDictionary<string,object>? overrides = null) (returns null when unknown). Reachable via ctx.Indicators or IndicatorResolverAmbient.Resolver. |
IndicatorResolverAmbient (static) |
Process-wide resolver install: Resolver, SetResolver(…), scoped Use(…). Default null = engine built-ins only. |
IIndicatorLogger |
Diagnostic sink (the target of Print/LogWarning/LogError): Print(identity, message), Warning(…), Error(identity, message, Exception? = null). Thread-safe. NullIndicatorLogger.Instance is the no-op. |
IIndicatorDefinitionSource +
IndicatorDefinitionAmbient let the host gate premium indicators' editor metadata on
cloud-served specs (verdicts Reflection / Spec / Withheld via
DefinitionVerdict + DefinitionResult). A process that installs no source sees
pure local reflection. Plugin authors normally never touch this — content keys stay byte-identical
across verdicts.Alerts
IndicatorAlert — the payload raised by ctx.Alert(…):
public readonly record struct IndicatorAlert(
string Id, string Message, DateTime TimeUtc,
AlertSeverity Severity = AlertSeverity.Info, string? SoundPath = null,
double RearmSeconds = 0, string? InstrumentId = null);
IIndicatorAlertSink — host seam delivering alerts to the user:
void Dispatch(in IndicatorAlert alert). Thread-safe; return promptly.