Building & deploying

Building & deploying

Overview & discovery

What a plugin DLL is, how SabrTrader finds and reloads it, which catalog each type lands in, and the rules a type must meet to be discovered.

What a plugin is

A plugin is one .NET assembly (one .dll) that references the SabrTrader.Sdk package and contains one or more public types implementing an SDK contract. There is no registration call and no entry-point method to write. You compile against the contracts, copy the DLL into Documents\SabrTrader\Plugins, and the platform finds your types.

One assembly can carry any mix of plugin kinds: indicators, strategies, bar types, drawing tools, Market Analyzer columns, venue plugins and add-ons. You can ship a whole feature, such as an indicator plus the custom bar type it depends on, as one file.

The build and reload loop

The platform loads every DLL in the plugin folder at startup, then watches the folder for as long as it runs. When a DLL is added or rebuilt, it is loaded again about a second after the file stops changing. Your development loop is:

  1. Build your plugin project (dotnet build, or build in your IDE).
  2. Deploy the DLL into the plugin folder, either through the SDK's opt-in auto-deploy target or by copying it (see Where to deploy). With auto-deploy, building is deploying.
  3. Check the result in the running platform. The Control Center Log tab shows a Plugins line for each reload, with the number of types it registered.

What a reload does depends on the plugin kind:

Plugin kind On reload
Indicators Indicators on open charts switch to the new build in place.
Strategies The next strategy you start uses the new build. A strategy that is already running keeps the build it started with until it stops.
Bar types, drawing tools, Market Analyzer columns The new build is used for bar types, drawings and columns you add from then on.
Venue plugins A venue that is not connected uses the new build straight away; a connected venue switches at its next connect.
Add-ons The previous build's windows close and its IAddOn.Shutdown runs, then the new build is initialised.
A failed build keeps the previous one. If a rebuilt DLL fails to load, the platform logs the error and keeps the previous build registered. The platform loads a copy of each DLL, so the file in the plugin folder is never locked and your build can always overwrite it.

What gets discovered

The platform catalogs each DLL's types by the contracts they implement. There is no wiring code to write: implement the right contract and the type appears; implement two and it appears in two places. The table maps each contract to where the type shows up, with the chapter that explains how to build it.

Implement this Where it appears Chapter
IIndicator (usually through IndicatorBase) The indicator picker Indicators
A subclass of Strategy The strategy list Strategies
A subclass of BarSpecification, plus its ITickBarBuilder or IDerivedBarBuilder The bar type picker Bar types
IDrawingTool (usually through DrawingToolBase) with [DrawingToolMetadata] The drawing toolbar Drawing tools
IColumnDefinition The Market Analyzer column picker Market Analyzer
IVenuePlugin The Connections dialog, one entry per IVenueDescriptor Venue plugins
IAddOn The Control Center menu entries its window kinds declare Add-ons

Discovery rules

A type is registered only when it meets the rules for its kind. A type that fails a rule is skipped without an error line in the log, so these rules explain most "my plugin does not show up" cases.

  • Public. Not internal. A public nested type counts for every kind except strategies, which must be top-level public classes.
  • Concrete. Not abstract, not an interface, not an open generic type.
  • Constructible without arguments. The platform creates instances before it applies parameter values, so the type needs a public constructor it can call with no arguments.
    • Indicators, bar specifications, Market Analyzer columns, venue plugins and add-ons: a parameterless constructor, or one whose parameters all have default values.
    • Strategies and drawing tools: a public parameterless constructor. A constructor whose parameters all have defaults does not count. A drawing tool with [DrawingToolMetadata] but no parameterless constructor is left out of the toolbar, and the Plugins log names the type.
    • Bar builders: a public constructor taking the bar specification, (TSpec) or (TSpec, double tickSize). Add [BarBuilderFor(typeof(TSpec))] when a builder has constructors for more than one specification type.
  • Implements a recognised contract from the table above.
"All optional" counts as no arguments for indicators. A constructor like MyIndicator(IIndicator? parent = null, ISeries<double>? input = null) can be called with no arguments, so it passes; this is the convention the built-in indicators use. A constructor with a required parameter (MyIndicator(int period)) fails the check and the type is skipped.

The example puts the rules side by side. The first type meets all of them and is discovered; the other two each break one rule and are skipped.

C#: discovered and skippedusing SabrTrader.Pipeline.Indicators;

// Discovered: public, concrete, parameterless ctor, implements IIndicator through IndicatorBase.
public sealed class MyIndicator : IndicatorBase
{
    public MyIndicator() { }
}

// Skipped: the only ctor needs an argument.
public sealed class Broken : IndicatorBase
{
    public Broken(int period) { }
}

// Skipped: internal type.
internal sealed class Hidden : IndicatorBase { }
Parameters. A constructor without arguments does not limit your inputs. Indicators expose settings as properties marked [IndicatorParameter]; strategies declare them with IntParameter, DoubleParameter and the other parameter methods in OnInitialize. The platform sets the values after construction. See the indicator and strategy parameter pages.