Your first plugin

Getting started

Your first plugin

Create the project, write a working indicator, build it, deploy it, and see it on a chart.

Create the project

A plugin is a normal class library. Create one and add the SDK package. This page builds an indicator because it is the quickest result to see on screen; the project shape is the same for every plugin kind.

shelldotnet new classlib -n MyFirstPlugin -f net10.0
cd MyFirstPlugin
dotnet add package SabrTrader.Sdk

Open the generated .csproj and make it look like the one below. DeploySabrTraderPlugin is optional but worth setting now: it switches on an MSBuild target from the SDK package that copies your built DLL into the plugin folder on every build.

MyFirstPlugin.csproj<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <LangVersion>latest</LangVersion>

    <!-- Copy the built DLL into Documents\SabrTrader\Plugins on every build. -->
    <DeploySabrTraderPlugin>true</DeploySabrTraderPlugin>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="SabrTrader.Sdk" Version="0.18.0" />
  </ItemGroup>

</Project>
Deploy folder. The target copies to SabrTrader\Plugins in your real Documents folder, including a Documents folder redirected to OneDrive or a network share. Set <SabrTraderPluginsFolder> to deploy somewhere else; see Where to deploy.
No UI framework needed. Indicators draw through the SDK's renderer interfaces, and add-ons and chart panels declare their UI from SDK panel elements, so plain net10.0 covers every plugin kind. Target net10.0-windows only if you choose to use WPF types yourself.

Write the indicator

Create MedianPrice.cs with the code below. It is a complete, working indicator that plots each bar's median price, the midpoint between high and low. The Indicators chapter explains each part in detail. The shape is a writable output series, a constructor that registers a plot, and two lifecycle methods that fill the series: once over history, then once per closed live bar.

MedianPrice.csusing SabrTrader.Pipeline.Indicators;
using SabrTrader.Pipeline.Plots;
using SabrTrader.Pipeline.Series;

namespace MyFirstPlugin;

[IndicatorDescription("Median price: the (high + low) / 2 midpoint of each bar.")]
public sealed class MedianPrice : IndicatorBase
{
    // The indicator owns the writable backing store; the plot reads it.
    private readonly ChunkedSeries<double> _output = new();

    // Canonical ctor shape: parent for child composition (null = standalone),
    // input for an explicit source series. The host calls this, then applies settings.
    public MedianPrice(IIndicator? parent = null, ISeries<double>? input = null)
        : base(parent, input)
    {
        // Register one plotted line. AddPlot is called once, from the ctor.
        AddPlot(new Plot("Median", _output, PlotStyle.Line, new ChartColor(91, 157, 255), 1.5));
    }

    // History: one pass over the whole backfill, oldest bar first so values
    // land in chronological order (i is barsAgo: Count-1 = oldest, 0 = newest).
    public override void OnDataLoaded(IIndicatorContext ctx)
    {
        var bars = ctx.Bars(0);
        for (int i = bars.Count - 1; i >= 0; i--)
            _output.Append((bars[i].High + bars[i].Low) / 2.0);
    }

    // Live: one new value each time a bar closes.
    public override void OnBarUpdate(IIndicatorContext ctx)
    {
        var b = ctx.Bars(0)[0];
        _output.Append((b.High + b.Low) / 2.0);
    }
}

That is the whole plugin. There is no registration code and no configuration: the platform finds a public class deriving from IndicatorBase and registers it. The [IndicatorDescription] text is the description users read in the indicator picker.

The pieces. OnDataLoaded and OnBarUpdate are virtual lifecycle methods on IndicatorBase; override the ones you need. ChunkedSeries<double> is the SDK's writable series: Append adds a value in constant time, and double.NaN values render as gaps. You hand the series to a Plot, and the chart reads it from there.

Build & deploy

Build the project. With DeploySabrTraderPlugin set to true, the build copies MyFirstPlugin.dll (and its PDB) into the plugin folder and logs where it went.

shelldotnet build -c Release
build logSabrTrader.Sdk: deploying plugin 'MyFirstPlugin.dll' to 'C:\Users\you\Documents\SabrTrader\Plugins'

To deploy by hand, copy bin\Release\net10.0\MyFirstPlugin.dll into Documents\SabrTrader\Plugins. The Building & deploying chapter covers the folder and what else may go in it.

See it on a chart

SabrTrader watches the plugin folder, so it does not matter whether it is running when you deploy. A DLL that is present at startup loads during startup; a DLL copied or rebuilt while the platform runs loads within a second or so of the copy finishing.

  1. Build (or copy the DLL) as above.
  2. Open a chart, open the indicator picker, and find MedianPrice in the list. Its description is the text from [IndicatorDescription].
  3. Add it. A blue median line is drawn over the bars, on history and live.
  4. Change the code and build again. The indicator on the open chart switches to the new build without a restart.
If it does not appear. Open the Control Center Log tab and look for lines in the Plugins category. The platform logs every load, reload and registration error there, naming the DLL or type involved. The Troubleshooting page lists the common causes.