research: nuovo schema fee Deribit (1 ago 2026) — misurata la curva, nessuna azione oggi

L'annuncio (taker piu' bassi, maker rebate piu' bassi, soglie VIP abbassate, VIP7,
liquidation fee 1%, spot a zero) NON contiene numeri, e la tabella nell'articolo
Insights e' un'IMMAGINE: non letta da fonte primaria. I valori indicativi (base ~5bps
taker / 2bps maker, VIP7 2/0) vengono da un riassunto SECONDARIO ed e' dichiarato.

Quindi misurata la CURVA invece di aspettare il numero — vale per qualunque valore esca.
Le repliche parametrizzate riproducono BIT-EXACT gli sleeve di produzione alla fee
canonica (max|dif| = 0.0), altrimenti la curva descriverebbe un'altra strategia.

 bps/lato   %RT |  TP01 Sh | SKH01 Sh | BOOK Sh   CAGR
      0.0  0.00% |   1.322  |   1.567  |  1.849  21.69%
      3.0  0.06% |   1.303  |   1.495  |  1.799  20.99%
      5.0  0.10% |   1.290  |   1.446  |  1.766  20.53%   <- oggi
     10.0  0.20% |   1.258  |   1.324  |  1.682  19.39%
     15.0  0.30% |   1.226  |   1.200  |  1.597  18.26%

Sensibilita' del book: -0.017 Sharpe/bps, -0.23% CAGR/bps. Anche un RADDOPPIO del taker
costa 0.08 di Sharpe, MENO della banda d'ancora dello stesso book (2.222 -> 1.946): la
fee va messa nella sua scala di grandezza.

SKH01 e' ~4x piu' sensibile di TP01 (-0.69% vs -0.09% CAGR/bps: round-trip discreti vs
posizione continua vol-targeted) -> se il taker salisse, il primo parametro da rivedere
e' il peso 75/25.

REGOLA DECISA IN ANTICIPO (per non decidere col numero davanti): taker <=5bps/lato ->
non si tocca nulla; >10bps/lato -> rivedere il peso di SKH01.

Punti irrilevanti e perche': maker (il book manda ordini market; tocca solo la
raccomandazione T1 gia' non implementata); liquidation fee 1% (live.json da' nozionale
lordo max 1.00x l'equity con disaster-SL -30% -> servirebbe un movimento avverso ~100%);
VIP (a $600 il volume 30g e' trascurabile).

La conclusione sulla liquidation fee poggia sul CAP, non sulla strategia: cablata una
guardia di decisione (test_leva_massima_da_config_resta_sotto_o_uguale_a_1x) che ROMPE
se qualcuno alza il cap, invece di lasciarla valida per inerzia.

AZIONE 1 agosto: leggere il tier reale in Account Settings e applicare la regola sopra.

Book, pesi, cron, config INVARIATI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-26 18:32:23 +00:00
parent 0050ac4782
commit a937e3766f
4 changed files with 392 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
"""Test per r0726_fee_sensitivity.py — sensibilita' del book live al cambio fee Deribit.
Due categorie:
* le repliche parametrizzate sulla fee devono riprodurre BIT-EXACT gli sleeve di produzione
alla fee canonica (5 bps/lato), altrimenti la curva descrive un'altra strategia;
* il test sul CAP e' una guardia di DECISIONE: la conclusione "liquidation fee 1% irrilevante"
poggia sulla leva <= 1x che discende da `live.json`. Se qualcuno alza il cap, quella
conclusione decade e il test deve dirlo invece di lasciarla in giro valida per inerzia.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
import numpy as np
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "scripts" / "research"))
sys.path.insert(0, str(ROOT / "scripts" / "research" / "alt"))
import r0726_fee_sensitivity as FS # noqa: E402
# ===========================================================================
# le repliche alla fee canonica == produzione
# ===========================================================================
def test_tp01_alla_fee_canonica_riproduce_lo_sleeve():
from src.portfolio.portfolio import to_daily
from src.portfolio.sleeves import _tp01_returns
from src.strategies.trend_portfolio import CANONICAL
mine = FS.tp01_at_fee(CANONICAL["fee_side"])
ref = to_daily(_tp01_returns())
assert len(mine) == len(ref)
assert float(np.max(np.abs(mine.values - ref.values))) == 0.0
def test_skh01_alla_fee_canonica_riproduce_lo_sleeve():
from src.portfolio.portfolio import to_daily
from src.portfolio.sleeves import _skyhook_returns
mine = FS.skh01_at_fee(0.001) # fee_rt canonico dello sleeve
ref = to_daily(_skyhook_returns())
assert len(mine) == len(ref)
assert float(np.max(np.abs(mine.values - ref.values))) == 0.0
def test_la_fee_canonica_del_progetto_e_5bps_per_lato():
"""Se qualcuno cambia il default, la curva va ri-ancorata: 'oggi' non sarebbe piu' 5 bps."""
from src.strategies.trend_portfolio import CANONICAL
assert CANONICAL["fee_side"] == pytest.approx(0.0005)
assert 5.0 in FS.BPS_GRID
# ===========================================================================
# monotonicita': piu' fee, meno rendimento
# ===========================================================================
def test_piu_fee_meno_sharpe_e_meno_cagr():
from src.portfolio.portfolio import metrics
lo = metrics(FS.tp01_at_fee(0.0))
hi = metrics(FS.tp01_at_fee(0.0015))
assert lo["sharpe"] > hi["sharpe"]
assert lo["cagr"] > hi["cagr"]
def test_skh01_e_piu_sensibile_alla_fee_di_tp01():
"""Il fatto che guida la raccomandazione (se il taker salisse, rivedere il peso di SKH01):
SKH01 fa round-trip discreti, TP01 e' una posizione lenta vol-targeted."""
from src.portfolio.portfolio import metrics
d_tp = metrics(FS.tp01_at_fee(0.0))["cagr"] - metrics(FS.tp01_at_fee(0.001))["cagr"]
d_sk = metrics(FS.skh01_at_fee(0.0))["cagr"] - metrics(FS.skh01_at_fee(0.002))["cagr"]
assert d_sk > d_tp
# ===========================================================================
# guardia di decisione: la leva su cui poggia "liquidation fee irrilevante"
# ===========================================================================
def test_leva_massima_da_config_resta_sotto_o_uguale_a_1x():
"""La conclusione 'liquidation fee 1% irrilevante' vale perche' il cap di live.json
limita il nozionale lordo a <= 1x l'equity (2 asset x equity/2), con disaster-SL a -30%.
Se il cap sale, quella conclusione NON vale piu': questo test deve rompersi."""
cfg = json.loads((ROOT / "config" / "live.json").read_text())
frac = cfg.get("max_notional_per_asset_frac")
assert frac is not None, "cap dinamico rimosso: rivedere l'analisi liquidation fee"
leva_max = frac * len(FS.ASSETS)
assert leva_max <= 1.0, (
f"leva massima {leva_max:.2f}x > 1x: la liquidation fee 1% torna rilevante, "
"rivedere r0726_fee_sensitivity e il diario 2026-07-26-fee-deribit.md")
assert cfg.get("disaster_sl_pct", 0) > 0, "disaster-SL disattivato: idem"