Vai al contenuto

Visualizza l’originale

CryptoLowVolAnomalySpotBasketLongOnly

Ipotesi

Anomalia di Bassa Volatilità Crypto, Selezione Solo Long (Nessuna Gamba Short): Detenere i 5 Nomi a LOWEST-Volatilità-Realizzata di un Universo Spot Liquido Fisso di 25 Coin, Equal-Weight, Ribilanciamento a 10 Giorni su Barre DAILY, Book Scalato a un Target di Volatilità Ex-Ante 15% — Puro OHLCV, Nessun Gate, Nessun Feed Supplementare

Ipotesi

Una strategia cross-sectional LONG-ONLY, SELECTION-BASED (esplicitamente NOT dollar-neutral, NOT beta-hedged, NO gamba short) su BINANCE_SPOT in un universo liquido FIXED di 25 titoli. Ogni 10esima barra giornaliera, ogni moneta viene classificata in base alla propria volatilità realizzata trailing a 20 giorni e vengono detenute le 5 LOWEST a peso uguale; l'intero portafoglio viene poi scalato con un unico fattore min(1.0, 0.15 / mean_RV_of_the_5) in modo che il portafoglio abbia come obiettivo una volatilità annualizzata di ~15% e non superi mai un nozionale di 1.0x (senza leva, conto cash). Non c'è alcun termine di momentum, alcun filtro di trend, alcun gate di regime, alcun feed supplementare, né alcun parametro di soglia — la volatilità realizzata è l'unico segnale ENTIRE e viene utilizzata come RANK, non come un gate on/off. Ho misurato questo prima di proporlo, sul catalogo, piuttosto che affermarlo. Decodificando direttamente le barre a virgola fissa di Nautilus (BINANCE_SPOT giornaliere, 25/25 titoli presenti, 2017-10-27 -> 2026-09-19, ~9 anni), la configurazione sopra restituisce uno Sharpe +0.74 NET dell'intero round-trip spot 0.20%, 13.4% annualizzato su una volatilità 18.1%, drawdown massimo -33.6%, 430 operazioni e un rendimento medio per operazione di 1.37% del nozionale della posizione. Per anno solare: 2018 -19%, 2019 +17%, 2020 +49%, 2021 +40%, 2022 -26%, 2023 +40%, 2024 +41%, 2025 +6%, 2026 -5% — 6 anni positivi su 9, e sopravvive a BOTH mercati ribassisti completi. CRITICAL ROBUSTNESS EVIDENCE (questo è un controllo di replicazione, NOT una gamba proxy — la strategia opera solo su BINANCE_SPOT): la stessa regola di classificazione è stata eseguita in modo indipendente su BYBIT perpetui lineari e BINANCE perpetui USD-M. Su una finestra 2022-2026 allineata per data, i due exchange concordano fino alla seconda cifra decimale — Sharpe della bassa volatilità +0.58 (Bybit) vs +0.57 (Binance), alta volatilità +0.11 vs +0.11, rendimento annuo 31.0% vs 30.4% — rispetto a un benchmark a peso uguale di +0.25/+0.21. Lo stesso effetto si riproduce su tre pipeline di dati indipendenti relative agli exchange. Su una finestra non allineata gli exchange sembravano essere in disaccordo (0.38 vs 1.01); si trattava puramente di un artefatto legato all'inizio della serie storica (l'universo di Bybit è incompleto prima di 2022), che ho isolato anziché riportare come risultato. Causa economica e WHO PAYS: questa è l'anomalia della bassa volatilità / preferenza per la lotteria (Bali-Cakici-Whitelaw; Frazzini-Pedersen), e le criptovalute ne sono l'habitat più puro. Le monete ad alta volatilità realizzata sono dove si concentra il flusso retail in cerca di leva e di 'lotteria' — vengono spinte al rialzo perché gli acquirenti pagano per la CHANCE di un payoff elevato, non per il rendimento atteso. Quegli acquirenti sono la controparte: pagano sistematicamente in eccesso per la volatilità e accettano rendimenti corretti per il rischio scarsi. La misurazione è netta ed è l'affermazione falsificabile centrale — nel periodo 2022-2026 i titoli a 5 HIGHEST volatilità hanno reso ~9% annualizzato mentre i 5 LOWEST hanno reso ~31%, con il basket ad alta volatilità che presenta una volatilità circa doppia. Il premio non è un effetto di trend di prezzo: ho verificato che la classificazione basata sul momentum trailing produce un profilo diverso e più debole su finestre oneste non sovrapposte (t=+1.25) rispetto alla classificazione basata sulla volatilità (t=+3.30 grezzo, +2.53 raggruppato per data).

Ipotesi

Ripristina l'universo di 25 titoli e l'esposizione lorda massima di 1.0 previsti dall'ipotesi, mantenendo al contempo il puro meccanismo di classificazione a bassa volatilità di OHLCV.

Ipotesi

verification_loop: Verifica fallita (Livello 2 — scenari sintetici): Parametri utilizzati: ['n_hold', 'cash_buffer', 'min_notional', '_param_bounds', 'rebalance_days', 'rv_lookback_days', 'target_annual_vol', 'max_gross_exposure', 'rebalance_tolerance'] Verificare che __init__ imposti tutti gli attributi da self.parameters.get(). - steady_uptrend: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - steady_downtrend: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - flat_ranging: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - volatility_spike: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - zero_volume: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - price_gap: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000)

Implementazione

Basket long-only su Binance Spot che detiene i cinque titoli con la volatilità realizzata più bassa da un universo fisso di 25 monete, ribilanciato ogni dieci barre giornaliere e scalato a una volatilità annualizzata di 15% con un limite lordo di 1.0x.

Risultati di verifica

Verifica fallita (Livello 2 — scenari sintetici): Parametri utilizzati: ['n_hold', 'cash_buffer', 'min_notional', '_param_bounds', 'rebalance_days', 'rv_lookback_days', 'target_annual_vol', 'max_gross_exposure', 'rebalance_tolerance'] Verificare che __init__ imposti tutti gli attributi da self.parameters.get(). - steady_uptrend: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - steady_downtrend: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - flat_ranging: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - volatility_spike: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - zero_volume: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000) - price_gap: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (bar timestamp: 1735692060000)

Riepilogo esito

CryptoLowVolAnomalySpotBasketLongOnl-7a915cf1a2

Riepilogo esito

La strategia ha testato un basket long-only su Binance Spot che deteneva le cinque criptovalute a più bassa volatilità da un universo di 25 monete. Sebbene l'ipotesi riportasse risultati storici positivi, la verifica è fallita in ogni scenario sintetico a causa di un TypeError Decimal/float, quindi la strategia è stata abbandonata prima del backtesting o dell'ottimizzazione.

Riepilogo esito

Assicurarsi che l'aritmetica Decimal e float sia gestita in modo coerente prima della verifica sintetica.

Riepilogo esito

È stata abbandonata dopo tre iterazioni perché la verifica del Livello 2 è fallita: tutti e sei gli scenari sintetici hanno generato un TypeError Decimal/float. Le fasi successive non sono state raggiunte.

Riepilogo esito

Ha cercato di sfruttare un'anomalia crypto a bassa volatilità detenendo i cinque titoli con la volatilità realizzata più bassa da un universo fisso di 25 monete su Binance Spot.

Riepilogo esito

L'ipotesi riportava uno Sharpe netto di 0.74, un rendimento annualizzato di 13.4%, un drawdown massimo di -33.6%, 430 operazioni e un rendimento medio per operazione di 1.37%. Non è stato registrato alcun backtest della pipeline né alcun report di ottimizzazione.

Iteration History

Verifica fallita (Livello 4 — revisione QA) [classe=code_defect]: - [edge_concern] L'economia del sandbox è sana e internamente coerente, quindi la redditività NOT è la causa di questo fallimento. avg_trade_return_pct 3.73% x avg_position_pct 8.25% x 95 operazioni = ~29% dell'equity vs total_return 32.07% — il ledger si riconcilia con la curva dell'equity (nessun difetto contabile), e 3.73%/operazione supera il round trip 0.20% BINANCE_SPOT di ~18x con commissioni pari a solo 2.64% del lordo. Due punti che l'analista deve portare avanti: (1) lo Sharpe riportato 0.547 non è internamente coerente con CAGR 19.26% su annualized_volatility 8.12% — la serie giornaliera MTM si è mossa solo in 580 giorni su 2401, mentre il book detiene 5 gambe spot continuamente da ~Nov-2022, quindi i numeri aggiustati per il rischio (Sharpe, Sortino, vol, VaR, Calmar) sono diluiti/scarsi rispetto al ledger realizzato. Si dichiara il sintomo, senza affermare alcuna causa. (2) l'attribuzione per regime mostra già una fase calma +42.6% (Sharpe 1.40) rispetto a una normale -4.1% e una stressata -3.7%, cioè il premio da bassa volatilità qui è un fenomeno da regime calmo in questo campione — ma questi tercili sono calcolati su una finestra in maggioranza piatta (vedi il problema critico), quindi vanno riletti dopo che la finestra è stata corretta, anziché agire su di essi ora. - [critico] UNIVERSE MAKES 58% OF THE BACKTEST WINDOW STRUCTURALLY UNTRADEABLE, CORRUPTING EVERY RISK METRIC. La barriera di allineamento cross-leg del template base (base_template.py _maybe_process_primary + _sync_extra_iids) rinvia la barra primaria finché EVERY la gamba extra con lo stesso timeframe non ha una barra esattamente a quel timestamp, e questa strategia richiede inoltre una riga completa in _row_for(). Ho verificato le date della prima barra in data/catalog per tutte le 25 gambe: i nomi vincolanti sono APTUSDT.BINANCE_SPOT (prima barra 1-DAY 2022-10-20) e ICPUSDT.BINANCE_SPOT (2021-05-12). La gamba primaria BTCUSDT.BINANCE_SPOT inizia 2017-08-18, e il backtest completo non passa alcuna data di inizio (backtest_agent._run_backtest invia solo `end`), quindi il motore gira da 2017-08 a 2026-09 (~9.1a) mentre il book non può piazzare il primo ordine prima di ~2022-11-10 (quotazione APT + 21 righe allineate di warmup). ~5.25 dei 9.1 anni (58%) risultano piatti per 0.00% giorni sulla griglia giornaliera. Il sandbox lo dimostra già esattamente: le finestre di stress covid_crash_2020, china_ban_2021, luna_collapse_2022 e rate_shock_2022 (gen-ott) restituiscono tutte precisamente 0.0000%, mentre ftx_collapse_2022 (che inizia 2022-11-06) è la prima non nulla, con -8.20%. Conseguenze, nessuna delle quali l'ottimizzatore o l'analista può annullare: (a) l'obiettivo della Fase-2 è lo Sharpe calcolato su una serie in maggioranza a zero — il sandbox riporta 0.547 mentre lo stesso CAGR del book sul suo arco temporale ACTIVE è 19.26%; (b) circa cinque anni solari riporteranno esattamente 0.00% e conteranno come non positivi rispetto alla soglia minima di validità della quota di anni positivi; (c) le affermazioni pre-registrate della stessa ipotesi — Sharpe +0.74 su 2017-2026, 6 dei 9 anni positivi, 'sopravvive a BOTH mercati ribassisti completi' (2018 -19%, 2022 -26%) — non possono essere prodotte affatto, perché 2018 e i primi dieci mesi di 2022 sono all'interno della finestra morta; (d) i tercili di regime di volatilità realizzata sono calcolati su una serie la cui maggioranza è composta da giorni morti. Questo è un difetto di sizing/configurazione con una correzione ovvia, non un giudizio sull'edge: la logica di trading in sé è corretta (vedi note). (riga 49) — correzione: scegliere un universo i cui membri esistano tutti sulla finestra che si intende misurare, e indicare nella motivazione della configurazione quale sia tale finestra. Date verificate del catalogo per la prima barra dell'attuale 25: APT 2022-10-20, ICP 2021-05-12, poi FIL 2020-10-16 / AAVE 2020-10-16 / NEAR 2020-10-15 / AVAX 2020-09-23 / UNI 2020-09-18 / DOT 2020-08-19 / SOL 2020-08-12, poi BCH 2019-11-29 / HBAR 2019-09-30 / DOGE 2019-07-06 / ALGO 2019-06-23 / ATOM 2019-04-30 / LINK 2019-01-17, poi VET 2018-07-26 / ETC 2018-06-13 / TRX 2018-06-12 / XLM 2018-06-01 / XRP 2018-05-05 / ADA 2018-04-18, e BTC/ETH 2017-08-18, BNB 2017-11-07, - [avviso] Il sizing degli acquisti in una rotazione è limitato da `available = get_account_equity() * cash_buffer`, letto AFTER l'uscita e i trim SELL vengono inviati alle righe 279-298. Nel backtest questo è corretto perché il SimulatedExchange di NT esegue gli ordini a mercato all'interno della stessa iterazione del motore, quindi il saldo USDT riflette già le vendite. In paper/live non è così: gli ordini a mercato restano in sospeso fino al tick successivo, quindi in una rotazione che vende 2-3 nomi per finanziarne 2-3 nuovi, la strategia vedrà la liquidità pre-vendita, scalerà ogni deficit di `ratio < 1`, e sotto-impiegherà il capitale. Poiché i nomi detenuti vengono ridimensionati solo quando escono dalla banda di tolleranza +/-25%, la carenza può persistere fino a una rotazione successiva. Divergenza backtest/paper, non un bug di correttezza del backtest. (riga 309) — correzione: calcolare `available` come (liquidità + nozionale delle uscite/trim appena inviati), oppure rinviare la gamba di acquisto di una rotazione alla barra successiva dopo che le vendite si sono regolate (una coda di acquisto differita di una barra, indicizzata al periodo di ribilanciamento). Se lasciato invariato, indicarlo esplicitamente nella motivazione affinché il controllo di paper-parity non interpreti la divergenza come un difetto. - [avviso] Le interruzioni dei dati su una singola gamba bloccano l'intero book. `_row_for()` restituisce None a meno che EVERY una delle 25 gambe non abbia una barra con esattamente il timestamp della barra primaria, e la barriera del template base blocca in modo indipendente la barra primaria nella stessa situazione. Una singola barra giornaliera mancante per un nome qualsiasi (gap di raccolta, sospensione da parte dell'exchange) salta silenziosamente la riga di quel giorno, lasciando un buco nella finestra dei log-return usata per la vol realizzata; un nome che smette del tutto di pubblicare (delisting) blocca la strategia per sempre con posizioni aperte. Il comportamento è conservativo piuttosto che errato, ma è invisibile — nulla registra o conta i giorni saltati. (riga 88) — correzione: contare le righe saltate (un intero `self._skipped_rows` viene auto-persistito dal template base) e registrare un avviso quando una gamba è assente per più di ~2 barre primarie consecutive, in modo che un delisting emerga come diagnostica invece che come un book piatto silenzioso.

Iteration History

Verifica fallita (Livello 4 — revisione QA) [class=hypothesis_mismatch]: - [edge_concern] Il backtest smoke è profittevole, ma la performance non viene utilizzata come verdetto di correttezza. - [critical] L'ipotesi richiede un universo fisso di 25 monete su Binance Spot, ma l'implementazione configura solo 14 strumenti. Detenere 5 titoli seleziona quindi 5/14 anziché 5/25, modificando in modo sostanziale la strategia cross-sectional. (riga 45) — correzione: Ripristinare l'esatto universo di 25 titoli in extra_instruments e extra_bar_types, quindi rieseguire la verifica e il backtesting. In alternativa, rivedere formalmente l'ipotesi nella variante a 14 titoli. - [critical] L'ipotesi consente un'esposizione lorda massima di 1.0x, ma l'implementazione imposta max_gross_exposure a 0.95 e la limita a 0.95. (riga 29) — correzione: Utilizzare un massimo di 1.0 oppure modificare esplicitamente l'ipotesi per pre-registrare il limite di 0.95.

Motivo abbandono

verification_loop: Verifica fallita (Livello 2 — scenari sintetici): Parametri utilizzati: ['n_hold', 'cash_buffer', 'min_notional', '_param_bounds', 'rebalance_days', 'rv_lookback_days', 'target_annual_vol', 'max_gross_exposure', 'rebalance_tolerance'] Verificare che __init__ imposti tutti gli attributi da self.parameters.get(). - steady_uptrend: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (timestamp barra: 1735692060000) - steady_downtrend: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (timestamp barra: 1735692060000) - flat_ranging: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (timestamp barra: 1735692060000) - volatility_spike: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (timestamp barra: 1735692060000) - zero_volume: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (timestamp barra: 1735692060000) - price_gap: TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float' (timestamp barra: 1735692060000)
Report della strategia

Stratmill è uno strumento di ricerca e paper trading, non una consulenza finanziaria né un broker. I risultati di backtest e paper trading sono ipotetici. Il trading comporta un rischio di perdita.