When the Fee Eats the Edge

The textbook Kelly criterion assumes the only thing standing between you and your payoff is the outcome. Real instruments charge you either way, and the charge is very often a flat fee: a fixed amount per settled bet that does not care how much you staked.

That combination has a sharp consequence. keeks sizes bets in proportion to your edge, so a thin edge means a small stake, and a small stake is exactly where a flat fee does the most damage.

The obvious version

Start with the easy case, which is the one that gets written about. A win pays you the payoff on your stake and then the fee comes off:

amt = (self.payoff * bet_amount) - self.transaction_costs
if amt >= 0:
    bankroll.deposit(amt)
else:
    bankroll.withdraw(abs(amt))

That else is not defensive programming. If the fee is larger than the payoff on your stake, you won the bet and your bankroll went down. The break-even stake is fee / payoff, and Kelly walks you toward it as your edge thins:

   edge        p   kelly f     stake   win pays        net
  0.200   0.6000    0.2000    200.00     200.00     199.00
  0.050   0.5250    0.0500     50.00      50.00      49.00
  0.010   0.5050    0.0100     10.00      10.00       9.00
  0.002   0.5010    0.0020      2.00       2.00       1.00
  0.001   0.5005    0.0010      1.00       1.00      -0.00

A one-dollar fee, a thousand-dollar bankroll, even money. At a 0.1% edge Kelly stakes exactly a dollar, and the fee takes all of it.

This is a real effect and it is worth having handled. It is also not the expensive one.

The version that actually costs you

Look at the 1% edge row. Kelly stakes ten dollars, a win pays nine, nothing looks broken. A one-dollar fee on a ten-dollar bet reads as a 10% cost: annoying, survivable.

Except the fee is not competing with your stake. It is competing with your profit, and at a 1% edge on a ten-dollar bet your expected profit is ten cents.

The fee is ten times your entire edge.

Run it and the ten-dollar-bet-with-a-one-dollar-fee that sounded survivable is not:

500 bets at a 1% edge, $1,000 bankroll, varying the flat fee

    fee   final bankroll
   0.00          1343.14
   0.50          1058.62
   1.00           774.10
   2.00           205.05
   5.00             1.71

The edge is real and unchanged in every row. At a fee of zero you make 34%. At one dollar you lose a quarter of the bankroll. At five you are wiped out.

The break-even, and why it is a square root

Per bet, your expected gross profit is your edge times your stake. Under Kelly at even money the stake is roughly your edge times your bankroll, so:

expected gross profit per bet  =  edge x stake  =  edge² x bankroll

Set that against the fee and the condition to make money at all is

edge² x bankroll > fee        i.e.        edge > sqrt(fee / bankroll)

The edge is squared because it enters twice: once as your advantage per unit staked, and once through Kelly deciding how much to stake. That is the part I find genuinely counterintuitive, and it is why fees feel so much worse in practice than a percentage-of-stake calculation suggests.

For a one-dollar fee and a thousand-dollar bankroll that is sqrt(0.001) = 3.16%. Not the 0.1% where a win literally loses money, thirty times higher.

Median bankroll by edge with a flat fee, and the edge required by bankroll size

The simulation crosses break-even right where the formula says: expected gross profit per bet is 0.999 against a 1.00 fee at a 3.16% edge, and the median outcome flips from losing to winning within a few tenths of a percent of that line.

What the square root implies

The right panel is the same formula read the other way. Because the required edge falls with the square root of the bankroll, quadrupling your bankroll only halves the edge you need:

bankrolledge required
$1,0003.16%
$10,0001.00%
$100,0000.32%
$1,000,0000.10%

A 1% edge is a good edge. It is unprofitable at a thousand dollars against a one-dollar fee and comfortably profitable at ten thousand, with nothing changing but the size of the account. Fixed costs are a threshold on capital, not a tax on returns, and the threshold moves slowly.

What to do about it

Compute net-of-cost expected value before sizing, not after settling. The quantity that decides whether to bet is edge x stake - fee, and it is knowable before you place anything. A strategy that sizes on gross edge and discovers the fee at settlement is sizing for a different game.

Treat a non-positive net as a no-bet. Not a small bet. If the arithmetic says this wager cannot pay for itself, the correct stake is zero, and clamping it to something tiny makes it worse because the fee does not shrink with it.

Push fees into the payoff terms. keeks’ Kelly does this directly:

adjusted_payoff = self.payoff - self.transaction_cost
adjusted_loss = self.loss + self.transaction_cost

Once the costs are inside the payoff structure, the sizing formula is solving the right problem and everything downstream follows. Note the unit though: strategies take transaction_cost as a per-unit fraction of the stake, while simulators take transaction_costs as a flat fee per settled bet. The distinction is exactly the subject of this post, and the two names differ by one letter, so it is worth checking which one you are setting.

And know your capital threshold. sqrt(fee / bankroll) is one line of arithmetic and it tells you whether an edge is worth pursuing at your size before you build anything.

Running it

from keeks.bankroll import BankRoll
from keeks.binary_strategies import KellyCriterion
from keeks.simulators.repeated_binary import RepeatedBinarySimulator

bank = BankRoll(initial_funds=1000.0, percent_bettable=1.0, max_draw_down=1.0)
strategy = KellyCriterion(payoff=1.0, loss=1.0, transaction_cost=0.0)
sim = RepeatedBinarySimulator(payoff=1.0, loss=1.0, transaction_costs=1.0,
                              probability=0.505, trials=500, seed=7)
sim.evaluate_strategy(strategy, bank)
print(bank.total_funds)

pip install keeks==0.6.0.