← Back to Blog
April 5, 2026programming

Position Sizing for Algo Trading: Kelly vs Fixed Fractional vs Volatility-Adjusted

By APIndicators

The most common cause of account blowups in algo trading is not a bad strategy. It is a good strategy with reckless position sizing. A 55% win-rate system with a 1:1 risk/reward ratio has positive expectancy, but if you bet 40% of equity per trade, a realistic losing streak will wipe you out before the edge realizes.

This post walks through three position sizing approaches used in production trading systems: Kelly criterion, fixed fractional, and volatility-adjusted. Each has specific strengths and failure modes. We show the math, the Python implementations, and how to wire them into the APIndicators simulated positions endpoint.

Fixed Fractional: The Baseline

Fixed fractional sizing risks a constant percentage of current account equity on every trade. Most commonly 1-2% risked per trade, meaning if the stop loss is hit, you lose that percentage of equity.

def fixed_fractional_size(equity, risk_pct, entry_price, stop_loss_price):
    risk_amount = equity * risk_pct
    price_risk = abs(entry_price - stop_loss_price)
    position_size = risk_amount / price_risk
    return position_size

size = fixed_fractional_size(
    equity=10_000,
    risk_pct=0.01,
    entry_price=65000,
    stop_loss_price=63700,
)
print(f"Size: {size:.4f} BTC")

Strengths: dead simple, hard to blow up, scales with account growth, easy to explain to a risk manager.

Weaknesses: ignores the conviction of the signal. A 60% confidence trade gets the same size as an 85% confidence trade.

Use when: starting out, or as the default for any system under 100 trades of live data.

Kelly Criterion: The Math-Optimal Sizing

Kelly tells you the fraction of capital to bet to maximize long-run geometric growth. Formula:

f* = (p * b - (1 - p)) / b

where:
  p = probability of winning
  b = win/loss ratio (net odds)
  f* = fraction of capital to bet

For a 58% win rate strategy with 1:1 risk/reward:

def kelly_fraction(win_prob, win_loss_ratio):
    q = 1.0 - win_prob
    f = (win_prob * win_loss_ratio - q) / win_loss_ratio
    return max(0.0, f)

f = kelly_fraction(0.58, 1.0)
print(f"Full Kelly: {f:.3f} -> {f*100:.1f}% of equity")

Output: Full Kelly = 16% of equity per trade. That is aggressive. Full Kelly has 50% probability of a 50% drawdown. Most practitioners use fractional Kelly — half or quarter:

def fractional_kelly(win_prob, win_loss_ratio, fraction=0.25):
    return kelly_fraction(win_prob, win_loss_ratio) * fraction

Quarter Kelly is common for crypto because win probabilities are noisy and overestimated.

Strengths: mathematically optimal long-run growth given accurate inputs.

Weaknesses: extremely sensitive to estimates. A 5 percentage point error in win_prob changes the size dramatically. Assumes stationary edge (false in crypto). Can be ruinous with correlated bets.

Use when: you have 500+ live trades establishing stable win rate and payoff, and you are sizing a single uncorrelated signal.

Volatility-Adjusted Sizing

Volatility-adjusted sizing scales position inversely to recent price volatility. The goal: target a consistent dollar risk regardless of whether BTCUSDT is ranging at 20% annualized volatility or panicking at 80%.

def volatility_adjusted_size(equity, target_daily_vol_dollars, atr, price):
    daily_vol_pct = (atr / price) * (24 / 14) ** 0.5
    dollar_vol_per_unit = price * daily_vol_pct
    units = target_daily_vol_dollars / dollar_vol_per_unit
    return units

size = volatility_adjusted_size(
    equity=10_000,
    target_daily_vol_dollars=50,
    atr=850,
    price=65_000,
)
print(f"Size: {size:.4f} BTC")

This keeps your daily P&L volatility roughly constant. When ATR expands, your size shrinks. When ATR compresses, your size grows.

Strengths: normalizes risk across market regimes, reduces blowup risk during volatility spikes, works across pairs with different natural volatilities.

Weaknesses: requires a good volatility estimate (APIndicators' ATR works well). Slower to scale up when a trend starts.

Use when: trading multiple pairs, running strategies across regimes, or when you need P&L smoothness for drawdown control.

Combining the Three: The Production Approach

In practice, most quant desks combine these. APIndicators V2's sizing logic looks like this:

def production_size(equity, signal_confidence, atr, price, max_risk_pct=0.015):
    base_risk_pct = 0.01
    confidence_multiplier = min(2.0, max(0.5, (signal_confidence - 0.50) / 0.30 * 2.0))
    kelly_adjusted = base_risk_pct * confidence_multiplier
    capped_risk = min(kelly_adjusted, max_risk_pct)

    daily_vol_pct = (atr / price) * 3.7
    dollar_risk = equity * capped_risk
    units = dollar_risk / (price * daily_vol_pct)
    return units

Start from fixed fractional (1%), scale up with signal confidence (up to 2x), cap the max risk (1.5%), and size the actual unit count by volatility. This gives you Kelly's conviction-sensitivity with volatility adjustment's regime-robustness and fixed fractional's bounded downside.

Testing Sizing via Simulated Positions

APIndicators exposes a /v1/simulated-positions endpoint that lets you test sizing logic without placing real orders:

import requests
import os

url = "https://api.apindicators.com/v1/simulated-positions"
headers = {"Authorization": f"Bearer {os.environ['APINDICATORS_API_KEY']}"}

payload = {
    "symbol": "BTCUSDT",
    "side": "BUY",
    "entry_price": 65000.0,
    "take_profit_at": 66300.0,
    "stop_loss_at": 63700.0,
    "leverage": 5,
    "quantity": 0.15,
}

r = requests.post(url, headers=headers, json=payload)
print(r.json())

Run your strategy against historical signals, create simulated positions with each sizing method, and compare the resulting drawdowns and Sharpe ratios. This is how you validate sizing before committing real capital.

Rules of Thumb

  1. Never exceed 2% risk per trade unless you have a statistically proven edge and are fully aware of drawdown risk.
  2. Use fractional Kelly (1/4 or 1/2), never full Kelly.
  3. Correlated positions compound risk. Three BTCUSDT, ETHUSDT, SOLUSDT longs at 1% each is actually 2.5-3% risk.
  4. Volatility-adjust across pairs so your top alt is not 10x riskier than BTC.
  5. Track realized win rate monthly and recalculate Kelly inputs.

Explore the simulated positions docs at apindicators.com/docs and start backtesting sizing approaches today.