PositionSizing 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package PositionSizing --version 1.0.0
                    
NuGet\Install-Package PositionSizing -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PositionSizing" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PositionSizing" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="PositionSizing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PositionSizing --version 1.0.0
                    
#r "nuget: PositionSizing, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PositionSizing@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PositionSizing&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=PositionSizing&version=1.0.0
                    
Install as a Cake Tool

PositionSizing

A small, dependency-free .NET library covering the questions every systematic trading strategy has to answer on every trade — not just "how big should this bet be," but the whole arc from placing the initial stop, through sizing, through managing the stop while the trade is open, to grading the outcome once it's closed.

It has no dependencies beyond the .NET base class library, and no notion of a broker, a market, or a strategy — just the arithmetic. Reference it as a normal package, or copy the files you need directly into your project.

What's in it

Placing the initial stop and target

TargetPriceCalculator — places a stop-loss and take-profit level from an entry price, a volatility measure (typically ATR), a stop-distance multiplier, and a risk:reward ratio. The target distance is always a multiple of the stop distance, so it scales proportionally with however wide or tight the stop is set.

Sizing the position — three independent philosophies

PositionSizeCalculator — the standard risk-budget approach: sizes a position under three constraints (how much you're willing to lose if the stop is hit, a hard cap on capital per trade, and how much portfolio exposure headroom remains) and returns the tightest one. A position with no headroom left for even one unit returns null rather than a zero-or-negative-sized position — "there's no size that fits" is a distinct, real outcome from "here's a valid size."

KellyCriterion — a different starting point: given a measured edge (win probability and payoff ratio), computes the fraction of equity that maximizes long-run growth, rather than a fraction chosen independent of that edge. Includes fractional-Kelly (half-Kelly by default), the standard practitioner adjustment for the large drawdowns full Kelly produces under real-world estimation error.

VolatilityTargetSizing — a third approach, from risk-parity and vol-targeting practice: sizes a position so its expected day-to-day P&L swing matches a fixed target, independent of any stop-loss distance. A calm instrument gets a bigger position and a volatile one a smaller position, for the same risk contribution.

Managing the stop while the trade is open

ChandelierStop — an ATR-based trailing stop that ratchets toward price as a trend extends, tightening only, never loosening — a favorable move can't be undone by a later, less favorable one pulling the stop back out.

BreakevenStop — the "once this trade can no longer be a loser" rule: moves the stop to entry once price has moved a given multiple of the initial risk in your favor. Composes with ChandelierStop: both only ever tighten, so calling either (or both, taking whichever is tighter) as new bars arrive is always safe.

After the trade closes

RMultipleCalculator — grades a closed trade as a multiple of its initial risk (a "+2.4R" winner or a "-0.6R" loser), the standard way to compare trade outcomes independent of how big any particular position happened to be.

ScaleOutPlan — splits a position across profit-taking levels you supply (this library has no opinion on which R-multiples or percentages make a good plan), correctly handling the integer-rounding remainder so legs never lose or double-count a unit, and separately reporting any quantity you deliberately left unassigned to run.

Instruments traded in lots

PositionSizeCalculator.ComputeForLotSize — a thin wrapper around the same risk-budget sizing for instruments traded in fixed contract sizes (index futures and options): pass a lot size, and the returned quantity is already expressed in whole lots, with capital already correctly scaled to real notional value.

Install

Reference the project directly, or build and reference the package:

dotnet add reference path/to/PositionSizing.csproj

or pack it and add it as a local NuGet feed:

dotnet pack src/PositionSizing -o ./nupkg
dotnet add package PositionSizing --source ./nupkg

Usage

The core lifecycle: place, size, trail, grade

using PositionSizing;

// 1. Place the initial stop and target from ATR.
var levels = TargetPriceCalculator.Compute(
    entryPrice: 100m, atrValue: 2.0, isShort: false,
    atrStopMultiplier: 1.5m, riskRewardRatio: 2.0m);
// levels.StopLossPrice = 97, levels.TargetPrice = 106, levels.StopDistance = 3

// 2. Size the position.
var size = PositionSizeCalculator.Compute(
    accountEquity: 1_000_000m, currentPrice: 100m, stopDistance: levels.StopDistance,
    riskPerTradePercent: 0.005m, maxCapitalPerTradePercent: 0.25m,
    openExposurePercent: 0.30m, maxExposurePercent: 0.60m);
if (size is null) { /* no exposure headroom left — skip the trade */ }

// 3. As new bars arrive, trail the stop (never loosens) and check the breakeven rule.
decimal stop = levels.StopLossPrice;
stop = ChandelierStop.Compute(stop, extremePriceSinceEntry: runningHighSinceEntry, atrValue: latestAtr, isShort: false);
stop = BreakevenStop.Compute(stop, entryPrice: 100m, currentPrice: latestPrice, initialStopDistance: levels.StopDistance, isShort: false);

// 4. Once closed, grade the outcome.
double? rMultiple = RMultipleCalculator.Compute(
    entryPrice: 100m, exitPrice: 108m, initialStopDistance: levels.StopDistance, isShort: false);

Kelly sizing, from a measured edge

// From your own trade history: 55% win rate, average win 1.8x average loss.
double halfKellyFraction = KellyCriterion.ComputeFractional(winProbability: 0.55, payoffRatio: 1.8);
decimal riskBudget = accountEquity * (decimal)halfKellyFraction;

Volatility-targeted sizing, independent of a stop

decimal? quantity = VolatilityTargetSizing.Compute(
    accountEquity: 1_000_000m, currentPrice: 100m,
    dailyVolatilityPercent: 0.02m,   // e.g. ATR / price
    targetDailyRiskPercent: 0.01m);  // this position should swing ~1% of equity on a normal day

Scaling out at caller-chosen levels

var (legs, remainder) = ScaleOutPlan.Compute(
    totalQuantity: 100m,
    levels: new[] { (RMultiple: 1.0m, ExitPercent: 0.5m) }); // half off at 1R, let the rest run
// legs[0].Quantity = 50, remainder = 50 (deliberately left to run)

Sizing a lot-based instrument (e.g. index options)

var lotSize = PositionSizeCalculator.ComputeForLotSize(
    accountEquity: 1_000_000m,
    underlyingPrice: 200m,       // premium per unit, not multiplied by lot size
    stopDistancePerUnit: 4m,
    lotSize: 25,
    riskPerTradePercent: 0.01m, maxCapitalPerTradePercent: 0.5m,
    openExposurePercent: 0m, maxExposurePercent: 0.6m);
// lotSize.Quantity is already in LOTS; lotSize.CapitalDeployed is already correct notional value.

What this library does not do

  • It does not decide whether to take the trade. Confidence thresholds, signal scoring, and regime filters are strategy decisions that belong upstream of this library, not inside it.
  • It does not enforce policy-level portfolio gates like a daily loss limit or a maximum position count. Those are one-line checks (dailyPnL <= -dailyLossLimit, openPositionCount >= maxPositions) that differ enough in exact semantics between systems (does the loss limit include unrealized P&L? does it reset intraday?) that it isn't a clean shared primitive the way stop placement and capital sizing are — write the check that matches your own system's semantics.
  • It does not model margin or SPAN requirements. ComputeForLotSize's capital figure is notional value (accurate real capital for a long option's premium), not a margin requirement — for futures or short options, actual capital consumed is a broker- and instrument-specific margin figure smaller than full notional, which this does not compute.
  • It does not know about correlation across positions. Exposure headroom sums capital across positions as if they were independent; two highly correlated positions carry more combined risk than two uncorrelated ones of the same size, and that's a portfolio-optimization problem (needing a real covariance estimate) well beyond what a small, dependency-free library should attempt.
  • It does not fetch data. ATR, win rates, account equity, and open exposure are all inputs you provide.

Provenance

TargetPriceCalculator and PositionSizeCalculator's core sizing formulas were extracted from a private trading-research platform's risk-management gate, where they were the one part of a much larger, strategy-specific gate (AI-confidence thresholds, composite-score gates, regime filters, session time windows) that had no dependency on any of that — pure arithmetic over equity, price, and exposure. KellyCriterion, ChandelierStop, BreakevenStop, VolatilityTargetSizing, RMultipleCalculator, ScaleOutPlan, and ComputeForLotSize were not part of that platform and were written directly for this package, to round out the sizing, stop-management, and trade-grading lifecycle around the extracted core.

License

MIT — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 135 8/31/2026
1.0.0 136 8/25/2026 1.0.0 is deprecated because it has critical bugs.