Quant500 Academy

3. Real costs: commissions, slippage and position sizing

Level 12: Backtesting and Real Risk Metrics

In Level 5 you built a deliberately naive backtest: no commissions, no slippage, entering and exiting at the exact closing price. We warned you at the time that it was not a result, it was a sketch. This module settles that debt.

Commissions

In Backtrader they are configured in a single line:

cerebro.broker.setcommission(commission=0.001)  # 0.1% of notional

That 0.1% looks harmless. Do the arithmetic: it applies to the buy and to the sell, so every complete round trip costs 0.2% of the notional traded. A strategy that does 250 round trips a year on the full capital pays 50% a year in commissions. No reasonable statistical edge survives that. Turnover is a first-order design variable, not an implementation detail.

For US equities a per-share scheme with a minimum is usually more realistic:

class PerShareCommission(bt.CommInfoBase):
    params = (
        ('commission', 0.005),   # dollars per share
        ('stocklike', True),
        ('commtype', bt.CommInfoBase.COMM_FIXED),
    )

    def _getcommission(self, size, price, pseudoexec):
        return max(abs(size) * self.p.commission, 1.0)  # minimum of one dollar

cerebro.broker.addcommissioninfo(PerShareCommission())

Slippage

Commission is the visible cost; slippage is the invisible one, and almost always the larger. It is the difference between the price your backtest assumes and the price at which your order actually crosses: the spread you pay, the impact your own volume causes, and the price movement between deciding and executing.

cerebro.broker.set_slippage_perc(perc=0.0005)   # 0.05% per trade
# or as an absolute amount:
# cerebro.broker.set_slippage_fixed(fixed=0.02)

There is a cruel asymmetry worth internalizing. Mean reversion strategies buy when the price falls and sell when it rises; they are providing liquidity, and the market tends to charge them for that service precisely when it is moving most. Momentum strategies chase the price, that is, they consume liquidity and pay the full spread. In both cases real slippage tends to be worse than the historical average exactly on the most volatile days, which are the days on which the strategy generates the most signals.

A practical rule: if your strategy's average return per trade is of the same order of magnitude as the asset's average spread, the strategy does not exist. It is noise decorated with an equity curve.

Position sizing

cerebro.addsizer(bt.sizers.FixedSize, stake=1000)

This sizer always buys 1000 shares. With starting capital of 100,000 and a price of 180 dollars per share, each order tries to move 180,000 dollars: more than the entire capital. The simulated broker will reject the order for insufficient margin and your backtest will do far fewer trades than you think, without warning you. The opposite problem also exists: if the asset trades at 8 dollars, each trade moves 8% of the capital and the strategy ends up under-invested.

More sensible alternatives:

cerebro.addsizer(bt.sizers.PercentSizer, percents=95)

Or a custom sizer that sizes by risk: decide how much you are willing to lose per trade (say, 1% of capital) and divide that amount by the distance to the stop in currency per share. That way the size adapts to the asset's volatility instead of to the accident of its nominal price.

A quick and very revealing check: run the same backtest with zero costs and with realistic costs. If the difference between the two results is larger than the profit of the second one, what you had was not a strategy.

The rest of Quant500

What you are learning, applied to the index every day:

The model portfolio, weekly in your inbox

Every Saturday, its week in one minute: how it went, the best and the worst, and which insiders bought with their own money. Plus, the day the model is rebuilt, which stocks come in and which go out. A simulation, not advice. At most one email a week, no ads, no account; one-click unsubscribe. Made by one person: Pol Gracia.

A model portfolio with simulated results, not a personalized recommendation. Your email is used for this only: privacy.

Behind the Academy and the rest of Quant500 there is one person: Pol Gracia Serrahima.