Backtest review · Bybit USDT perpetuals

XSMOM cross-sectional momentum, re-tested

The strategy ranks the 50 most-traded Bybit perps by 30-day volatility-normalised return, buys the top 5 that pass a trend filter and shorts the weakest. This page re-runs it on a point-in-time, survivorship-free universe (delisted coins included) with fees, slippage and historical funding, and subjects it to benchmark, random-selection, rank-IC, walk-forward and overfitting tests.

01Verdict

The published results (+$6,371, Sharpe ≈1.3–1.8) do not survive a correct backtest. They came from an earlier engine with a look-ahead stop-loss, on a universe of coins chosen because they are liquid today.

02What was wrong with the earlier analysis

Each item below changed the numbers; together they explain the gap between the old and new results.

Look-ahead and accounting

  • Stop-loss used the future: the old engine capped each trade's end-of-period loss at −15%, a free put that never stopped out trades that dipped and recovered. On the old data it added $1,377 of $6,371.
  • Published files were stale: the engine was rewritten but README, site and JSON were never regenerated.
  • ATR overstated 30/14×: 30 true ranges summed then divided by 14; the short floor −0.5 really meant −1.07.
  • Sizing: min–max scaling gave the weakest long zero weight (a phantom "losing" trade) and old gross exposure swung from $100 to $1,614 per period.
  • Sharpe annualised with √52 on biweekly periods (should be √26).

Universe and testing design

  • Survivorship / look-ahead universe: today's top-50 by 24h volume, re-downloaded every run (non-reproducible, and it included gold, oil and a 3× equity ETF).
  • Parameters chosen on 24 periods (~5 months) with the look-ahead stop, weekly vs biweekly compared over different spans.
  • Robustness matrix leaked state (BOTTOM_N=0 carried into the next config) and compared configs over different date ranges.
  • "Walk-forward" was a split-half of in-sample-optimised parameters; Monte Carlo resampled an already-biased P&L; no fees or funding.

03Results on the corrected engine

Cumulative return of the headline config, the original design, the survivorship-biased replica and BTC buy-and-hold
Cumulative return as % of a $100 capital base, non-compounded, after fees, slippage and funding.
ConfigurationPeriodsSharpeAnn. returnMax DDLong P&LShort P&LTrades

By year (% of capital)

Original design P&L decomposed into long price, short price, funding and costs
The original design's P&L split into price moves, funding and trading costs. Funding received on longs in squeezed small caps is the largest single source.
Drawdown chart
Drawdown in % of capital (gross exposure up to 200%).

03bComposition and rotation (headline config)

Is the long book rotating, or a proxy for holding a few coins? Computed from the per-trade records by composition.py.

Rotation

Top contributors (cumulative long P&L, $)

SymbolPeriodsWinsCum P&L

Long book by rebalance

RebalanceLong book

04Validation tests

Every test uses the same universe and cost model. "Headline" is the sweep-optimised config; "Original" is the pre-sweep design (weekly, MA50, no stop, bottom-5 shorts), which the full-history sweep ranks much higher.

TestHeadlineOriginalWhat it tells you

Execution and accounting sensitivity (annualised Sharpe)

VariantHeadlineOriginal

05Parameter sweep and overfitting

Histogram of Sharpe ratios across the sweep
Annualised Sharpe of every configuration on the same window, after costs.

Median Sharpe by parameter value

Top configurations

ConfigSharpeP&L

06Monte Carlo (headline config)

Moving-block bootstrap of the realised per-period returns. This measures sampling noise only; it cannot correct selection bias, which is what the deflated Sharpe and PBO above address.

Block lengthP(total > 0)Sharpe P5Sharpe P50Sharpe P95Max DD P95

07Methodology

Data

  • Crypto only: stock, ETF, commodity and forex perps, stablecoins and tokenised gold are excluded.
  • Daily candles with turnover; the in-progress candle is dropped. Funding from Bybit's settlement history for every symbol that ever entered the universe.

Engine

  • Universe at each rebalance = top 50 by trailing 30-day turnover among coins trading that day.
  • Signal = 30-day return / (mean daily true range % × √30). Entry at the signal candle's close; exit at the next rebalance close; intraday stops fill at the stop or the gapped open.
  • $100 long budget (weights ∝ signal) and $100 short budget (equal weight) on $100 capital. Taker fee 0.055% + 0.05% slippage per side, charged only on traded notional. Delisted coins exit at their last price.

08Caveats

09Reproduce

cd ..                                          # parent of the MOMSXperp package
python -m MOMSXperp.refetch_deep --funding     # snapshot instruments, klines, funding (~10 min)
python -m MOMSXperp.run                        # headline backtest
python -m MOMSXperp.robustness                 # config matrix
python -m MOMSXperp.montecarlo                 # bootstrap + jackknife
python -m MOMSXperp.sweep                      # 360-config grid, deflated Sharpe, PBO
python -m MOMSXperp.validation                 # benchmarks, null, IC, phase, walk-forward
python -m MOMSXperp.validation --config original
python -m MOMSXperp.composition                # rotation / contribution
python -m MOMSXperp.charts
python -m MOMSXperp.site_build                 # refresh this page's data
python MOMSXperp/tests/test_core.py            # unit tests