Technique explained as code
Fixed fraction position sizing
Put the same share of the account at risk on every trade. This page runs one invented sequence of coin flip trades at several fractions to show what the size alone does.
Risk warning: CFDs and spread bets are complex instruments and come with a high risk of losing money rapidly due to leverage. You can lose money on these products, and each provider publishes its own loss figure under FCA rules. You should consider whether you understand how they work and whether you can afford to take the high risk of losing your money. Automated and API trading can amplify losses through bugs, connectivity failures and runaway orders.
Teaching material only. This page explains how a technique works as code and how to test an idea honestly. It is not investment advice, not a recommendation and not an invitation to trade. Every price on it is invented, so no result here says anything about any real market, and nothing here suggests that a technique makes money.
What it is
Fixed fraction sizing answers one question: how big should this trade be? The answer is whatever size makes the loss, if the stop is hit, equal to a fixed share of the account as it stands today.
Because the share is taken from the current balance, the amount at risk shrinks after losses and grows after gains.
The idea behind it
Sizing is separate from deciding what to trade. Two people taking exactly the same trades can end in very different places because one risked a small share each time and the other a large one.
To isolate that, this page removes the market altogether. The trades are coin flips from a fixed seed: a win and a loss are equally likely and the same size. They have no edge by construction. The only thing that varies is the fraction.
The code
The function at the top is the arithmetic on a single trade. The rest plays one fixed run of 200 coin flip trades at each of six fractions. The fractions are examples that show the shape of the effect. They are not suggestions.
Each trade also pays a small cost, as every real trade does, and the last line of the table is the comparison with doing nothing.
This script reads no file. Its inputs are made inside the script from a fixed seed.
The file that was run: fixed_fraction.py
# Fixed fraction position sizing: put the same share of the account at risk on every trade.
# There are no prices here at all. The trade outcomes are coin flips from a fixed seed: a win
# and a loss are equally likely and the same size, so the trades have no edge by construction.
# The point is what the size of the fraction alone does to the same run of trades.
import random
def position_size(balance, fraction, stop_distance):
"""How many units to trade so that being stopped out costs `fraction` of the balance."""
if stop_distance <= 0:
raise ValueError("stop distance must be greater than zero")
return balance * fraction / stop_distance
# The arithmetic on one trade. Example figures only.
print("Units for 10,000 at risk of 1 percent with a stop 25 points away:", position_size(10_000, 0.01, 25))
print("The same with a stop 50 points away:", position_size(10_000, 0.01, 50))
# One fixed run of 200 trades: +1 means the trade made what it risked, -1 means it lost it.
rng = random.Random(7)
outcomes = [rng.choice([1, -1]) for _ in range(200)]
print("Trades:", len(outcomes), "of which wins:", outcomes.count(1), "and losses:", outcomes.count(-1))
COST = 0.05 # cost of each trade, as a share of the amount risked
START = 10_000.0
def play(fraction):
"""Run the same outcomes with one fraction. Return the final balance and the worst fall from a high."""
balance = peak = START
worst_fall = 0.0
for outcome in outcomes:
at_risk = balance * fraction # sized from the balance as it is now
balance += at_risk * (outcome - COST)
peak = max(peak, balance)
worst_fall = max(worst_fall, (peak - balance) / peak * 100)
return balance, worst_fall
# Example fractions, to show the shape of the effect. They are not suggestions.
print("fraction final balance worst fall from a high")
for fraction in [0.005, 0.01, 0.02, 0.05, 0.10, 0.25]:
balance, worst_fall = play(fraction)
print(f"{fraction * 100:5.1f} % {balance:13,.2f} {worst_fall:5.1f} %")
print("Doing nothing leaves the balance at", f"{START:,.2f}")
# Why losses weigh more than gains: the gain needed to get back to where you started.
print("loss gain needed to recover")
for loss in [10, 25, 50, 75]:
print(f"{loss:3d} % {100 / (100 - loss) * 100 - 100:6.1f} %")What the run printed
Units for 10,000 at risk of 1 percent with a stop 25 points away: 4.0 The same with a stop 50 points away: 2.0 Trades: 200 of which wins: 102 and losses: 98 fraction final balance worst fall from a high 0.5 % 9,680.20 10.8 % 1.0 % 9,323.81 20.7 % 2.0 % 8,520.61 37.7 % 5.0 % 5,760.69 71.6 % 10.0 % 1,990.20 94.7 % 25.0 % 3.02 100.0 % Doing nothing leaves the balance at 10,000.00 loss gain needed to recover 10 % 11.1 % 25 % 33.3 % 50 % 100.0 % 75 % 300.0 %
Output of the run on , copied as printed. Every input to this run was invented, so the result says nothing about any real market.
How to read it
Every row uses the same 200 outcomes, with slightly more wins than losses. Every row still ends below the starting balance, because trades with no edge that pay a cost lose the cost. Doing nothing ended higher than all of them.
What changes down the table is how much was lost and how deep the worst fall was. The same trades that cost a few percent at the smallest fraction left almost nothing at the largest. Nothing about the trades changed. Only the size did.
The second table is why. A loss of half the account needs a gain of 100 percent to recover, so large swings in both directions do not cancel out. They grind the balance down. These are coin flips, not a market, and the table says nothing about how any way of trading would do.
How it fails or misleads
- Sizing cannot create an edge. Applied to trades that lose on average, every fraction loses. A smaller fraction only loses more slowly.
- The loss is only fixed if the stop is honoured. A gap through the stop makes the real loss larger than the fraction, sometimes much larger.
- Several open positions that move together are, in effect, one large position. A fraction per trade says nothing about that.
- With leverage, the position size the formula gives can be far larger than the account. The formula does not know or care, and a broker's margin rules may close the position before the stop is reached.
- Risk of ruin is not zero at any fraction. A long enough losing run arrives eventually, and the larger the fraction the shorter the run it takes.
The page on how a backtest lies shows the mistakes that make any rule look better in a test than it is.
What to try changing
These are programming exercises. Each one changes the code and asks you to explain what you see. None of them is a search for settings to use.
- Change the seed and run it again several times. Which rows change a lot from one run to the next, and which hardly move?
- Set COST to zero. With no cost and no edge, do the small fractions end near the starting balance? Do the large ones?
- Make wins slightly more likely than losses and run the table again. Notice that the largest fractions can still end lower than the smallest: more size is not more of a good thing.
- Add a column for the longest run of losses in a row and the fall it caused at each fraction.
- Extend position_size to refuse a fraction above a limit you choose, raising an error with a clear message, and write three test calls for it.
How this page was made
Each script on this page was run with Python 3.12 on Windows, standard library only, from a folder holding the data files listed. No network and no account. Each exited with code 0, and what is shown is everything it printed.
The data files whose names begin with the word invented are written by make_invented_data.py from fixed seeds, so anyone can make the same files again and get the same output. This site is not published if the code or a data file has changed since the run.