AlgoPro UniversityCourse home
Part 7 · Lesson

Position sizing: fixed-fractional risk

Risk a fixed percentage of equity per trade and let the stop distance decide your size. The workhorse method that anchors everything else.

The single most important number in your trading is not the entry price — it is the position size. Get it wrong and a good strategy still blows up (last lesson); get it right and a mediocre strategy survives long enough to earn. The workhorse method used by most professional discretionary and systematic traders is fixed-fractional sizing, also called "percent-risk" sizing.

The formula

You need three inputs: your equity, the risk fraction (how much of that equity you will lose if stopped out), and the stop distance (how far, in price, from entry to stop). The size falls straight out:

pythonFixed-fractional position size
def position_size(equity, risk_pct, entry, stop):
    class="s">""class="s">"
    equity   : account value in currency
    risk_pct : fraction of equity to risk, e.g. class="n">0.01 for class="n">1%
    entry    : planned entry price
    stop     : stop-loss price
    returns  : number of units (shares / contracts / coins)
    "class="s">""
    risk_amount   = equity * risk_pct        class="c"># currency you'll lose if stopped
    stop_distance = abs(entry - stop)         class="c"># loss per unit
    if stop_distance == class="n">0:
        raise ValueError(class="s">"stop must differ from entry")
    return risk_amount / stop_distance

size = position_size(equity=25_000, risk_pct=class="n">0.01,
                     entry=class="n">100.0, stop=class="n">96.0)
print(fclass="s">"Buy {size:.0f} units")               class="c"># Buy class="n">62 units
print(fclass="s">"Capital deployed: {size * class="n">100:,.0f}") class="c"># class="n">6,class="n">250
print(fclass="s">"Risk if stopped:  {size * class="n">4:,.0f}")   class="c"># class="n">250  == class="n">1% of class="n">25,class="n">000

Read the last two comments carefully. We deployed 6,250 of capital — a quarter of the account — but the *actual risk* is only 250, exactly 1% of equity, because the stop is just 4 points away. Capital deployed and capital at risk are completely different quantities. Fixed-fractional sizing controls the one that matters: the loss you take when you are wrong.

Why let the stop set the size?

Because it makes every trade an equal-risk bet. A wide-stop trade and a tight-stop trade both lose the same 1% if they fail. This decouples "how confident is the stop placement" from "how much am I risking" — you place the stop where the chart says it belongs, and the formula shrinks or grows the size to keep the risk constant.

pythonSame 1% risk, wildly different share counts
equity, risk_pct = 25_000, class="n">0.01

trades = [
    class="c"># (name,           entry,  stop)
    (class="s">"Tight stop",     class="n">100.0,  class="n">99.0),   class="c"># class="n">1-point stop
    (class="s">"Medium stop",    class="n">100.0,  class="n">96.0),   class="c"># class="n">4-point stop
    (class="s">"Wide stop",      class="n">100.0,  class="n">90.0),   class="c"># class="n">10-point stop
    (class="s">"Cheap stock",     class="n">20.0,  class="n">19.5),   class="c"># class="n">0.5-point stop
]

for name, entry, stop in trades:
    size = position_size(equity, risk_pct, entry, stop)
    deployed = size * entry
    risk = size * abs(entry - stop)
    print(fclass="s">"{name:12s}  {size:class="n">6.0f} units  "
          fclass="s">"deployed {deployed:class="n">8,.0f}  risk {risk:class="n">6,.0f}")

class="c"># Tight stop      class="n">250 units  deployed   class="n">25,class="n">000  risk    class="n">250
class="c"># Medium stop      class="n">62 units  deployed    class="n">6,class="n">250  risk    class="n">250
class="c"># Wide stop        class="n">25 units  deployed    class="n">2,class="n">500  risk    class="n">250
class="c"># Cheap stock     class="n">500 units  deployed   class="n">10,class="n">000  risk    class="n">250

Four completely different position sizes — from 25 units to 500 — yet the risk column is a flat 250 every time. That is the point of the method: you normalise risk, not size. Note the tight-stop trade deploys the full account; a sensible system adds a cap so a single position cannot use more than, say, 30% of capital even when the stop is very close.

Choosing the risk fraction

How big should risk_pct be? This is a judgement about survival, informed directly by the risk-of-ruin maths from the last lesson. Common practice:

0.5%1%2%3%5%10%Drawdown from a 10-loss streak by risk-per-trade
Compounded loss after ten consecutive losing trades, by risk-per-trade. At 1% you barely notice; at 5% you are in the steep part of the recovery curve; at 10% you have nearly halved the account. Streaks of 10 losses are normal, not rare.

Putting it in a trade loop

pythonSizing inside a simple strategy step
class FixedFractionalSizer:
    def __init__(self, risk_pct=class="n">0.01, max_deploy_pct=class="n">0.30):
        self.risk_pct = risk_pct
        self.max_deploy_pct = max_deploy_pct

    def size(self, equity, entry, stop):
        raw = position_size(equity, self.risk_pct, entry, stop)
        class="c"># cap capital deployed so a tight stop can't use the whole account
        cap = (equity * self.max_deploy_pct) / entry
        return min(raw, cap)

sizer = FixedFractionalSizer(risk_pct=class="n">0.01)

class="c"># on a signal:
equity = 25_000
units = sizer.size(equity, entry=class="n">100.0, stop=class="n">99.0)
print(fclass="s">"{units:.0f} units")   class="c"># class="n">75 units (capped at class="n">30% = class="n">7,class="n">500), not class="n">250

Fixed-fractional sizing is the foundation. But it has a blind spot: it treats a 4-point stop the same whether the market is dead calm or violently volatile. In a quiet market 4 points might be enormous; in a wild one it might be nothing. The next lesson fixes that by sizing off volatility itself.