TakerFlowPriceDivergenceReversalLS
Hypotheses
Taker-Flow / Price Divergence Reversal, Long-Short (3-Asset Liquid USD-M Basket ETH/BNB/ADA, 4h Bars + TAKER BUY/SELL VOLUME-RATIO Feed, Fade Price Extremes That Are NOT Confirmed by Aggressor Flow — Short a New High Made on FALLING Taker-Buy Dominance, Buy a New Low Made on RISING Taker-Buy Dominance, 3-Parameter)
Hypotheses
A LONG-SHORT, multi-instrument reversal on three liquid Binance USD-M perps (ETHUSDT, BNBUSDT, ADAUSDT) on 4h bars, driven by DIVERGENCE between price and the TAKER buy/sell volume ratio (sum_taker_long_short_vol_ratio in the Binance Vision metrics CSV — the ratio of aggressive market-buy to market-sell volume, multi-year history, reliable). The mechanism is microstructure, not a chart pattern: a price advance to a new local high that is made while AGGRESSOR buying is actually WEAKENING (taker-buy dominance falling) is a rally driven by passive/spoofed liquidity or short-covering with no real demand behind it — it tends to fail. Symmetrically, a new local low printed while aggressor SELLING is drying up (taker-buy dominance rising) is exhausted supply that bounces. This is deliberately distinct from the factory's other flow work: it is NOT trend-following aggressive flow (that is a separate long-only spot strategy) and NOT positioning-extreme fading (account ratio); it fades the specific case where realized aggressor FLOW contradicts the PRICE move. Deliberately 3-parameter (extreme_lookback, taker_smoothing, atr_stop_mult) to resist the overfit deaths, basket-diversified for trade count and robustness.
Hypotheses
Iteration 2 fix (Layer 2 synthetic failure): the reported TypeError — `_extract() takes 1 positional argument but 2 were given` — was caused by `_extract` being a `@staticmethod`. The Layer-2 verification proxy rebinds strategy methods onto its proxy object, which strips the staticmethod descriptor so `self._extract(rows)` passed `self` + `rows` (2 args) into a 1-parameter function. The SMALLEST fix is to make `_extract` a normal instance method (`def _extract(self, rows)`); every call site already used `self._extract(...)`, so no other code changed. All previously-passing logic (Layer 1 static + the entire signal/entry/exit/sizing design) is untouched: the continuous taker-vs-price divergence score, the fresh-extreme + flow-sign entry trigger, revert-to-mean + ATR-stop exits, and risk-based sizing are byte-identical to iteration 1. Design unchanged from iteration 1: single-instrument ETHUSDT on BINANCE USD-M futures (per-leg metrics/taker data is only injected for the primary instrument, so a literal ETH/BNB/ADA basket would have no flow data on the extra legs); 3 tuned parameters; risk-bounded sizing (leverage=1.0).
Hypotheses
No edge to optimize. Negative per-trade expectancy across a measurable 230-trade sample: avg_trade_return_pct -0.199% (below the fee floor), profit_factor 0.77, Sharpe -0.53 (CI [-1.15, 0.08]), total_return -36.1%, max_drawdown 49.0%, losing in 4 of 6 years (2024 -27.7%). The strategy exhibits the exact inverted reward:risk the hypothesis claimed to be 'deliberately distinct' from: despite a healthy 57.8% win rate, the revert-to-midpoint exit banks tiny wins (avg_win $885) while the ATR stop lets losers run ~1.8x larger (avg_loss $1,572), so expectancy is -$150.88/trade. It is the single-name reversal/fade class with inverted realized RR that has died repeatedly this session (SOL/XRP/DOGE/ADA/LINK fades, same signature). The 57.8% hit rate shows the entry timing isn't random, but tuning extreme_lookback/taker_smoothing/atr_stop_mult cannot flip a negative-expectancy signal whose payoff geometry is structurally upside-down, and avg_trade_return_pct is already negative. Note also the delivered strategy is single-name ETH, not the intended 3-asset basket. Abandon rather than spend 2 hours optimizing.
Implementation
Long-short microstructure reversal on ETHUSDT USD-M perp (4h bars) that fades price extremes NOT confirmed by aggressor flow. Flow is the taker buy/sell volume ratio (taker_long_short_vol_ratio from the Binance Vision metrics feed — aggressive market-buy vs market-sell volume, multi-year history). calculate_signal returns a CONTINUOUS divergence score D = long_strength - short_strength each bar: short_strength rises as price nears the top of its extreme_lookback range WHILE the smoothed taker-buy dominance is falling; long_strength rises as price nears the bottom WHILE taker-buy dominance is rising. Confirmed moves (price up on rising flow, or price down on falling flow) score ~0. Entry uses a binary trigger — a fresh new local high/low over extreme_lookback bars — combined with the divergence sign: SHORT a new high made on falling flow (signal<0), BUY a new low made on rising flow (signal>0). Exit is revert-to-mean (price retraces to its range midpoint) plus an ATR stop (atr_stop_mult x ATR). Positions are risk-sized: risk_frac of equity per trade over the ATR stop distance, capped at leveraged equity notional. Three tuned parameters only: extreme_lookback, taker_smoothing, atr_stop_mult.
Verification Results
Verification failed (Layer 2 — synthetic scenarios):
Parameters used: ['risk_frac', 'atr_period', 'min_notional', 'atr_stop_mult', 'min_ratio_pts', 'taker_smoothing', 'extreme_lookback']
Check that __init__ sets all attributes from self.parameters.get().
- steady_uptrend: TypeError: TakerFlowPriceDivergenceReversalLS._extract() takes 1 positional argument but 2 were given (bar timestamp: 1735690920000)
- steady_downtrend: TypeError: TakerFlowPriceDivergenceReversalLS._extract() takes 1 positional argument but 2 were given (bar timestamp: 1735690920000)
- flat_ranging: TypeError: TakerFlowPriceDivergenceReversalLS._extract() takes 1 positional argument but 2 were given (bar timestamp: 1735690920000)
- volatility_spike: TypeError: TakerFlowPriceDivergenceReversalLS._extract() takes 1 positional argument but 2 were given (bar timestamp: 1735690920000)
- zero_volume: TypeError: TakerFlowPriceDivergenceReversalLS._extract() takes 1 positional argument but 2 were given (bar timestamp: 1735690920000)
- price_gap: TypeError: TakerFlowPriceDivergenceReversalLS._extract() takes 1 positional argument but 2 were given (bar timestamp: 1735690920000)
Verification Results
Decide whether single-name ETH satisfies intent; if a true basket is required it needs per-leg taker supp. If accepted, weight OOS/holdout heavily.
Verification Results
UNIVERSE REDUCED FROM 3-ASSET BASKET TO SINGLE-NAME ETH (analyst/PM to rule). Hypothesis is a 3-asset basket (ETH/BNB/ADA) relying on the basket for trade count and robustness; config is single-instrument ETHUSDT. Developer discloses the framework constraint (taker/metrics supp injected for the primary only) and correctly declined a cross-name taker proxy (aggressor flow is name-specific). ETH is a named asset with identical mechanism — not a critical mismatch — but it removes basket overfitting protection.
Verification Results
Send to holdout but treat as fragile; confirm win rate/trade count survive OOS; consider a trailing exit to de-invert the RR.
Verification Results
Marginal, low-sample, inverted-RR edge: +4.66%, Sharpe 0.27 (CI [-1.34, 2.01] spans zero), only 52 trades (below ~100 floor). avg_win $1,225 < avg_loss $1,726 (0.71) — profitability rests on the 62% win rate because revert-to-mean caps wins at the midpoint while the 2-ATR stop lets losers run. Fragile: a small win-rate drop flips expectancy negative.
Verification Results
Verify the loaded key maps to sum_taker_long_short_vol_ratio; select the column explicitly if ambiguous.
Verification Results
Confirm the flow field is the taker aggressor-VOLUME ratio (taker_long_short_vol_ratio), not the count-based account ratio used by the sibling retail-crowding strategy — the two carry opposite interpretations.
Backtest Review
Well-defined, differentiated microstructure signal (taker-flow vs price divergence) with multi-year data
Backtest Review
Decent 57.8% win rate suggests entry timing isn't random
Backtest Review
230 trades = measurable; no liquidation
Backtest Review
avg_trade_return_pct -0.199% — negative per-trade expectancy, below the fee floor
Backtest Review
profit_factor 0.77, Sharpe -0.53 (CI [-1.15, 0.08]), total_return -36.1%, max_drawdown 49.0% (near hard-abandon)
Backtest Review
Inverted reward:risk despite 57.8% win rate — avg_win $885 is only ~0.56x avg_loss $1,572; the revert-to-midpoint exit caps wins while the ATR stop lets losers run, netting -$150.88/trade
Backtest Review
Losing in 4 of 6 years (2024 -27.7%); no durable regime
Backtest Review
Hypothesis specified a 3-asset ETH/BNB/ADA basket but code ran single-name ETH only — diversification absent
Backtest Review
This is the single-name reversal/fade class with inverted realized RR that has died repeatedly this session
Outcome Summary
This strategy sought a microstructure edge by fading price extremes that aggressor taker flow failed to confirm — shorting hollow new highs and buying exhausted new lows — deliberately framed as distinct from the fades that had died all session. The entry timing was not random (57.8% win rate), but the payoff geometry was upside-down: the revert-to-midpoint exit capped average wins at $885 while the ATR stop let losers run to $1,572, netting -$150.88/trade for a -36.1% total return, profit factor 0.77, and a 49% drawdown. Compounding the problem, the code ran single-name ETH rather than the intended ETH/BNB/ADA basket, so the promised diversification was absent. The analyst abandoned it at backtest review as yet another single-name reversal with inverted realized reward:risk — a negative-expectancy signal that tuning three parameters could not rescue.
Outcome Summary
A high win rate does not imply a positive edge — a revert-to-midpoint target paired with a wider ATR stop banks small wins and lets losses run ~1.8x larger, producing negative expectancy; the exit geometry, not the entry hit rate, decides whether a fade survives, and the delivered strategy must actually implement the hypothesized diversification.
Outcome Summary
The analyst abandoned it at the pre-optimization backtest-review gate: negative per-trade expectancy across a measurable sample with an upside-down payoff geometry (the same inverted reward:risk signature that killed the session's other single-name fades), losing in 4 of 6 years and sitting near the 50% hard-abandon drawdown line; parameter tuning could not flip a structurally negative-expectancy signal. It was also noted the delivered code ran single-name ETH only, not the intended 3-asset basket.
Outcome Summary
A long-short reversal that faded price extremes not confirmed by aggressor flow — shorting a new local high made while taker-buy dominance was falling (rally with no real demand) and buying a new local low made while taker-sell pressure was drying up (exhausted supply) — using the multi-year Binance taker buy/sell volume ratio, intended as a 3-asset ETH/BNB/ADA 4h basket.
Outcome Summary
Over 230 trades (99 long / 131 short) it was a net loser despite a healthy 57.8% win rate: avg_trade_return_pct -0.199% (below the fee floor), expectancy -$150.88/trade, profit factor 0.77, Sharpe -0.53 (CI [-1.15, 0.08]), total return -36.1%, and max drawdown 49.0%. The reward:risk was inverted — avg win $885 was only ~0.56x avg loss $1,572 — as the revert-to-midpoint exit capped winners while the ATR stop let losers run.
Backtest and paper results are hypothetical. Trading involves risk of loss.