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:
@@ -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())
|
||||
Reference in New Issue
Block a user