Skip to content

View original

BtcSmartMoneyVsRetailDivergenceLS

Hypotheses

BTC Smart Money vs Retail Divergence: Long-Short on BTCUSDT.BINANCE 1H When Top-Trader vs Global L/S Ratio Z-Score Exceeds ±2

Hypotheses

A long-short directional strategy on BTCUSDT.BINANCE USD-M perpetual futures that exploits structural disagreements between SOPHISTICATED traders (Binance 'Top Long/Short Account Ratio') and RETAIL traders (Binance 'Global Long/Short Account Ratio'). The hypothesis: when top-trader positioning diverges significantly from global (retail-dominated) positioning, the sophisticated cohort tends to be RIGHT more often than wrong — they have better information, faster execution, and discretionary judgment that retail lacks. The divergence z-score, computed as a rolling 30-day measure on log(top_ls/global_ls), captures this 'smart-vs-dumb' positioning gap. When the z-score exceeds +2 (top traders significantly MORE long than retail), enter LONG BTC. When z ≤ -2 (top traders significantly MORE short than retail), enter SHORT BTC. This is structurally OPPOSITE to my prior crowdedness-reversal strategy (which fades crowded consensus): here we FOLLOW the dissenting minority. Both can coexist in the portfolio because they detect orthogonal market states. Fills FIVE under-represented buckets: long-short direction (14.1% → toward 45%), L/S-ratio-data-driven mechanism (zero strategies in 462 experiments have used this stream), smart-money sentiment edge (TradFi-equivalent of Commitment of Traders reports), mid-term hold (8-24h cycles), and BINANCE-USD-M-only (proven clean data, avoiding all BINANCE_SPOT failure modes). Position sizing: 15% of equity per direction. Risk per trade: 1.5% of equity capped by stop-loss.

Hypotheses

Iteration-3 fix for the Layer-3 sandbox crash "'float' object is not callable / Bars processed: 0". Root cause: the strategy stored the stop-loss percent in self._stop, which shadows NautilusTrader's reserved Component lifecycle method Strategy._stop(). The backtest ran but the engine crashed at teardown when it invoked self._stop() and found a float, so the run was reported with 0 bars. The smallest safe fix renames the attribute to self._stop_pct in all three occurrences (assignment, guard, and the should_exit comparison). No other logic changed: imports stay clean (Layer 1), the continuous z-score signal is untouched (Layer 2), and the entry/exit/sizing that already reached Layer 3 are preserved. This keeps every previously-passing layer green while eliminating the reserved-name collision.

Hypotheses

Data-availability wall (not a code fix, so not iterable): the strategy depends on Binance Top/Global Long-Short Account Ratio streams, but those endpoints only serve a short rolling history (~30 days). The engine swept 56,852 hourly bars yet only 8 entries fired, all inside a ~18-day recent window (data_days=18) — because the divergence z-score only becomes valid where the ratio data exists. 8 trades cannot support a 3-window walk-forward + 15-day holdout, and the headline metrics (Sharpe 1.47, PF 1.44) are noise (Sharpe CI [-6.12, +9.30], IR -0.70). The developer cannot manufacture historical L/S-ratio data Binance never provided, so optimization would only overfit 8 points. This is why zero of 462 prior experiments used this stream — the mechanism is un-backtestable at statistical scale. Recommend a research-side note to the Research Lead: any L/S-account-ratio-driven hypothesis is blocked by the ~30-day data history and should not be re-proposed unless the factory has continuously accumulated many months of this stream first (verify stored coverage before coding).

Implementation

Long/short BTCUSDT.BINANCE USD-M perp on 1H bars that follows smart-money vs retail divergence. Computes a rolling z-score on log(top_account_ratio / global_account_ratio); z>=+2 (top traders more long than retail) goes LONG, z<=-2 (top traders more short) goes SHORT. Exits on divergence close, take-profit, stop-loss, or a 48-bar time cap.

Verification Results

Verification failed (Layer 3 — sandbox backtest): 'float' object is not callable Bar type used: BTCUSDT.BINANCE-1-HOUR-LAST-EXTERNAL, Bars processed: 0 Ensure your strategy produces trades with the given data and parameters.

Backtest Review

Code is correct and functional: builds both L/S-ratio series with O(log n) causal lookup, streaming z-score, and the 8 trades that fired implement the stated follow-the-dissenting-smart-money mechanism (long when top-traders more long, short when more short).

Backtest Review

Clean instrument choice (BTCUSDT.BINANCE USD-M), no dropped orders (0 size-zero, 0 min-notional, 0 cash-short), sensible risk plumbing (15% sizing, TP/stop/time-cap exits).

Backtest Review

STRUCTURAL DATA WALL: only 8 entries signaled out of 56,852 bars seen, all clustered in a ~18-day window (data_days=18) in 2026-03..2026-05. The Binance Top/Global Long-Short Account Ratio endpoints only provide a short rolling history (~30 days), so the two streams the strategy depends on do not exist over the 6.5-year backtest span and cannot be backfilled.

Backtest Review

8 trades is far too few for a valid 3-window walk-forward + 15-day holdout — optimization would fit parameters to 8 points (pure overfit).

Backtest Review

The flattering headline (Sharpe 1.47, PF 1.44, win rate 62.5%) is statistically empty: Sharpe CI spans [-6.12, +9.30] and information_ratio is -0.70. No power to distinguish edge from noise.

Backtest Review

long_trades=2 / short_trades=6 — the sample is too small to even characterize the long vs short sides.

Outcome Summary

This strategy aimed to open an entirely new mechanism class for the portfolio — a 'smart-money vs retail' edge following the dissenting minority when Binance top-trader positioning diverged from retail by a z-score of ±2 — and its code implemented the idea cleanly with efficient causal lookups and sound risk plumbing. But it hit a structural data wall: the Top/Global Long-Short account-ratio endpoints only provide about 30 days of rolling history, so across 56,852 hourly bars only 8 trades could fire, all inside an 18-day 2026 window, making its Sharpe-1.47 headline pure noise (CI [-6.12, +9.30]). The analyst abandoned it at backtest review before optimization — a data-availability failure, not a code fix — noting this is why zero of 462 prior experiments used this stream, and recommended that L/S-account-ratio hypotheses be blocked until the factory has continuously accumulated many months of the data first.

Outcome Summary

Verify that a supplementary data stream has enough continuous historical coverage to backtest at statistical scale before coding a strategy on it — the Binance L/S account-ratio endpoints only retain ~30 days, so any L/S-ratio-driven hypothesis is un-backtestable and should not be re-proposed unless the factory has first accumulated many months of the stream.

Outcome Summary

The analyst abandoned it at the backtest-review gate before any optimization ran (optimization report and analyst verdict are null): the Binance Top/Global L/S account-ratio endpoints only serve ~30 days of rolling history, so the two data streams the strategy depends on do not exist over the 6.5-year backtest and cannot be backfilled — 8 trades cannot support a walk-forward plus holdout, and the wall is a data-availability issue, not a fixable code bug.

Outcome Summary

A long-short directional strategy on BTCUSDT.BINANCE 1H perp that followed the dissenting 'smart money': it computed a rolling z-score of the divergence between Binance's Top (sophisticated) and Global (retail) Long/Short account ratios, going long when top traders were significantly more long than retail (z ≥ +2) and short when they were more short (z ≤ -2).

Outcome Summary

The code was correct and the mechanism fired as designed, but only 8 trades signaled across 56,852 hourly bars, all clustered in a single ~18-day window (data_days=18); the headline metrics (Sharpe 1.47, profit factor 1.44, 62.5% win rate, +0.41% total return) were statistically empty, with the Sharpe CI spanning [-6.12, +9.30] and information ratio -0.70.

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['z_entry', 'stop_pct', 'min_notional', 'z_window_bars', 'take_profit_pct'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: BtcSmartMoneyVsRetailDivergenceLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - steady_downtrend: TypeError: BtcSmartMoneyVsRetailDivergenceLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - flat_ranging: TypeError: BtcSmartMoneyVsRetailDivergenceLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - volatility_spike: TypeError: BtcSmartMoneyVsRetailDivergenceLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - zero_volume: TypeError: BtcSmartMoneyVsRetailDivergenceLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - price_gap: TypeError: BtcSmartMoneyVsRetailDivergenceLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000)
Strategy report

Backtest and paper results are hypothetical. Trading involves risk of loss.