bb40e87d13
Quattro misure (r0909_*), nessun cambio a libro/pesi/config: - libro nei crolli: −0,48%/g nei 160 giorni ≤ −5%, positivo per finestra dal 2022 per la gamba short di SKH01 (108% dei guadagni); beta 0,0769 riprodotto (§46); il peso di SKH01 resta chiuso dal gate (in-sample). - crollo catturato 1-5/06/2026 a quote vere: f_net 0,74 = rally; put δ−0,10 1,92× il modello; a vol bassa e fuori dal gate di VRP01 → §3 non si riapre. - XRP terza gamba (harness r0822_sol_leg): hold-out −0,169 in 0/24, un anno buono. - universo Deribit: liquidi solo BTC/ETH/XRP/SOL; XS01 13/19; BTCDVOL future non negoziabile; PAXG non misurato. Revisione fable: due conclusioni smontate (MTM 2,6× era un artefatto di quote; «8/12 guadagna» era l'ordine delle classi). Debito §5.18: cblib.spot_series + asof guarda un'ora avanti (feed 1h etichettato all'apertura). Test Opus: 92 nuovi, suite 1008/1008; due difetti del verdetto XRP corretti. Docs: diario, RESULTS §74-77, CLAUDE.md, memoria 20/50, README; journal 07-08/09. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017zJjHUS7mf4pnGE6pq9RTt
126 lines
6.7 KiB
Python
126 lines
6.7 KiB
Python
"""r0909 — L'UNIVERSO DERIBIT LETTO OGGI: quali "altre monete" esistono davvero sul venue.
|
|
|
|
Domanda dell'operatore: "anche piu' monete, ma sempre in Deribit". Prima di misurare una
|
|
moneta si legge il venue (N10: la verifica esterna a €0 si fa PRIMA, e sul venue). Questo
|
|
script interroga l'API PUBBLICA Deribit (nessuna credenziale, nessun ordine) e stampa:
|
|
1. i perpetual USDC-lineari aperti, con data di listing, lotto minimo in $, volume 24h,
|
|
spread top-of-book, open interest e funding — ordinati per volume;
|
|
2. quante delle 19 gambe di XS01 sono quotate (il 23/08 erano 14/19, 11 con ≥1 anno);
|
|
3. le famiglie di opzioni (inverse BTC/ETH; USDC-lineari per sottostante).
|
|
Una lettura e' UN istante (come r0822_alt_options): il file salva il JSON grezzo in
|
|
`data/_cache/` con l'ora della lettura, cosi' il numero stampato ha la sua fonte.
|
|
|
|
Cosa NON fa: nessun backtest, nessuna proposta. Dice solo quali strumenti esistono e quanto
|
|
sono negoziabili oggi — il filtro che decide cosa vale la pena misurare (C6).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
from collections import Counter
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(ROOT))
|
|
from src.portfolio.sleeves import XS_UNIVERSE # noqa: E402 (P1: l'universo si importa)
|
|
|
|
API = "https://www.deribit.com/api/v2/public/"
|
|
CACHE = ROOT / "data" / "_cache" / "r0909_deribit_universo.json"
|
|
SOGLIA_LIQUIDO_USD = 10e6 # volume 24h da cui una gamba e' "liquida" per un libro da $4-5k
|
|
|
|
|
|
def get(path: str) -> dict:
|
|
req = urllib.request.Request(API + path, headers={"User-Agent": "PythagorasGoal-research"})
|
|
with urllib.request.urlopen(req, timeout=30) as r:
|
|
return json.load(r)["result"]
|
|
|
|
|
|
def leggi(usa_cache: bool = True) -> dict:
|
|
if usa_cache and CACHE.exists():
|
|
return json.loads(CACHE.read_text())
|
|
d = dict(letto_a=datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
|
fut=get("get_instruments?currency=USDC&kind=future"),
|
|
bs=get("get_book_summary_by_currency?currency=USDC&kind=future"),
|
|
opt_usdc=get("get_instruments?currency=USDC&kind=option"),
|
|
opt_inv={c: len(get(f"get_instruments?currency={c}&kind=option")) for c in ("BTC", "ETH")})
|
|
CACHE.parent.mkdir(parents=True, exist_ok=True)
|
|
CACHE.write_text(json.dumps(d))
|
|
return d
|
|
|
|
|
|
def tabella(d: dict) -> list[dict]:
|
|
perps = {i["base_currency"]: i for i in d["fut"] if i["instrument_name"].endswith("PERPETUAL") and i["state"] == "open"}
|
|
bs = {b["instrument_name"]: b for b in d["bs"]}
|
|
rows = []
|
|
for c, i in perps.items():
|
|
b = bs.get(i["instrument_name"], {})
|
|
bid, ask, mark = b.get("bid_price"), b.get("ask_price"), b.get("mark_price") or 0.0
|
|
rows.append(dict(
|
|
coin=c, listato=time.strftime("%Y-%m-%d", time.gmtime(i["creation_timestamp"] / 1000)),
|
|
min_amt=i["min_trade_amount"], min_usd=i["min_trade_amount"] * mark,
|
|
vol_usd=b.get("volume_usd") or 0.0,
|
|
spread_bps=((ask - bid) / ((ask + bid) / 2) * 1e4) if bid and ask else float("nan"),
|
|
oi_usd=(b.get("open_interest") or 0.0) * mark, funding_8h=b.get("funding_8h"),
|
|
xs01=c in XS_UNIVERSE))
|
|
return sorted(rows, key=lambda r: -r["vol_usd"])
|
|
|
|
|
|
def sintesi(rows: list[dict], d: dict) -> dict:
|
|
listati = {r["coin"] for r in rows}
|
|
liquidi = [r["coin"] for r in rows if r["vol_usd"] >= SOGLIA_LIQUIDO_USD]
|
|
bs = {b["instrument_name"]: b for b in d["bs"]}
|
|
inattivi = sorted(i["instrument_name"] for i in d["fut"] if i["instrument_name"].endswith("PERPETUAL") and i["state"] != "open")
|
|
datati = [i for i in d["fut"] if not i["instrument_name"].endswith("PERPETUAL")]
|
|
dvol_fut = []
|
|
for i in datati:
|
|
if "DVOL" not in i["instrument_name"]:
|
|
continue
|
|
b = bs.get(i["instrument_name"], {})
|
|
dvol_fut.append(dict(nome=i["instrument_name"], stato=i["state"], min_amt=i["min_trade_amount"],
|
|
vol_usd=b.get("volume_usd") or 0.0, oi=b.get("open_interest") or 0.0,
|
|
bid=b.get("bid_price"), ask=b.get("ask_price")))
|
|
return dict(
|
|
n_perp=len(rows), liquidi=liquidi, inattivi=inattivi, n_datati=len(datati), dvol_fut=dvol_fut,
|
|
xs01_listate=sorted(c for c in XS_UNIVERSE if c in listati),
|
|
xs01_mancanti=[c for c in XS_UNIVERSE if c not in listati],
|
|
opt_inv=d["opt_inv"], opt_usdc=Counter(i["base_currency"] for i in d["opt_usdc"]).most_common(),
|
|
letto_a=d["letto_a"])
|
|
|
|
|
|
def verdetto(s: dict) -> str:
|
|
return (f"{s['n_perp']} perpetual USDC; LIQUIDI (≥${SOGLIA_LIQUIDO_USD/1e6:.0f}M/g): {', '.join(s['liquidi'])}; "
|
|
f"XS01 {len(s['xs01_listate'])}/19 quotate, mancano {', '.join(s['xs01_mancanti'])}; "
|
|
f"opzioni USDC-lineari su {len(s['opt_usdc'])} sottostanti — lettura del {s['letto_a']}")
|
|
|
|
|
|
def main() -> None:
|
|
d = leggi(usa_cache="--fresh" not in sys.argv)
|
|
rows = tabella(d); s = sintesi(rows, d)
|
|
print("=" * 110)
|
|
print(f" r0909 — UNIVERSO DERIBIT (API pubblica, lettura {s['letto_a']}; --fresh per rileggere)")
|
|
print("=" * 110)
|
|
print(f"\n [1] PERPETUAL USDC-LINEARI APERTI: {s['n_perp']}")
|
|
print(f" {'coin':<9}{'listato':>11}{'min $':>8}{'vol 24h M$':>12}{'spread bps':>12}{'OI M$':>8}{'funding 8h':>12} XS01")
|
|
for r in rows:
|
|
print(f" {r['coin']:<9}{r['listato']:>11}{r['min_usd']:>8.2f}{r['vol_usd']/1e6:>12.2f}{r['spread_bps']:>12.1f}"
|
|
f"{r['oi_usd']/1e6:>8.2f}{(r['funding_8h'] or 0)*1e4:>+11.2f}bp {'<--' if r['xs01'] else ''}")
|
|
print(f" perpetual NON aperti (stato ≠ open): {s['inattivi'] or 'nessuno'}")
|
|
print(f"\n [1bis] FUTURE USDC DATATI: {s['n_datati']} — fra cui il future sul DVOL, l'unico strumento long-vol DIRETTO del venue "
|
|
f"(visto dalla revisione del 09/09: non in memoria):")
|
|
for f in s["dvol_fut"]:
|
|
spr = (f["ask"] - f["bid"]) / ((f["ask"] + f["bid"]) / 2) * 100 if f["bid"] and f["ask"] else float("nan")
|
|
print(f" {f['nome']:<28} {f['stato']:<8} min {f['min_amt']} vol24h ${f['vol_usd']/1e6:.2f}M OI {f['oi']:.0f} "
|
|
f"bid/ask {f['bid']}/{f['ask']} (spread {spr:.0f}%) → non negoziabile a questi numeri; e in contango sanguina come la put")
|
|
print(f"\n [2] XS01: {len(s['xs01_listate'])}/19 gambe quotate; mancano {s['xs01_mancanti']}")
|
|
print(f" (23/08, §50: 14/19 quotate, 11 con ≥1 anno; sulle 11 il meccanismo collassa 1,265 → 0,116 — breadth, non capitale)")
|
|
print(f"\n [3] OPZIONI: inverse {s['opt_inv']}; USDC-lineari per sottostante: {s['opt_usdc']}")
|
|
print("\n VERDETTO: " + verdetto(s))
|
|
print("=" * 110)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|