crolli: il libro perde nel giorno e chiude > 0 in 8/8 finestre dal 2022 (SKH01 short); crollo catturato a vol bassa, XRP diluisce come SOL
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
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user