+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
| Strategy | Category | Total return | CAGR | MaxDD | Sharpe | Trades |
|---|---|---|---|---|---|---|
| di_cross | trend | +11.80% | +11.83% | -37.59% | 0.50 | 361 |

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 68Data: 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.