Chart Style Extension API
A Chart Style Extension controls how open, high, low, and close (OHLC) price data is rendered on WealthLab 9 charts. Common Chart Styles include:
- Bar
- Candlestick
- Line
Build Environment
You can create a Chart 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 Chart Style will be a class in this library that descends from ChartStyleBase, 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 Chart Style, making it available in appropriate locations of the WL9 user interface.

ChartStyleBase derives from PlotBase. Consult the PlotBase class reference for additional properties and methods available to Chart 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.
Configuring a Chart Style
ChartStyleBase derives from Configurable, which provides the standard WealthLab configuration framework. By default, ChartStyleBase uses a ConfigurableType of ParameterListType, so Chart Styles are configured using Parameter instances contained in a ParameterList. Define your Chart Style's configurable Parameters by overriding GenerateParameters, as described in the Configurable class reference.
Descriptive Properties
The Configurable base class provides descriptive properties that determine how your Chart Style appears in WealthLab. The most important properties to override are:
- Name - The name displayed for the Chart Style.
- GlyphResource - The icon used to represent the Chart Style.
Accessing the CoreChart
public CoreChart Chart
This property is inherited from PlotBase and returns the underlying CoreChart instance on which the Chart Style is being rendered. Several CoreChart properties are particularly useful when implementing a Chart Style, including:
- StartIndex - The index of the first BarHistory bar currently visible at the left edge of the chart.
- EndIndex - The index of the last BarHistory bar currently visible at the right edge of the chart.
These values allow your rendering code to process only the portion of the BarHistory that is currently visible.
Initialization and Bar Width
public virtual void Initialize(BarHistory bars)
Override this method to perform any initialization required by your Chart Style. WealthLab calls Initialize whenever the BarHistory being charted changes. The new BarHistory instance is supplied in the bars parameter.
Fixed and Variable Width Styles
public virtual bool IsSimpleStyle
Chart Styles can use either fixed or variable bar widths. Most common styles, including Candlestick, Bar, and Line, use a fixed width where each bar occupies the same amount of horizontal chart space. More specialized styles, such as Kagi and Point & Figure, can use variable widths. Individual bars can occupy different amounts of horizontal space, and some bars can have a width of zero.
For a conventional fixed-width Chart Style, return true. If your Chart Style requires variable bar widths, return false and implement the additional bar-width methods described below.
public virtual double GetBarWidth(int idx)
For a variable-width Chart Style, override this method to return the width, in pixels, of the bar at index idx. Returning zero is valid for Chart Styles that render only a subset of the source BarHistory.
public virtual int CalculateBarSpacings()
WealthLab calls this method when conditions affecting horizontal bar placement change, including when:
- The configured chart bar spacing changes.
- The underlying BarHistory changes.
- The chart is scrolled.
Override this method if your Chart Style needs to recalculate internal data used to determine variable bar widths or positions. After performing your own calculations, call the base implementation:
base.CalculateBarSpacings();
The base implementation works backward from the right edge of the chart, summing bar widths to determine the first bar that needs to be rendered.
Rendering the Chart Style
public abstract void Render(DrawingContext dc)
Override this method to render your Chart Style onto the WPF DrawingContext supplied in dc. A typical implementation performs the following operations:
- Loops through the visible bars in Bars, from
Chart.StartIndexthroughChart.EndIndex. - Uses ConvertIndexToX to convert a BarHistory index into an x-coordinate.
- Uses ConvertValueToY to convert a price into a y-coordinate.
- Uses the DrawingContext methods to draw the resulting chart elements.
- Uses PenBrushFactory to obtain WPF Pen and Brush instances based on WealthLab colors.
For example:
for (int n = Chart.StartIndex; n <= Chart.EndIndex; n++)
{
double x = ConvertIndexToX(n);
double y = ConvertValueToY(Bars.Close[n]);
// render chart element here
}
Determining Bar Color
public override WLColor GetBarColor(int idx)
Returns the color that should be used to render the bar at index idx. The resulting color takes into account the active ChartPreferences as well as any bar color changes made by Strategy code. Use this method when your Chart Style should respect custom bar colors assigned by a Strategy.
Rendering the Streaming Bar
public virtual void RenderStreamingBar(DrawingContext dc)
Override this method to render the current partial streaming bar. The following properties provide the information needed to render it:
- Chart.StreamingBarColor - The color assigned to the streaming bar.
- Chart.StreamingBarPlotX - The x-coordinate at which the streaming bar should be rendered.
- Bars.StreamingBar - A BarData instance containing the current streaming bar's OHLC/V values.
The StreamingBar represents the currently forming bar and is therefore separate from the completed bars normally processed by Render.
Rendering as a Line
protected void RenderAsLine(DrawingContext dc)
Call this helper from Render to render the price data using a simple Line-style representation. Basic Chart Styles such as Candlestick and Bar can use this optimization when bars are compressed to a very small horizontal spacing. For example:
if (ChartPreferences.BarSpacing <= 2 &&
!ChartPreferences.DisableRenderingOptimization)
{
RenderAsLine(dc);
return;
}
This allows a Chart Style to collapse gracefully as the user reduces bar spacing and can significantly improve rendering performance when many bars are visible.
Example: Heikin Ashi Chart Style
The following is a complete implementation of the Heikin Ashi Chart Style:
using WealthLab.WPF;
using System.Windows;
using System.Windows.Media;
using WealthLab.Core;
namespace WealthLab.ChartWPF
{
public class HeikinAshiChartStyle : ChartStyleBase
{
public override string Name => "Heikin Ashi";
public override bool IsSimpleStyle => true;
public override string GlyphResource =>
"WealthLab.ChartWPF.Glyphs.HeikinAshi.png";
public override bool DisableGlyphReverse => true;
public override void Render(DrawingContext dc)
{
if (ChartPreferences.BarSpacing <= 2 &&
!ChartPreferences.DisableRenderingOptimization)
{
RenderAsLine(dc);
return;
}
BarHistory ha = HeikinAshi.Convert(Bars);
Brush bkg = PenBrushFactory.GetBrush(
ChartPreferences.ColorBackground);
for (int n = Chart.StartIndex;
n <= Chart.EndIndex;
n++)
{
if (Double.IsNaN(ha.Close[n]))
continue;
WLColor c;
if (ha.Close[n] >= ha.Open[n])
c = ChartPreferences.ColorUpBar;
else
c = ChartPreferences.ColorDownBar;
double xCoord = ConvertIndexToX(n);
double yHigh = ConvertValueToY(ha.High[n]);
double yLow = ConvertValueToY(ha.Low[n]);
Pen pen = PenBrushFactory.GetPen(c, 1);
dc.DrawLine(
pen,
new Point(xCoord, yHigh),
new Point(xCoord, yLow));
double tickSize =
ChartPreferences.BarSpacing / 2.0 - 1.0;
if (tickSize < 1)
tickSize = 1;
double yOpen = ConvertValueToY(ha.Open[n]);
double yClose = ConvertValueToY(ha.Close[n]);
double height = Math.Abs(yOpen - yClose);
if (height < 1.0)
height = 1.0;
double width = tickSize * 2.0;
double x = xCoord - tickSize;
if (ha.Close[n] >= ha.Open[n])
{
Rect rect =
new Rect(x, yClose, width, height);
dc.DrawRectangle(
bkg,
PenBrushFactory.GetPen(c, 1),
rect);
}
else
{
Rect rect =
new Rect(x, yOpen, width, height);
dc.DrawRectangle(
PenBrushFactory.GetBrush(c),
null,
rect);
}
}
}
}
}