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:
-
Build your plugin project (
dotnet build, or build in your IDE). - 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.
-
Check the result in the running platform. The Control Center Log tab shows a
Pluginsline 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. |
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.
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 { }
[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.