HyperliquidSolFundingExtremeContrarian
Hypotheses
Hyperliquid SOL Perp Funding-Extreme Contrarian — Long-Short, Single-Name: FADE Crowded Positioning When Rolling Funding Z-Score Hits an Extreme (Very Positive Funding = Over-Leveraged Longs → SHORT; Very Negative = Capitulated Shorts → LONG), Confirmed by Price Non-Confirmation, Exit on Funding Reversion / ATR Stop / Time Stop (SOLUSDT.HYPERLIQUID, 4H, 3-Parameter)
Hypotheses
A LONG-SHORT, single-instrument, POSITIONING-driven contrarian strategy on the Hyperliquid SOL perpetual, built around a NON-OHLCV mechanical signal — perpetual FUNDING — used the OPPOSITE way to the factory's dead cash-and-carry family. This is NOT a delta-neutral carry (which died because funding P&L was too small vs basis noise) and NOT price momentum (the HL momentum baskets are 0/84). Instead, funding is used as a crowding/positioning gauge to time a DIRECTIONAL fade: the well-documented result that when perp funding is extremely positive, longs are over-leveraged and paying to hold — a state that historically precedes LOWER forward perp returns (squeeze/washout risk), and symmetrically extreme-negative funding marks capitulated shorts that precede bounces. Chosen to fill three under-represented buckets at once: HYPERLIQUID (6.8% vs 20% target), long_short (14.2%), and a data-safe non-OHLCV edge that isn't in the OHLCV overfit graveyard. Single-name and 3-parameter deliberately, to keep it implementable (the multi-instrument HL baskets died in coding timeouts) and to resist overfitting. IMPLEMENTATION NOTE: maintain the funding baseline as a rolling deque updated incrementally (O(1) per update) — NEVER rescan the full funding series inside on_bar (that pattern caused the repeated 300s sandbox timeouts).
Hypotheses
Iteration 2 fixes the single Layer-2 failure (`FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given`, all six scenarios). The Layer-2 `_StrategyProxy` rebinds every callable attribute of the strategy onto a plain wrapper via `types.MethodType`, which converts the base class's one-argument `_bar_ts` staticmethod into a bound method — so `self._bar_ts(bar)` arrives with two arguments. The minimal fix replaces that one call with a module-level `_bar_timestamp_ns(bar)` helper that reads `bar.ts_event` (falling back to `ts_init`) directly — behaviourally identical, immune to the proxy's rebinding. Nothing else changed: imports, class structure, funding parsing, signal logic, entries, exits and sizing are byte-identical to the previous_code that passed Layer 1, so no earlier check can regress. Note `_bar_interval_ns` is still called from `__init__`, which runs on the real instance before the proxy rebinds anything, so it is unaffected. Leverage 2.0 is consumed in `position_size` via `self.config.leverage` in the gross-notional cap.
Hypotheses
Negative-expectancy single-name funding-extreme contrarian fade — no edge to optimize. PF 0.60, total_return -33.7%, Sharpe -0.42, expectancy -$156/trade, and avg_trade_return_pct -0.37% (negative, below the 0.15% Hyperliquid fee floor, L22). Losing in every year (2024 -14.8%, 2025 -13.8%, 2026 -6.5%) with both long and short legs sub-43% win rate and avg_loss > avg_win — the contrarian fade is systematically on the wrong side of the move, and the only positive month is a single +10.77% outlier day (kurtosis 9.8). The mechanism is well-implemented (no timeout, funding credited) but sits in two zero-survivor families: single-name mean-reversion/fade (L55) and single-perp supplementary(funding)-gated directional (L73). The price-non-confirmation gate did not add a real edge. The sign of the per-trade edge is negative, which no parameter tuning can flip. Not worth 2 hours of optimization. Failure pattern: fee_edge/no_edge single-perp funding-gated contrarian fade.
Implementation
Long-short single-name contrarian on the Hyperliquid SOL perp (4H bars). Funding is used as a crowding gauge: a rolling z-score of the hl_funding_rates print against its own trailing distribution is returned every bar as the continuous signal. Extreme positive z (crowded, over-paying longs) is faded with a SHORT; extreme negative z (capitulated shorts) is faded with a LONG, but only when price fails to confirm the crowd (close not making a fresh confirm_bars-bar high/low). Exits on funding reversion (|z| <= exit_z), an ATR stop snapshotted at entry, or a calendar time stop measured from position.ts_opened. Sizing is risk-first: the ATR stop costs ~risk_frac of equity, with an independent gross-notional cap.
Verification Results
CLEAN RESTART 2026-09-04 — this run's verdict history and learning records were removed and it was restarted from verification. Its previous abandonment came from the pipeline, not from the market: the Layer-2 harness mis-bound @staticmethod helpers (fixed), QA issued terminal performance verdicts on an unoptimized smoke test (removed — QA now judges correctness only), and sandbox timeouts came from backtest-slot starvation (fixed). The hypothesis and the strategy code are unchanged. Verify the code on its merits; performance is decided later by the full backtest and the optimizer.
Verification Results
Narrow _param_bounds to the 3 headline tunables (entry_z, exit_z, funding_lookback_prints); lock the risk/plumbing params as constants.
Verification Results
Hypothesis sells a '3-parameter deliberately, to resist overfitting' design, but _param_bounds exposes 11 optimizable params. Mechanism is correct, but an 11-dim walk-forward search contradicts the stated anti-overfit rationale and raises PBO risk. Not blocking.
Verification Results
None required; noted for the analyst.
Verification Results
Layer-2 synthetic signals all frozen at 0.0 (no funding injected), so the trading path was exercised only by the sandbox (which traded 65 times on real funding). Non-fatal.
Backtest Review
Mechanism fires cleanly and produces an adequate sample (201 trades over 953 days) with no timeout — the O(log n) funding implementation works as intended
Backtest Review
Single-instrument, single supplementary feed (hl_funding_rates), no data/verification pathology; funding is credited in PnL
Backtest Review
Negative expectancy: profit_factor 0.60, total_return -33.7%, expectancy -$156/trade
Backtest Review
avg_trade_return_pct -0.37% — negative and far below the 0.15% Hyperliquid fee floor (L22)
Backtest Review
Losing in all three years (2024 -14.8%, 2025 -13.8%, 2026 -6.5%) — a persistent no-edge, not a decayed one
Backtest Review
Both legs lose (long win 42%, short win 42%) with avg_loss > avg_win — the funding-extreme fade is on the wrong side of the move
Backtest Review
Sole positive month is a single +10.77% outlier day (kurtosis 9.8); the underlying tape is uniformly negative
Backtest Review
Single-name funding-gated directional fade — mean-reversion (0/174) and single-perp supplementary-gated directional (L73) zero-survivor classes
Iteration History
Verification failed (Layer 2 — synthetic scenarios):
Parameters used: ['exit_z', 'entry_z', 'atr_bars', 'risk_frac', 'min_prints', 'confirm_bars', '_param_bounds', 'atr_stop_mult', 'max_hold_bars', 'max_lag_seconds', 'max_notional_frac', 'funding_lookback_prints']
Check that __init__ sets all attributes from self.parameters.get().
- steady_uptrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690500000)
- steady_downtrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690500000)
- flat_ranging: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690500000)
- volatility_spike: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690500000)
- zero_volume: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690500000)
- price_gap: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690500000)
Backtest and paper results are hypothetical. Trading involves risk of loss.