Position Sizer API
A Position Sizer Extension determines the quantity of shares, contracts, or other units to assign to a Transaction during a WealthLab 9 backtest. A Position Sizer has access to the current and historical equity and cash levels of the simulation, open and closed Positions, Transactions being processed, and other information that can influence the sizing decision. Position Sizers are available in the Position Sizing section of the Strategy Settings.
Build Environment
You can create an Advanced Position Sizer in a .NET development tool such as Visual Studio 2026.
Create a class library project that targets .NET10, then reference the WealthLab.Core library DLL that you'll find in the WL9 installation folder.
Your Advanced Position Sizer will be a class in this library that descends from PositionSizerBase, which is defined in the WealthLab.Core library, in the WealthLab.Backtest 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 Advanced Position Sizer, making it available in appropriate locations of the WL9 user interface.

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
Override the following properties to describe your Position Sizer and indicate which features it supports.
Name
public abstract string Name
Return the descriptive name of the Position Sizer. WealthLab displays this name in the Position Sizing selector in Strategy Settings.
Description
public virtual string Description
Return a brief description of how the Position Sizer works. WealthLab displays this description when the user selects or configures the Position Sizer.
UsesBasisPrice
public virtual bool UsesBasisPrice
Return true if the Position Sizer should allow the user to select the basis price used when calculating position size. For Market orders, the user can select either:
- Current bar closing price
- Next bar opening price
If UsesBasisPrice returns false, this option is hidden from the Position Sizing interface.
UsesMaxRiskPct
public virtual bool UsesMaxRiskPct
Return true if your Position Sizer uses the Max Risk Percent sizing mechanism. This allows WealthLab to automatically issue a Stop Loss order at the Transaction's RiskStopLevel when the corresponding Trading Preference is enabled.
GenerateParameters
protected virtual void GenerateParameters()
Override this method to define Parameters that configure your Position Sizer. Add the appropriate Parameter instances to the inherited Parameters collection. PositionSizerBase derives from Configurable, so Position Sizers use the standard WealthLab Parameter configuration framework.
Sizing Positions
Initialize
public virtual void Initialize()
WealthLab calls this method before it begins sizing Positions. Override it to perform one-time initialization, such as reading configured Parameter values into local fields.
SizePosition
public abstract double SizePosition(
Transaction t,
BarHistory bars,
int idx,
double basisPrice,
double equity,
double cash)
WealthLab calls SizePosition each time it needs to determine the quantity for a Transaction. Return the desired position size as a double. The parameters provide:
- t - The Transaction being sized.
- bars - The BarHistory associated with the Transaction.
- idx - The current index in the BarHistory.
- basisPrice - The price WealthLab should use as the basis for sizing.
- equity - Current simulated account equity.
- cash - Current simulated available cash.
The basisPrice depends on the order type. For a Market order, it is based on the Position Sizing setting selected by the user:
- Current bar closing price
- Next bar opening price
For Limit and Stop orders, the basis price is the Limit or Stop price. Use these values together with the simulation-related properties described below to calculate and return the desired quantity. Returning zero prevents the Transaction from being taken.
Simulation-Related Properties
PositionSizerBase exposes information about the current state of the backtest.
EquityCurve
public TimeSeries EquityCurve
Contains the simulated account equity over time. The series is populated only through the point in the simulation at which the current Transaction is being sized.
CashCurve
public TimeSeries CashCurve
Contains the available simulated cash over time.
DrawdownCurve
public TimeSeries DrawdownCurve
Contains the simulated account drawdown over time. Drawdown represents the peak-to-trough decline in the equity curve and is calculated on a closing-price basis.
DrawdownPctCurve
public TimeSeries DrawdownPctCurve
Contains the percentage drawdown of the simulated account over time.
Orders
public List<Transaction> Orders
Contains Transactions that have already been sized and processed on the current bar. The collection can include both entry and exit orders.
OpenPositions
public List<Position> OpenPositions
Contains all Positions that are currently open in the simulation.
ClosedPositions
public List<Position> ClosedPositions
Contains all Positions that have already been closed.
Positions
public List<Position> Positions
Contains all Positions in the simulation, both open and closed.
Candidates
public List<Transaction> Candidates
Contains all entry Transactions currently being processed for position sizing on the current bar. This can be useful for Position Sizers that need to allocate capital among multiple simultaneous entry Signals.
Helper Methods
CalculatePositionSize
public double CalculatePositionSize(
PositionSizeTypes pst,
double value,
BarHistory bars,
double basisPrice,
double equity,
int? idx)
Calculates a position size using one of WealthLab's standard Position Sizing methods. The pst parameter specifies the sizing method. Supported PositionSizeTypes include:
- Dollar - Allocate a fixed amount of currency specified by value.
- Quantity - Use a fixed number of shares or contracts specified by value.
- PctOfEquity - Allocate the percentage of current simulated equity specified by value.
You will typically call this method from SizePosition, passing along the bars, basisPrice, equity, and idx values supplied by WealthLab. For example:
return CalculatePositionSize(
PositionSizeTypes.PctOfEquity,
10.0,
bars,
basisPrice,
equity,
idx);
UseFuturesMode
public bool UseFuturesMode(BarHistory bars)
Returns true if Futures Mode should be used for the specified BarHistory. When Futures Mode applies, sizing logic can take advantage of contract-specific information available through:
bars.SymbolInfo
Important properties include:
- PointValue
- Margin
- TickSize
The Margin property is particularly important because it determines how much capital is required to enter one contract. For example, a Position Sizer allocating $10,000 might use:
if (UseFuturesMode(bars))
return 10000.0 / bars.SymbolInfo.Margin;
else
return 10000.0 / basisPrice;
BasicPositionSizer
If your Position Sizer builds on WealthLab's standard sizing choices, derive from BasicPositionSizer instead of PositionSizerBase. BasicPositionSizer automatically provides two Parameters:
- Position Size Type - A StringChoice containing the standard sizing methods.
- Amount - A Double containing the sizing amount.
The standard methods are:
- Fixed Dollar amount
- Fixed Quantity
- Percent of Equity
BasicPositionSizer also implements Initialize to read the configured values and SizePosition to calculate the appropriate quantity using CalculatePositionSize. Its SizePosition implementation follows this pattern:
public override double SizePosition(
Transaction t,
BarHistory bars,
int idx,
double basisPrice,
double equity,
double cash)
{
return CalculatePositionSize(
_posSizeType,
_amount,
bars,
basisPrice,
equity,
idx);
}
Derive from BasicPositionSizer when you want to preserve WealthLab's standard sizing choices while adding additional rules or restrictions.
Example: Max Entries per Bar
The following Position Sizer derives from BasicPositionSizer. It retains the standard Position Sizing choices but returns a size of zero when the number of entry Transactions exceeds a configured maximum. For intraday Strategies, it can optionally apply the maximum across the entire trading day rather than separately to each bar.
using System.Linq;
using WealthLab.Core;
namespace WealthLab.Backtest
{
public class MaxEntriesPerBar : BasicPositionSizer
{
public override void GenerateParameters()
{
base.GenerateParameters();
Parameters.Add(
new Parameter(
"Max Entries",
ParameterType.Int32,
2,
1.0,
999999999.0));
Parameters.Add(
new Parameter(
"For intraday trades, sum up positions opened during the day",
ParameterType.Boolean,
false));
}
public override string Name =>
"Max Entries per Bar";
public override string Description =>
"Provides the basic Position Sizing options, " +
"with the additional ability to limit the " +
"number of entries taken on each bar or day.";
public override void Initialize()
{
base.Initialize();
_maxEntries =
Parameters[2].AsInt;
_considerIntraday =
Parameters[3].AsBoolean;
}
public override double SizePosition(
Transaction t,
BarHistory bars,
int idx,
double basisPrice,
double equity,
double cash)
{
int count = 0;
if (!_considerIntraday)
{
foreach (Transaction o in Orders)
{
if (o.TransactionType.IsEntry())
count++;
}
}
else
{
if (t.Bars.Scale.IsIntraday)
{
var positionsInSymbolOpenedToday =
Positions
.AsParallel()
.AsOrdered()
.Reverse()
.TakeWhile(p =>
p.EntryDate.DayOfYear ==
t.EntryDate.DayOfYear &&
p.Symbol == t.Symbol);
count +=
positionsInSymbolOpenedToday.Count();
}
}
if (count >= _maxEntries)
return 0.0;
return base.SizePosition(
t,
bars,
idx,
basisPrice,
equity,
cash);
}
private int _maxEntries;
private bool _considerIntraday;
}
}
This pattern is useful when you want to retain WealthLab's standard sizing calculations while adding portfolio-level rules that can reject or modify individual entry Signals.