Backtesting Arena

Backtesting Arena

Back to blog

When Fees Kill a Strategy: Why We Benched Our Second-Most-Popular One

Our backtest engine used to compute returns before costs. We built a net-of-cost layer that re-prices every fill at a realistic fee — and it flipped our second-most-popular strategy negative after fees. Here is the math, the numbers, and why "beats buy-and-hold" is half a truth until you pay the fees.

Backtesting Arena·July 1, 2026·6 min read·25 views
When Fees Kill a Strategy: Why We Benched Our Second-Most-Popular One

A strategy can make money on paper and still burn money in reality. The difference is called fees — and that is exactly where one of our most popular strategies revealed an uncomfortable truth.

We have benched stoch_rsi_sma. By number of runs it is the second-most-used strategy on the entire platform (around 4,125 backtests). It does not lose to buy-and-hold because its signal is bad. It loses because it trades too often — and every trade costs.

The problem: backtests compute before costs

Most backtest engines — ours until recently included — compute returns before fees. Every buy and every sell executes at the raw market price, with no spread, no maker/taker fee, no slippage.

For buy-and-hold this does not matter: one buy, hold, done. A single fee over years — negligible.

For a high-frequency strategy it does matter. Every entry and exit pays. Across hundreds of round-trips it adds up to a hidden tax the pre-cost backtest hides entirely.

The net-of-cost layer

We built a new calculation layer that re-prices every fill at a realistic per-side fee:

  • Crypto: 0.10 % per side (Binance spot taker)
  • Stocks & ETFs: 0.05 % per side

The mechanic is simple and exact. For a round-trip (buy → sell) with per-side cost c:

Net multiplier = (1 − c)² × (exit price / entry price)

You pay on the buy and on the sell — hence (1 − c)². At c = 0 the net return is exactly the gross return. That is the mandatory sanity check: with no fee, nothing may change.

Important: this layer changes no signal whatsoever. It operates purely on the trades that already exist and only reduces proceeds by the cost. No new look-ahead, no new data source.

What the numbers show

We ran eight strategies across 28 asset cells (8 crypto, 10 stocks, 10 ETFs), daily data, default parameters. Cost drag scales exactly with trade frequency — precisely as expected:

StrategyAvg round-tripsGross CAGRNet CAGRCost drag
Buy-and-hold1+15 to +23 %~unchanged~0
Golden Cross7–9+8 to +18 %~unchanged−0.1 to −0.3 pp
RSI/SMA~245midpositive−2.3 pp
MACD Cross~115midpositive−1.1 pp
stoch_rsi_sma558+9.2 %+1.1 %up to −14 pp

Buy-and-hold is practically fee-immune. Golden Cross with seven trades over years, likewise. And then there is stoch_rsi_sma, with an average of 558 round-trips.

stoch_rsi_sma in detail

Before costs the strategy looks viable: an average +9.2 % CAGR. That is exactly why it was so popular — the pre-cost backtest rewards it.

After costs it collapses:

  • Average net CAGR: +1.1 % (median actually −2.1 %)
  • 16 of 28 tested cells turn net negative
  • In 0 of 28 cells does it beat the average buy-and-hold return after costs — on average it lands 19.9 percentage points below it

The implementation itself is correct: clean StochRSI-over-SMA logic, no look-ahead, no calculation error. This is not a bug. It is pure turnover erosion. The strategy generates a thin signal and trades it to death.

The general lesson: turnover is a tax

The real insight is bigger than a single strategy:

Trade frequency × thin edge = post-cost ballast.

A strategy that trades a lot needs a far larger per-trade edge just to overcome the fees. A small but genuine advantage per signal can look gross-positive and still bleed net.

And it makes a second thing clear: when someone claims an active strategy "beats buy-and-hold," you have to ask — before or after fees? Buy-and-hold pays in once. Every active strategy pays on every switch. The fair comparison is the net comparison, and it is often sobering.

What benching means here

stoch_rsi_sma disappears from the backtester and from the default selection. But:

  • The data stays. Not a single valid backtest run is deleted.
  • The verdict stays visible. In the Strategy Library and in Insights the entry remains, including the net numbers that led to the shutdown.

We crystallize the robust strategies out instead of dragging every one along. A strategy that is ballast after costs does not belong in the active roster — even if it was popular.

The test's limits

So the numbers do not sound stronger than they are:

  • The audit ran with default parameters, full history, no filters — that is the worst case for turnover. With a profit guard, a WMA filter, or shorter windows the strategy trades less and the drag is smaller.
  • Slippage is set to 0 in this version — we measure the pure fee, isolated. Real slippage would enlarge the drag, not shrink it.

The direction is robust: stoch_rsi_sma is the clear turnover outlier and flips negative after fees. The exact magnitude depends on parameters and filters.

What Backtesting Arena contributes here

Net-of-cost is now its own check alongside our others — Monte Carlo robustness (How fragile is the result under a different trade order?) and fill realism (What does the gap between the signal close and the tradable open cost?). All three share one goal: make the reported number more realistic, not prettier.

The insight itself is part of the product. We show which strategies we have benched and why — with the numbers behind it. Openly showing what does not work is worth more than one more strategy that looks good gross.

FAQ

Why bench such a popular strategy — won't that annoy users? Possibly. But popularity is not a performance argument. stoch_rsi_sma was popular because the pre-cost backtest rewarded it. That illusion is exactly what we are correcting. We would contradict ourselves if we knowingly left a post-cost loss-making strategy in the active roster.

Are 0.10 % / 0.05 % per side realistic? Yes, if anything conservative. 0.10 % matches the Binance spot taker fee; many users pay less with maker rebates or BNB, others effectively more on small amounts via spread. For stocks/ETFs, 0.05 % is a realistic spread proxy. It is an assumption, not a constant of nature — but one that hits the right order of magnitude.

Couldn't you just rescue stoch_rsi_sma with fewer trades? Maybe — with more aggressive thresholds or a trend filter that cuts most of the whipsaws. But that would be a different strategy. Until someone presents a repaired, validated version that sits above buy-and-hold after costs, the current one stays benched. Data first, then implement.

Does this mean every active strategy is worse than buy-and-hold after costs? No. Golden Cross, RSI/SMA, MACD Cross and others stay net-positive too — they trade rarely enough that the fee does not eat their edge. The point is not "active bad, passive good," but: frequency has a price, and that price has to show up in the comparison.

Does the net-of-cost layer change my old backtest results? No. The engine default stays pre-cost for now — net-of-cost runs as an additional view, not a silent switch. We do not retroactively change reported numbers without clear communication. A fee changes every value; that kind of thing is announced, not slipped in.

Why wasn't slippage in the test? Deliberately. We wanted to show the pure fee effect in isolation, without mixing it with an estimated slippage assumption. Slippage comes as a separate, evidenced knob in a later version — it would enlarge the drag, so it only strengthens the conclusion.

Try it yourself

Run the backtest with your own parameters and time ranges.

Run backtest →
📬

Don't miss new blog posts

One short email per new post — strategies, backtests, market analysis. No spam, unsubscribe with one click anytime.

By subscribing you accept our privacy policy. We use Resend for delivery. Double opt-in confirmation required.

Comments (0)

Join free to post comments.

Sign up →

No comments yet. Be the first!