Build1 publisher2 min readPublished
Charging 10 bps a side turns a 13.44 Sharpe into -40.13 on the same code revision
A cross-sectional reversal baseline on 15-minute Bybit perpetual bars won 67 of 76 out-of-sample windows before costs and none of them after. Charging the trading it requires puts breakeven near 2.5 bps per side.
The Engineer · Build desk

What happened
- A cross-sectional reversal signal on cached Bybit USDT perpetual bars scored a Sharpe of 13.44 before transaction costs, with 67 of 76 reported out-of-sample windows finishing positive.
- Charging the same signal 10 bps per side inside the same evaluation path drove net Sharpe to -40.13, and none of the 76 windows stayed positive.
- The run used 15-minute bars from January 2021 to a September 2025 boundary, an eight-bar return signal, and 90-day formation periods followed by 21-day out-of-sample periods rolled every 21 days.
- The evaluator enforces execution delay centrally by shifting every position column one bar, so a weight computed at t earns nothing until t+1.
- The cache holds 451 symbol directories and the reproduction applies no historical liquidity screen, so the author says survivorship and availability bias remain possible.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint With breakeven around 2.5 bps per side, whether this signal can trade at all is decided by the fee schedule and the fill quality, not by any further work on the signal.
- decision Anyone running this class of baseline has to put execution delay, turnover, fees, slippage and funding in the evaluation path from the first run, because adding them afterwards reverses the conclusion.
- exposure Without a point-in-time universe, the pre-cost 13.44 may itself be inflated, since part of it may come from symbols the cache retains only because they survived.
- precedent Publishing both numbers from one code revision and one data fingerprint gives readers a comparison they can argue with.
H3 rebuilds the whole portfolio at every 15-minute bar. At each timestamp it takes each available asset's return over the previous eight bars, standardizes those returns across the cross-section, and flips the sign, so recent relative losers get positive weights and recent relative winners get negative ones [11]. The vector is scaled to unit gross exposure, then portfolio volatility targeting runs on top, using a 96-bar trailing estimate against a 10% annualized target with a 3x leverage cap [6]. Nothing is fitted, and the post says no feature search sits behind the result [14].
The execution delay is the part you cannot forget to switch on. Every position column passes through one helper in the evaluator, `live()`, defined as `pl.col(column).shift(1).fill_null(0.0)` [12]. "Without the shift, the backtest would earn the same closing-bar return used to calculate the signal," the author wrote [13].
Charging 10 bps per side moves the result by 53.57 Sharpe units [1]. If that drag is roughly linear in per-side cost, the signal pays for itself only below about 2.5 bps per side [2]. The volatility target is 10% annualized [6], so the same gap converts to about 5.36 in annualized return, which is roughly 540% of capital a year in fees and slippage [3]. At 10 bps per side that implies one-way trading of about 5,400 times equity a year [4]. Spread across roughly 35,000 fifteen-minute rebalances, it is near 15% of gross exposure each time [5]. Both steps assume realized volatility landed near the target in both runs.
The author wrote: "A huge pre-cost Sharpe and huge turnover can be two descriptions of the same fragile result" [17]. On the cause, he wrote that "It is what can happen when a short-lived pattern asks for a new portfolio every 15 minutes" [18]. On the pre-cost number, he wrote that "the pre-cost numbers looked clean enough that I spent twenty minutes checking whether I had made an error somewhere before I accepted the result" [19]. Twenty minutes seems about right for a 13.44.
The zero-cost baseline still includes funding PnL, so it is not a gross price-return series; funding belongs to holding a perpetual position, and 13.44 is the baseline before fees and slippage [15]. Both bars come from the same code revision, data fingerprint, walk-forward windows, signal weights and normalization [16].
The author, who wrote "I am not a professional quant" [20], labels the output himself: "This result is a development diagnostic, not evidence of a deployable alpha" [10]. A lockbox period beginning September 1, 2025 stayed sealed for the article [7].
What to watch
- The lockbox from September 1, 2025 is still sealed; opening it on the same code revision would test whether the pre-cost signal survives at all.
- A point-in-time liquidity screen over the 451-symbol cache would show how much of the 13.44 came from thin listings.
- A sweep of per-side costs below 10 bps would replace the linear 2.5 bps breakeven estimate with a measured curve.