trading2026-08-10Β·8 minΒ·17/68

+DI/-DI Cross Backtest on BTC/USDT: +11.80% Net β€” Why the ADX Filter Was Worth 38 Points

The raw +DI/-DI directional cross on real hourly BTC/USDT 2023: +68.82% naive, +11.80% after fees and funding, 361 trades. Dropping the ADX filter from post 06's ADX/DMI rule costs 38 net points β€” the filter's real value.

+DI/-DI Cross Backtest on BTC/USDT (2023, hourly, real fees)

Post 06 tested the full ADX/DMI rule: long when +DI is above βˆ’DI and ADX is above 20. It made +49.66% net. This post removes the second condition β€” just the +DI/βˆ’DI cross, no ADX confirmation β€” to find out exactly what the trend-strength filter is worth. The answer: +38 points of net return. Same oscillator family, same data, one filter difference. Strategy Lab #68.

The setup

+DI and βˆ’DI from Wilder's DMI, both smoothed over 14 bars. Long when +DI > βˆ’DI. No ADX threshold, no other filter. Same engine, same costs.

Results

StrategyCategoryTotal returnCAGRMaxDDSharpeTrades
di_crosstrend+11.80%+11.83%-37.59%0.50361

+DI/-DI cross vs buy & hold (2023, hourly, BTC/USDT)

The fee bill

| Scenario | Cost/leg | Total return | MaxDD | Sharpe | Trades | |---|---:|---:|---:|---:|---:|---:| | naive (zero cost) | 0.00% | +68.82% | -21.94% | 1.77 | 361 | | taker fee 0.05%/leg | 0.05% | +17.66% | -35.89% | 0.66 | 361 | | + funding 0.01%/8h | 0.05% | +11.80% | -37.59% | 0.50 | 361 | | + slippage 10bp/leg | 0.15% | -45.73% | -61.19% | -1.69 | 361 | | + slippage 25bp/leg | 0.30% | -81.67% | -84.23% | -4.88 | 361 |

The raw cross is net-positive but thin: +11.80%, Sharpe 0.50, and a -37.6% drawdown that is worse than holding BTC. Notably, the filtered rule of post 06 grossed +92.23% β€” higher than the raw cross's +68.82%. The ADX filter didn't just protect the returns; it added gross edge, because it kept the position out of the churning no-trend periods where the raw cross was long on +DI/βˆ’DI flips. The raw cross traded 361 times to the filtered rule's 216.

The filter's value, isolated

| Rule | Post | Trades | Naive | Fees+funding | MaxDD | |---|---:|---:|---:|---:|---:|---:| | +DI/βˆ’DI + ADX>20 | 06 | 216 | +92.23% | +49.66% | -29.92% | | +DI/βˆ’DI only (this) | β€” | 361 | +68.82% | +11.80% | -37.59% |

One condition β€” "ADX > 20" β€” is worth 38 net points, a 145-trade reduction, and 8 points of drawdown improvement. This is the lab's cleanest single-filter experiment: both rules are identical except for the trend-strength requirement. On 2023 BTC, the ADX threshold was doing real work: it kept the rule out of the spring correction and the late-year chop, exactly the periods where the unfiltered cross bled. A filter that trades less is not a cost β€” on this data it is the edge.

What this does NOT prove

  • The 20 ADX threshold is Wilder's default; a lower threshold (10) or higher (30) changes the trade count and the result. One point in that space is tested here, the other posts tested none.
  • +DI/βˆ’DI is sometimes traded with the ADX as a buy-signal requirement (+DI rising through βˆ’DI only when ADX is falling from a high) β€” a different, rarer setup, untested.
  • One pair, one year, one regime.

Code

from backtest_base import fetch, backtest_signal, metrics
from strategy import sig_di_cross

df = fetch("BTCUSDT", "binance", "2023-01-01", "2023-12-31", "1h")
signal = sig_di_cross(df, period=14)

res = backtest_signal(df, signal, cost_per_leg=0.0005, funding_per_bar=0.0000125)
print(metrics(res, 8760))

Reproduce it

cd blog-drafts/scripts
python gen_post_assets.py --ids 68

Data: Binance public API, hourly OHLCV, 8,735 bars. Tables above reproduce exactly from this command.

This is a backtest on historical data, not investment advice. Past performance does not predict future results.