research(live): follow-up SKH chiuso — peso 0.25 e cron orario CONFERMATI de-luckati sul path live; + snapshot point-in-time stablecoin (sblocco WATCH a 12 mesi)

- r0724_skh_live_weight.py: sweep w 0-0.50 sul path hourly x 23 offset; w*=0.25
  (argmax mediana-IS di banda, plateau 0.20-0.30); w=0.30 passa weights_tilt_null
  solo a off0 (ancora fortunata), fallisce a offset mediano -> INVARIATO.
  Cadenza 230m = rumore (+0.01/+0.02 Sh med); il degrado live e' il fill-al-livello
  (~+0.35 Sh) che nessun cron recupera. Book e cron INVARIATI.
- r0724_stable_snapshot.py: cattura giornaliera point-in-time supply stablecoin
  (DefiLlama, tokenless, idempotente) -> data/external/stable_snapshots/ (gitignored).
  Criterio di rivisita del lead STABLE: >=12 mesi di serie propria.
- CLAUDE.md: bullet SKH01 aggiornato (follow-up chiuso).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-24 23:08:23 +00:00
parent 00996640fb
commit 636be89b2b
4 changed files with 521 additions and 1 deletions
+102
View File
@@ -0,0 +1,102 @@
"""SNAPSHOT point-in-time supply stablecoin (DefiLlama) — sblocca il lead STABLE fra 12 mesi.
CONTESTO (2026-07-24, ondata on-chain). STABLE-supply-growth (gate risk-on su crescita 30g
della supply stablecoin totale, thr 10% ann.) e' stato l'unico candidato dell'ondata sopra
quasi tutti i gate (DSR 0.998, marginale ADDS, non-hedge) ma e' declassato a WATCH perche'
la storia DefiLlama e' RICOSTRUITA retroattivamente (chain/coin aggiunte nel tempo): il
"totale" visto oggi per il 2019-21 non era osservabile allora -> vintage-risk non sanabile.
Criterio di rivisita scritto a diario (2026-07-24-onchain-sentiment-wave.md): quando una
fonte POINT-IN-TIME della supply accumula >=12 mesi, ritestare il gate thr=10%. Questo
script E' quella fonte: cattura oggi cio' che e' osservabile oggi.
COSA FA (sola lettura, API pubblica tokenless, nessun ordine):
- GET https://stablecoins.llama.fi/stablecoins (lista coin + circolante corrente);
- 1 riga JSON per run APPESA a data/external/stable_snapshots/snapshots.jsonl:
totale USD-peg, totale all-peg, breakdown top-15 per simbolo, n_coins.
~1 KB/riga -> ~400 KB/anno. Idempotente per giorno: se esiste gia' una riga con la
stessa data UTC esce senza scrivere (safe da ri-run in cron).
CADENZA RACCOMANDATA (quando/se si decide di cablarla — NON e' in cron adesso):
1 run/giorno dopo mezzanotte UTC (es. 00:15), accanto agli altri snapshot.
USO:
uv run python scripts/research/r0724_stable_snapshot.py
NB ONESTO: questo script MISURA, non decide. Fra >=12 mesi la serie risponde a: il segnale
crescita-30g calcolato su dati point-in-time replica quello calcolato sulla storia
ricostruita? Se no, il lead STABLE era un artefatto di vintage e muore li'.
"""
from __future__ import annotations
import json
import sys
import time
from datetime import datetime, timezone
from pathlib import Path
import requests
PROJECT_ROOT = Path(__file__).resolve().parents[2]
OUT_DIR = PROJECT_ROOT / "data" / "external" / "stable_snapshots"
OUT_FILE = OUT_DIR / "snapshots.jsonl"
API = "https://stablecoins.llama.fi/stablecoins?includePrices=true"
def fetch() -> dict:
last = None
for _ in range(4):
try:
r = requests.get(API, timeout=30)
j = r.json()
if "peggedAssets" in j:
return j
last = str(j)[:200]
except Exception as e:
last = str(e)
time.sleep(2.0)
raise RuntimeError(f"DefiLlama fail: {last}")
def circ_usd(asset: dict) -> float:
c = asset.get("circulating") or {}
return float(sum(v for v in c.values() if isinstance(v, (int, float))))
def main() -> None:
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
if OUT_FILE.exists():
for line in OUT_FILE.read_text().splitlines():
try:
if json.loads(line).get("date") == today:
print(f"SKIP: snapshot per {today} gia' presente")
return
except json.JSONDecodeError:
continue
data = fetch()
assets = data["peggedAssets"]
usd_peg = [a for a in assets if a.get("pegType") == "peggedUSD"]
tot_usd = sum(circ_usd(a) for a in usd_peg)
tot_all = sum(circ_usd(a) for a in assets)
top = sorted(usd_peg, key=circ_usd, reverse=True)[:15]
row = {
"date": today,
"snap_ts": int(time.time() * 1000),
"total_usd_peg": round(tot_usd, 2),
"total_all_peg": round(tot_all, 2),
"n_coins": len(assets),
"n_usd_peg": len(usd_peg),
"top15": {a.get("symbol", "?"): round(circ_usd(a), 2) for a in top},
"source": "stablecoins.llama.fi/stablecoins",
}
OUT_DIR.mkdir(parents=True, exist_ok=True)
with OUT_FILE.open("a") as f:
f.write(json.dumps(row, separators=(",", ":")) + "\n")
print(f"OK {today}: totale USD-peg ${tot_usd/1e9:.2f}B ({len(usd_peg)} coin, "
f"{len(assets)} totali) -> {OUT_FILE}")
if __name__ == "__main__":
sys.exit(main())