· ai-ops · 4 min read

Episode 2 of 3: Why Most DeFi Trading Bots Fail in the Real World

The easiest way to make a DeFi trading bot look smart is to stop the story before the trade has to survive the market.

on this page
  1. What most DeFi bot backtests leave out
  2. The Boros test system
  3. The assumptions that changed the answer
  4. What happened to the Boros signal
  5. Why paper trading staying flat was a good sign
  6. Research & Code
  7. Next up

The easiest way to make a DeFi trading bot look smart is to stop the story before the trade has to survive the market.

That usually means three things get hidden:

The Boros project only became useful once it stopped doing that.

Series navigation: Episode 1 | Episode 2 | Episode 3

What most DeFi bot backtests leave out

What most DeFi bot backtests leave out The easiest way to make a DeFi trading bot look smart is to stop the story before the trade has to survive the market.

If you have ever seen a crypto bot thread with a smooth chart and a lot of confidence, there is a good chance the hard parts were removed before the chart was drawn.

In practice, the hard parts are usually:

That is why so many bot ideas look great in research and mediocre in reality.

The model is not trading.

The notebook is not trading.

The market is trading.

The Boros test system

The real value of the Boros repo was not the strategy itself. It was the system around it.

Instead of treating one promising setup like a winner, the repo forced every strategy through the same path:

market data
    +
reference data
    +
historical snapshots
    |
    v
signal engine -> backtest -> execution realism -> capacity checks
    |
    v
forward paper trader -> persistent logs -> dashboard

That structure did two useful things:

  1. it made every assumption visible
  2. it made bad strategies fail in the same place every time

That is what you want from a research stack.

The assumptions that changed the answer

Once the Boros strategy moved into the strict framework, every run had to survive the same execution profiles.

Profile Delay Spread multiplier Extra slippage Cost floor
Optimistic 0s 1.00x 0.25 bps 0.25 bps
Base realistic 300s 1.10x 0.75 bps 0.75 bps
Conservative 900s 1.25x 1.50 bps 1.50 bps
Adversarial 1800s 1.50x 3.00 bps 3.00 bps

That table is where the mood changed.

A strategy that only works with perfect timing, clean fills, and gentle costs is not robust. It is just lucky.

The Boros-native carry signal did not survive that transition.

What happened to the Boros signal

The original story was simple:

That sounds reasonable until you ask the more useful version:

after delay, spread, slippage, exit friction, and a short history window, is there still enough left to matter?

For the lead strategy, carry_mean_reversion_v2, the final answer was no.

Under the strict realism pass it finished with:

The important point is not that performance got worse.

The important point is that it crossed through zero and stayed there.

That is not a tuning problem. That is a strategy-quality problem.

Why paper trading staying flat was a good sign

One of the most honest outputs in the Boros project was also the least exciting one.

The paper trader stayed flat.

On the March 27, 2026 forward snapshot:

That means the system was alive.

It just was not pretending.

The main rejection reasons were exactly what you would want from a strict paper stack:

That is the opposite of fantasy paper trading.

The system saw the market, scored the setup, and decided the trade did not deserve to exist.

Research & Code

The technical details belong here, not at the center of the reader story.

If you want the deeper mechanics, the key repo pieces are:

The simplified trade lifecycle looked like this:

for snapshot in market_history:
    signal = strategy.compute(snapshot, refs, config)
    if not signal.accepted:
        record_rejection(signal)
        continue

    entry = execution_model.enter(signal, book=snapshot.book)
    if not entry.filled:
        record_missed_trade(signal, entry)
        continue

    position = open_position(entry)
    position = manage_until_exit(position)
    close_position(position)

That code is not there to look clever.

It is there so the hidden assumptions have nowhere to hide.

Next up

The final article is the blunt one.

I will put the Boros-native carry idea, the external-reference strategy, and the benchmark funding strategy side by side, then answer the only question that matters:

did any Boros edge survive realistic costs?

Continue with Episode 3: Boros Trading Bot Verdict.