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. This is the full round-trip — about ten minutes end to end.

Create the project

A plugin is a normal class library. Create one and add the SDK package. We will build an indicator here because it is the quickest thing to see on screen, but the project shape is identical for every plugin kind.

shelldotnet new classlib -n MyFirstPlugin -f net10.0
cd MyFirstPlugin
dotnet add package TradeStrike.Sdk --version 0.1.0

Open the generated .csproj and make it look like the one below. The two DeployToAlgoStudioPlugins properties are optional but worth setting now: they come from an MSBuild target inside the SDK package and copy your built DLL straight into the host's Plugins folder on every build, so you never copy files by hand while developing.

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

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

    <!-- Copy the built DLL into the host's Plugins folder on every build. -->
    <DeployToAlgoStudioPlugins>true</DeployToAlgoStudioPlugins>
    <!-- Override the destination if you don't use the default %AppData% folder. -->
    <AlgoStudioProPluginsFolder>C:\Program Files\TradeStrike\Plugins</AlgoStudioProPluginsFolder>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="TradeStrike.Sdk" Version="0.1.0" />
  </ItemGroup>

</Project>
Default deploy folder. If you leave AlgoStudioProPluginsFolder out, the target deploys to %AppData%\AlgoStudioPro\Plugins. Set it explicitly when your host lives elsewhere — see Where to deploy.
Need WPF? If your plugin draws on the chart with WPF types, target net10.0-windows and add <UseWPF>true</UseWPF>. Most indicators and all strategies, bar types and data providers do not need WPF, so stay on plain net10.0 unless you hit a reason to switch.

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. Read it once now; the Indicators chapter explains every line in detail, but the shape is already worth recognising: 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 TradeStrike.Pipeline.Indicators;
using TradeStrike.Pipeline.Plots;
using TradeStrike.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 entire plugin. Notice what is not there: no registration code, no manifest, no host configuration. Discovery is purely by type — the loader sees a public class deriving from IndicatorBase and registers it. The [IndicatorDescription] text becomes the blurb users read in the Add-Indicator dialog.

Why these methods. OnDataLoaded and OnBarUpdate are virtual lifecycle hooks on IndicatorBase; you override only the ones you need. ChunkedSeries<double> is the SDK's writable, append-only series — appends are O(1) and NaN-aware, so warmup bars render as gaps. You hand it to a Plot and the chart reads it; you never expose it directly.

Build & deploy

Build in Release. Because we set DeployToAlgoStudioPlugins=true, the build copies MyFirstPlugin.dll into the host's Plugins folder and logs where it went.

shelldotnet build -c Release
build logTradeStrike.Sdk: deploying plugin 'MyFirstPlugin.dll' to 'C:\Program Files\TradeStrike\Plugins'

If you would rather copy the file yourself, that is fine too — just remember the one rule: copy only the plugin DLL, never its dependencies or .deps.json. The exact folder and the reasoning behind that rule are covered in the Building & deploying chapter.

See it on a chart

Plugins are scanned once, at startup, so the workflow is "build, then relaunch". After that your indicator behaves exactly like a built-in one.

  1. Close TradeStrike if it is running.
  2. Launch it. During startup the plugin loader scans the Plugins folder and registers your indicator into the shared catalog.
  3. Open a chart, click Add Indicator, and find MedianPrice in the list — its description is the text from [IndicatorDescription].
  4. Add it. A blue median line is drawn over your candles, on history and live.
If it doesn't appear. Open the Control Center Log tab and look for lines tagged Plugins. The loader records every load and registration there, so a missing dependency or a wrongly-deployed contract DLL is visible immediately. The Troubleshooting page lists the common causes.