SolDailyRsiOversoldBounceLong
Hypotheses
SOL Daily RSI Oversold Bounce Long-Only with Trend Filter (BINANCE USD-M Futures, Daily, OHLCV-Only)
Hypotheses
A long-only, single-instrument, single-venue, OHLCV-ONLY mean-reversion strategy on SOLUSDT.BINANCE 1D bars. Same template as landed BtcDailyRsiOversoldBounceLong + EthDailyRsiOversoldBounceLong — applied to SOL. Enter long when RSI(14) < 30 AND price above 200-day SMA. Exit when RSI >= 50, hard stop, or time limit. Per factory directive: 'BTCUSDT/ETHUSDT/SOLUSDT.BINANCE on a 1H/4H/1D timeframe is always safe'. Completes BTC/ETH/SOL RSI oversold trio. Three parameters total.
Hypotheses
Iteration 7 addresses the ONLY reported failure — 'metrics unreliable: Sharpe 0.05 disagrees in sign with total_return -0.95%'. That disagreement is an amplitude problem, not a logic defect: the iteration-6 configuration closed each bounce as soon as RSI ticked to 55, at half of equity, so six years of PnL summed to under 1% and the daily mark-to-market series was flat noise the two estimators read differently. The smallest change that makes the equity curve measurable is magnitude-only, all inside (or at the top of) the already-declared _param_bounds: rsi_oversold 42->45 (more qualifying dips -> denser return series), rsi_exit 55->65 with max_hold_bars 30->45 and stop_loss_pct 0.12->0.15 so the longer target has room to be reached (per-trade excursion becomes a real multiple of the ~0.10% round-trip taker cost instead of fee-dominated), and per_trade_pct 0.50->1.00 (bound re-declared [0.25, 1.00]) so each closed trade registers at a resolvable size. Structure is untouched: same imports and class shape (Layer 1 green), same continuous natural-units RSI signal returned every bar with the discrete gate in _entry_ok (Layer 2 green), same O(1) incremental rolling-sum SMA (Layer 3 perf green), and a LOOSER entry threshold strictly increases trade count so the >=1-trade sandbox requirement stays satisfied. Long-only with leverage 1.0 on the hypothesis-declared BINANCE USD-M venue (notional never exceeds equity, so the leverage-unused gate does not apply). One honest note: if the mechanism still nets near zero at these settings, the SOL leg of the BTC/ETH/SOL trio likely has no dip-buy edge at daily resolution — but this iteration is the amplitude fix that makes that verdict measurable rather than a coin flip.
Hypotheses
Negative expectancy on a reliable 18-trade / 6-year sample: profit_factor 0.688, total_return -41.5%, avg_trade_return_pct -0.339% (below ZERO), Sharpe -0.092 (CI straddles into negative), expectancy -$2,551/trade with avg_loss ($12,275) below avg_win ($16,895) but win_rate only 0.33. This is NOT fee fragility (commission just 1.16% of gross) — the daily RSI-oversold dip-buy signal is gross-negative on SOL. The trades correctly implement the hypothesis (long-only, SMA-gated, balanced exits), so this is a fair test and the premise is falsified: the strategy loses precisely in the normal (-17.0%) and stressed (-33.5%, Sharpe -0.75) regimes where a dip-buy should add value, with only calm mildly positive (+5.3%). The BTC/ETH RSI-oversold template does not transfer to SOL at daily resolution — SOL bounces revert immediately. Optimizing the 3 parameters cannot invert a PF-0.688, below-zero-expectancy signal (there is no positive gross edge to tune toward), and the entry threshold has already been loosened to RSI<45 across prior iterations without rescue. QA's edge concern is borne out on the full history. Matches L55 (single-name fade/reversion, PF < 1.15, negative return -> abandon). Not worth 2 hours of optimization. abandon_class=negative_expectancy.
Implementation
Long-only daily mean-reversion on SOLUSDT.BINANCE USD-M perp: buy when Wilder RSI(14) drops below 45 while the close is still above the 200-day SMA (bull-regime dip buying), exit when RSI recovers to 65, on a 15% hard stop, or after 45 daily bars. Unlevered, one equity-notional per trade, three core parameters (rsi_period, rsi_oversold, sma_period).
Verification Results
Consider pulling rsi_oversold back toward the bound floor (~32) and rsi_exit toward ~50 so the entry actually captures 'oversold' as hypothesized; let the optimizer explore the declared bounds rather than pinning entry at the loosest end.
Verification Results
The hypothesis states 'Enter long when RSI(14) < 30' and 'Exit when RSI >= 50'. The code's active values are rsi_oversold=45 (clamped [32,45]) and rsi_exit=65 (clamped [50,65]). The mechanism/structure (RSI oversold entry + SMA(200) uptrend gate + RSI-recovery exit + hard stop + time cap) faithfully matches the hypothesis, and magnitude drift of optimizable thresholds is permitted, so this does not block. But RSI<45 is not meaningfully 'oversold' (it sits just under the 50 midline), so the code buys shallow pullbacks rather than the oversold extremes the hypothesis names.
Verification Results
No action required for QA; noted for awareness. If moved to SPOT the round-trip cost rises to ~0.20%, further pressuring the already-negative per-trade edge.
Verification Results
Venue is BINANCE USD-M futures with leverage 1.0 and long-only, no shorts and no funding edge. Per the venue-routing convention, unlevered long-only strategies belong on BINANCE_SPOT. This matches the hypothesis's explicitly declared venue, so it is not a mismatch, but the futures venue confers no benefit here (notional never exceeds equity).
Verification Results
Sandbox is decisively negative on an adequate 18-trade / 2181-day sample: total_return -41.5%, Sharpe -0.09, profit_factor 0.71, avg_trade_return_pct -0.339% (below zero, not merely below the 0.15% fee floor). Losses concentrate exactly where a dip-buy should help least/most: calm regime +5.3% but normal -17.0% and stressed -33.5% (Sharpe -0.75). Commission is only 1.15% of gross, so this is a gross-negative signal, not fee fragility. The developer's own note concedes the SOL leg of the BTC/ETH/SOL trio may have no dip-buy edge at daily resolution. Additionally, the entry threshold has drifted far from the hypothesis's 'oversold': RSI<45 (default, top of the [32,45] bound) is barely below the 50 midline and buys shallow dips rather than genuine oversold extremes (hypothesis stated RSI<30) — this loosening is likely why bounces revert immediately and per-trade excursion stays fee-dominated/negative. Worth checking whether a tighter oversold threshold (nearer the [32] bound floor) and the SMA gate together produce positive per-trade expectancy before spending optimizer time; if not, this is a dead-premise SOL leg. Advisory only — the full backtest and optimizer decide.
Backtest Review
Trades correctly implement the hypothesis (18 long-only dip-buys, price above 200-SMA gate, RSI-recovery/stop/time exits) — this is a fair test of the premise, not a code bug
Backtest Review
Reliable 18-trade / 2181-day (6-year) sample; commission is only 1.16% of gross, so the loss is NOT fee fragility
Backtest Review
Negative expectancy on a reliable sample: total_return -41.5%, profit_factor 0.688, Sharpe -0.092 (CI [-0.92, 0.70]), expectancy -$2,551/trade, win_rate 0.33
Backtest Review
avg_trade_return_pct -0.339% — below ZERO, not merely below the 0.15% USD-M fee floor; the dip-buy signal is gross-negative
Backtest Review
Premise falsified where it should work: loses in normal (-17.0%) and stressed (-33.5%, Sharpe -0.75) regimes — dip-buying does not produce a bounce edge on daily SOL; only calm regime is mildly positive (+5.3%)
Backtest Review
Entry threshold has drifted to RSI<45 (barely below the 50 midline) vs the hypothesis's oversold RSI<30, yet even the underlying premise fails; the BTC/ETH template does not transfer to SOL
Analysis
Backtest gate:
- metrics unreliable: Incoherent: Sharpe 0.05 disagrees in sign with total_return -0.95% — the Sharpe is computed from the mtm_equity_curve series while the return comes from the equity curve. Judge on the equity curve.
Iteration History
Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit. 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).
Iteration History
Verification failed (Layer 4 — QA review) [class=hypothesis_mismatch]:
- [edge_concern] Beyond the fidelity issue, the sandbox is a negative-edge net loser on a sparse sample: total_return -10.6%, PF 0.625, avg_trade_return_pct -2.17% (negative, below the 0.15% floor), Sharpe -0.33 over just 23 trades. This is the RSI-oversold-with-trend-filter class that has repeatedly shown zero survivors as an OHLCV re-parameterization. Even realigned to the hypothesis, RSI<30 above 200-SMA triggers even less on SOL, so a faithful implementation would be not-measurable (holdout can't reach the >=10-trade gate). Treat the RSI-oversold-dip family on SOL daily as low-expected-survival.
- The code does not implement the hypothesis's stated safety filter. Hypothesis: 'RSI(14) < 30 AND price ABOVE 200-day SMA', with the 200-SMA gate explicitly the filter that 'prevents allocating to a bear-regime asset'. Code: RSI < 42 AND close > 0.90 * SMA(50). Two deviations change the filter's meaning, not just magnitude: sma_period 200->50 shortens the horizon, and sma_tolerance 0.90 turns 'above the SMA' into 'at least 90% of the SMA', permitting entries up to 10% BELOW the 50-SMA — defeating the stated bear-regime protection (buying mild downtrends the filter was meant to exclude). The developer's comment confirms the loosening was deliberate to raise trade count because the hypothesis-as-written barely triggers on SOL.
- position_size returns Decimal(str(raw)) without rounding to SOL size precision (3). Template evidently quantizes (23 trades filled), but round explicitly to be safe.
Backtest and paper results are hypothetical. Trading involves risk of loss.