Strategies
Hyperliquid Downside-Beta Risk Premium: Long Crash-Sensitive Alts Against Matched Low-Sensitivity Alts
Outcome: Abandoned
HyperliquidDownsideBetaPremiumPair
Outcome Summary
HyperliquidDownsideBetaPremiumPair tested whether a published crypto downside-beta premium carries over to four Hyperliquid perpetuals, using beta-matched long/short pairs on synchronized 4-hour bars. Over 4 iterations the code was revised: leverage was set explicitly to 1.0 in iteration 3, and iteration 4 replaced the per-bar array rebuilds with a numpy ring buffer. Every attempt still timed out in the Layer 3 sandbox backtest at the 300s limit, so the run was abandoned in verification. It never reached backtesting, optimization, analyst review or risk review, and the hypothesis is still untested.
Hypothesis
Test whether investors demand compensation for asymmetric exposure to crypto market losses. Use synchronized 4-HOUR bars across LINK, AVAX, XRP and DOGE perpetuals, selecting one long-short pair with similar ordinary market betas but different downside betas. Long the more downside-sensitive asset; short the less sensitive asset. This deliberately accepts downside risk rather than forecasting price reversal or ranking momentum. Source: [Is downside risk priced in cryptocurrency market?](https://www.sciencedirect.com/science/article/pii/S1057521923004635), which reports a positive downside-beta premium in historical cryptocurrency samples; transfer to these four Hyperliquid perpetuals remains unproven. HyperliquidCollector supplies exact perpetual OHLCV. Local parquet timestamps were checked: common coverage begins 2024-02-07T12:00:00Z and ends 2026-10-02T00:00:00Z, with isolated gaps in three legs. Trade only on complete synchronized observations and restart warm-up after gaps.
Hyperliquid is 7.5% of experiments against a 20% target; long-short strategies are 16.7% against an implied minimum of 45%. This hypothesis addresses both deficits and reduces single-symbol concentration. Options remain underrepresented, but their documented structural failures make another options proposal unjustified. Unlike prior Hyperliquid pair reversals, this tests compensation for bearing asymmetric systematic risk, without assuming cointegration or spread convergence. Corpus concentration was empty, so exact symbol shares could not be assessed. The supplied library excerpts did not provide a suitable implementable mechanism.
verification_loop: sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (2400 days of LINKUSD.HYPERLIQUID-4-HOUR-LAST-EXTERNAL). This almost always means per-bar work that scales with history — e.g. rescanning the full funding/supplementary series, or rebuilding a list and calling min()/sorted() inside calculate_signal()/on_bar() on every bar. Precompute sorted timestamp arrays ONCE in __init__ and use bisect, or cache lookups keyed by timestamp, so per-bar cost is O(log n) not O(n).
Implementation
Long-short pair on four Hyperliquid perps (LINK, AVAX, XRP, DOGE) using 4h bars. On every complete synchronized observation it estimates each leg's ordinary beta and downside beta against an equal-weight market factor over beta_lookback_bars. Among pairs with ordinary betas in [0.5, 2.0] that differ by at most 0.2, it picks the largest downside-beta gap. If that gap is at least asymmetry_gap, it goes long the high-downside-beta leg and short the low one at equal notional. Positions are held 84 bars, with a pair stop anchored at entry (min of 8% and 2x spread volatility) and a 6-bar cooldown.
Iteration 4 fixes the Layer-3 sandbox timeout. The only code change is to the per-bar data structure: the deque of return tuples, re-converted with np.asarray every bar (about 1ms per bar), is replaced by a preallocated numpy ring buffer used in place. All window statistics are order-invariant, so signals, pair selection, sizing and exits are unchanged. Ring counters are added to PERSIST_EXCLUDE because warm-up rebuilds the ring. However, profiling a local sandbox run with py-spy showed the wall clock was not spent in strategy code. The backtest child spent more than 6 minutes inside NautilusTrader's ParquetDataCatalog.bars() -> fsspec glob/walk over data/catalog/data/bar, which holds 133,589 bar directories, while loading the primary leg at runner.py:683, before any bar reached the strategy. Even the old per-bar numpy cost was about 15-20s over the 14k-bar window. If this times out again, the cause is the catalog file listing (engineering issue), not the hypothesis or the strategy, and it should be escalated rather than iterated (lesson 155 c/b).
Verification Results
sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (2400 days of LINKUSD.HYPERLIQUID-4-HOUR-LAST-EXTERNAL). This almost always means per-bar work that scales with history — e.g. rescanning the full funding/supplementary series, or rebuilding a list and calling min()/sorted() inside calculate_signal()/on_bar() on every bar. Precompute sorted timestamp arrays ONCE in __init__ and use bisect, or cache lookups keyed by timestamp, so per-bar cost is O(log n) not O(n).
After submitting, check that both legs have an open position or a pending order on the next bar. If only one leg exists, flatten it instead of treating the pair as open.
The two legs are submitted independently. If _submit_entry_instrument drops one leg (market not ready, entry already in flight, or a paused block), _pair_open is still set True. The surviving leg is then held unhedged for up to 84 bars. _manage_open still computes pair PnL from both legs' closes, so the stop is measured on a position that does not exist.
Keep as is, or in a later iteration consider a broader market factor that does not include the traded legs. That would need a hypothesis change to declare the extra instrument.
The market factor is the equal-weight mean of the four traded legs. Each leg makes up 25% of its own benchmark, which pulls ordinary betas toward 1 and dampens downside-beta dispersion. The hypothesis does not name a market proxy, and the developer says this was done deliberately so the strategy stays inside the declared universe, so this is acceptable. It is still a weaker market proxy than in the source paper.
Optional: add reduce-only stop orders per leg if tighter loss control is needed.
The pair stop is checked only on 4h bar closes and exits with market orders, so a gap through the stop can lose more than stop_pct. The hypothesis does not specify a fixed stop, so this is informational only.
Cache the window as a rolling numpy ring buffer, or recompute betas only when flat and outside cooldown. Betas are not needed while a pair is held, since exits use only time and price.
Runtime: the sandbox took 258s for 4,340 four-leg bars, close to the 300s limit. Per-bar work is bounded (a 360x4 numpy window rebuilt from the deque, with no history rescan), so cost does not grow with the backtest span. Still, a full run of about 5,800 bars times the optimization trials will be slow. runtime_review_required is set.
The sandbox ran 725 days and closed 14 pairs (28 positions). Profit factor was 0.998 and avg_trade_return_pct 0.027%, well below the ~0.15% round-trip floor. Modeled impact was 110% of gross, so impact alone exceeded the gross edge. Funding was not folded in (funding_events_available=0), even though each pair is held 14 days on Hyperliquid perps where funding can be several bps a day per leg. The analyst should check the full-history per-pair return after impact and funding first. Also check that the downside-beta gap persists out of sample (the betas are estimated against a four-coin equal-weight basket, not a broad market). The source paper's premium is cross-sectional across hundreds of coins, and its transfer to one pair chosen from four coins is unproven, as the hypothesis itself says.
Analysis
Iteration History
Verification failed (Layer 3 — backtest process): the strategy could not be loaded/built in the backtest process: ory/src/backtesting/supp_collector.py", line 684, in _ensure_then_load_supp return await _load_supp_with_per_leg_funding(instrument_id, legs, db_url, keys) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/strategy-factory/src/backtesting/supp_collector.py", line 749, in _load_supp_with_per_leg_funding await load_supplementary_data(instrument_id, db_url=db_url, only_keys=keys) File "/opt/strategy-factory/src/backtesting/supp_collector.py", line 812, in load_supplementary_data hl_db_funding = await _load_hl_funding_from_db(db_url, base) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/strategy-factory/src/backtesting/supp_collector.py", line 598, in _load_hl_funding_from_db add_funding_observation(out, ts_ns, row[1], f"hyperliquid/{base_symbol}") File "/opt/strategy-factory/src/ba
Verification failed (Layer 1.5 — hypothesis/config consistency) [class=hypothesis_mismatch]: - optimization_plan fixes leverage at 1.0
Outcome Summary
A multi-leg pair strategy that recomputes rolling covariance and downside-beta statistics for every candidate pair on every bar must keep its per-bar work cheap enough to clear the sandbox time budget, so profile it on the full-length window before submitting.
It was abandoned in the verification loop after 4 iterations. The Layer 3 sandbox smoke test went over the 300s wall-clock limit on a window of about 20,000 bars (2400 days of LINKUSD.HYPERLIQUID 4-hour bars), and this happened again even after iteration 4 moved the synced returns into a preallocated numpy ring buffer.
Harvest a downside-beta risk premium on Hyperliquid 4-hour perps (LINK, AVAX, XRP, DOGE) by going long the more crash-sensitive leg and short a matched leg with a similar ordinary beta but lower downside beta.
No performance metrics exist: the backtest report is empty and no optimization was run, so there are no figures for return, Sharpe or trade count.
Backtest and paper results are hypothetical. Trading involves risk of loss.