Clone our Wealth-Lab 8 Extension Demo project on GitHub to get a head start in developing your own Extensions!

Series Plot Style Extension API

A Series Plot Style Extension determines how a TimeSeries, such as an Indicator, is rendered on a WealthLab 9 chart. Common Plot Styles include:

  • Line
  • Histogram
  • Dots

Build Environment

You can create a Plot Style in a .NET development tool such as Visual Studio 2026. Create a class library project that targets .NET10, then reference the WealthLab.ChartWPF library DLL that you'll find in the WL9 installation folder.

Your Plot Style will be a class in this library that descends from SeriesStyleBase, which is defined in the WealthLab.ChartWPF library, in the WealthLab.ChartWPF namespace. After you implement and build your library, simply copy the resulting assembly DLL into the WL9 installation folder. The next time WL9 starts up, it will discover your Plot Style, making it available in appropriate locations of the WL9 user interface.

Visual Studio 2026 Build Environment

SeriesStyleBase derives from PlotBase. Consult the PlotBase class reference for additional properties and methods available to Series Plot Styles.

Accessing the Host (WL9) Environment

The IHost interface provides access to the current WealthLab environment. Extensions can use it to retrieve application-level information and services, such as the location of the user's WealthLab data folder or the DataSets defined by the user.

You can access the current IHost instance from anywhere in your extension through the WLHost singleton and its Instance property. For example, the following code retrieves the path to the user's WealthLab data folder:

string folder = WLHost.Instance.DataFolder;

Use WLHost.Instance whenever your extension needs access to functionality exposed by the IHost interface.

Descriptive Properties and Parameters

SeriesStyleBase ultimately derives from Configurable, which provides the standard WealthLab configuration framework. Override Configurable properties such as:

  • Name - The name displayed for the Plot Style.
  • GlyphResource - The icon used to represent the Plot Style.

GenerateParameters

public virtual void GenerateParameters()

Override this method to define Parameters that allow the user to configure your Plot Style. SeriesStyleBase already provides some standard Parameters, so call the base implementation before adding your own:

public override void GenerateParameters()
{
    base.GenerateParameters();

    // Add custom Parameters here.
}

Color

public WLColor Color

SeriesStyleBase provides a standard Parameter named Color. The Color property's getter obtains its value from this Parameter, and the setter updates the Parameter. If your Plot Style uses the Color property, do not remove the standard Color Parameter. When overriding GenerateParameters, call:

base.GenerateParameters();

before adding additional Parameters to ensure that the standard Color Parameter remains available.

Accessing the CoreChart

public CoreChart Chart

This property is inherited from PlotBase and returns the CoreChart instance on which the Plot Style is being rendered. Two especially important CoreChart properties are:

  • Chart.StartIndex - The first BarHistory index currently visible on the chart.
  • Chart.EndIndex - The last BarHistory index currently visible on the chart.

Use these values to limit rendering to the visible portion of the chart.

Accessing the Source Series

public TimeSeries Series

Returns the TimeSeries being rendered by the Plot Style. The Series is synchronized with the BarHistory displayed by the chart. Its DateTimes and Values correspond to the bars in:

Chart.Bars

Use the Series indexer to retrieve the value to render for a particular chart index:

double value = Series[idx];

Rendering the Plot Style

public abstract void Render(DrawingContext dc)

Override this method to render your Plot Style onto the WPF DrawingContext supplied in dc. A typical implementation:

  1. Loops from Chart.StartIndex through Chart.EndIndex.
  2. Obtains each value from the source Series.
  3. Uses ConvertIndexToX to convert the bar index to an x-coordinate.
  4. Uses ConvertValueToY to convert the TimeSeries value to a y-coordinate.
  5. Draws the resulting graphical elements onto the DrawingContext.

For example:

for (int n = Chart.StartIndex;
    n <= Chart.EndIndex;
    n++)
{
    if (Double.IsNaN(Series[n]))
        continue;

    double x =
        ConvertIndexToX(n);

    double y =
        ConvertValueToY(Series[n]);

    // Render the point at x, y.
}

Use PenBrushFactory to obtain WPF Pen and Brush instances using WealthLab colors and line styles.

Determining the Color of a Data Point

public override WLColor GetBarColor(int idx)

Returns the color that should be used to render the Series value at index idx. The default color is based on the Plot Style's Color property. However, a plotted TimeSeries can contain custom colors assigned to individual values, for example by Strategy code or by an Indicator's SeriesBarColors collection. Use GetBarColor when your Plot Style should respect these custom colors.

Overriding the Plot Pane

public virtual string OverridePlotPane

Override this property if the Plot Style should always render in a specific chart pane, regardless of the pane normally associated with the source Series. Common return values include:

Price
Volume

For example, the BooleanDots Plot Style returns "Price" so that its dots are always rendered in the Price Pane, even when the source Indicator normally appears in its own pane. Leave this property unchanged when the Plot Style should use the pane selected for the source Series.

Highlight Rendering

public override void RenderHighlight(
    DrawingContext dc)

WealthLab calls this method when the user moves the mouse over the plotted Series. The default implementation renders a thick, translucent highlight over the plot. Override this method if your Plot Style requires different highlighting behavior.

Companion Indicators

public bool IsCompanionPlotted

Some Indicators are composed of two related Indicator series. Examples include:

  • Bollinger Bands
  • Keltner Bands

Each Indicator in such a pair can identify the other as its BandCompanion. Certain Plot Styles, particularly Bands, render both series together. IsCompanionPlotted returns true if the companion Indicator has already been rendered. Use this property to avoid rendering the same combined visualization twice. If the source Series is an Indicator, you can access its companion by casting Series to IndicatorBase:

IndicatorBase indicator =
    Series as IndicatorBase;

IndicatorBase companion =
    indicator?.BandCompanion;

Example: Line Plot Style

The following is the implementation of the standard Line Plot Style. It demonstrates:

  • Adding custom Parameters
  • Preserving the standard Color Parameter
  • Rendering only visible values
  • Using StreamGeometry for efficient rendering
  • Respecting custom Series colors
  • Rendering the partial streaming value
using WealthLab.Core;
using WealthLab.WPF;
using System.Windows;
using System.Windows.Media;

namespace WealthLab.ChartWPF
{
    public class LineSeriesStyle : SeriesStyleBase
    {
        // Add Plot Style Parameters
        public override void GenerateParameters()
        {
            base.GenerateParameters();

            Parameters.Add(
                new Parameter(
                    "Thickness",
                    ParameterType.Int32,
                    2));

            Parameters.Add(
                new Parameter(
                    "Line Style",
                    ParameterType.LineStyle,
                    LineStyle.Solid));
        }

        // Name
        public override string Name =>
            "Line";

        // Glyph
        public override string GlyphResource =>
            "WealthLab.ChartWPF.Glyphs.Line.png";

        // Line thickness
        public int LineThickness
        {
            get
            {
                return Parameters
                    .FindName("Thickness")
                    .AsInt;
            }
            set
            {
                Parameter p =
                    Parameters.FindName(
                        "Thickness");

                p.DefaultValue = value;
                p.Value = value;
            }
        }

        // Line style
        public LineStyle LineStyle
        {
            get
            {
                Parameter p =
                    Parameters.FindName(
                        "Line Style");

                if (p == null)
                    return LineStyle.Solid;

                return p.AsLineStyle;
            }
            set
            {
                Parameter p =
                    Parameters.FindName(
                        "Line Style");

                p.DefaultValue = value;
                p.Value = value;
            }
        }

        // Render
        public override void Render(
            DrawingContext dc)
        {
            if (LineThickness <= 0)
                return;

            RenderLine(
                dc,
                Chart.StartIndex,
                Chart.EndIndex);
        }

        // Render a line
        protected void RenderLine(
            DrawingContext dc,
            int startIdx,
            int endIdx)
        {
            StreamGeometry sg =
                new StreamGeometry();

            StreamGeometryContext sgc =
                sg.Open();

            WLColor c = Color;

            Pen pen =
                PenBrushFactory.GetPen(
                    c,
                    LineThickness,
                    LineStyle);

            // Faster rendering when the Series
            // does not contain custom colors.
            if (Series.SeriesBarColors == null)
            {
                bool first = true;

                for (int n = startIdx;
                    n <= endIdx;
                    n++)
                {
                    if (Double.IsNaN(Series[n]))
                        continue;

                    if (n < Series.FirstValidIndex)
                        continue;

                    double xCoord =
                        ConvertIndexToX(n);

                    double yData =
                        ConvertValueToY(
                            Series[n]);

                    if (first)
                    {
                        sgc.BeginFigure(
                            new Point(
                                xCoord,
                                yData),
                            false,
                            false);

                        first = false;
                    }
                    else
                    {
                        sgc.LineTo(
                            new Point(
                                xCoord,
                                yData),
                            true,
                            true);
                    }
                }

                RenderStreamingBarLine(sgc);

                sgc.Close();

                dc.DrawGeometry(
                    null,
                    pen,
                    sg);
            }
            else
            {
                bool first = true;

                WLColor lastColor =
                    WLColor.Empty;

                for (int n = startIdx;
                    n <= endIdx;
                    n++)
                {
                    if (Double.IsNaN(Series[n]))
                        continue;

                    if (n < Series.FirstValidIndex)
                        continue;

                    double xCoord =
                        ConvertIndexToX(n);

                    double yData =
                        ConvertValueToY(
                            Series[n]);

                    c = GetBarColor(n);

                    Point pt =
                        new Point(
                            xCoord,
                            yData);

                    if (c != lastColor)
                    {
                        if (!first)
                        {
                            sgc.LineTo(
                                pt,
                                true,
                                true);

                            sgc.Close();

                            pen =
                                PenBrushFactory
                                    .GetPen(
                                        lastColor,
                                        LineThickness,
                                        LineStyle);

                            dc.DrawGeometry(
                                null,
                                pen,
                                sg);

                            sg =
                                new StreamGeometry();

                            sgc = sg.Open();
                        }

                        sgc.BeginFigure(
                            pt,
                            false,
                            false);

                        lastColor = c;
                        first = false;
                    }
                    else
                    {
                        sgc.LineTo(
                            pt,
                            true,
                            true);
                    }
                }

                RenderStreamingBarLine(sgc);

                sgc.Close();

                pen =
                    PenBrushFactory.GetPen(
                        lastColor,
                        LineThickness,
                        LineStyle);

                dc.DrawGeometry(
                    null,
                    pen,
                    sg);
            }
        }

        // Render the streaming portion
        // of the line.
        protected void RenderStreamingBarLine(
            StreamGeometryContext sgc)
        {
            if (LineThickness <= 0)
                return;

            if (Chart.ShouldStreamingBarBeRendered &&
                !Double.IsNaN(
                    Series.StreamingValue))
            {
                double xCoord =
                    Chart.StreamingBarPlotX;

                double yCoord =
                    ConvertValueToY(
                        Series.StreamingValue);

                Point pt =
                    new Point(
                        xCoord,
                        yCoord);

                sgc.LineTo(
                    pt,
                    true,
                    true);
            }
        }
    }
}