research(§43 DATA-UNUSED): inventario dei dati mai letti + l'unica ipotesi che ne esce, misurata
FASE 1 — censimento di data/ e di CHI lo legge (indice di 647 .py, Old/ escluso). Colonne MAI lette: 26 su 31 di CoinMetrics (fra cui FlowIn/FlowOutExNtv, 2018-2026 al 100%), `fetch_errors_json`, `iv_90d`. Tutto il resto con storia vera e' gia' stato analizzato: cio' che resta non letto e' telemetria a finestra corta (catena opzioni 113 g, 0DTE 30 g, vol_term 58 righe). Corretti in sessione due difetti dell'inventario stesso: la ricerca a SOTTOSTRINGA dava `iv` in 571 file, e le chiavi derivate dall'etichetta producevano due falsi "NESSUNO" su famiglie realmente lette (eqx_, fut_deribit/fund_). FASE 2 — EXFLOW: il turnover LORDO sugli exchange. SCARTATO. La famiglia exchange-flow fu uccisa il 24/07 sullo STOCK (SplyExNtv). Misurato prima di riaprirla: `In-Out` e' la derivata dello stock (corr +0.999 BTC / +0.752 ETH) mentre `In+Out` e' ortogonale (+0.035 / +0.080) — il 94% del flusso si cancella, quindi il lordo e' algebricamente assente da cio' che era stato provato. Griglia dichiarata prima: 3 variabili x 3 finestre x 2 modi x 2 segni = 36 celle, +4 gia' spese su EXS = 40 trial. (1) La cella scelta al buio fa Sharpe FULL 0.951 contro un massimo atteso dal PURO RUMORE di 1.009: sotto la soglia che una griglia di monete raggiunge da sola (DSR 0.437 a N=36, 0.411 a N=40). (2) La selezione in-sample torna sul CONTROLLO NEGATIVO messo apposta nella griglia (NETCTL = l'informazione gia' uccisa): il lordo non e' selezionabile, hold-out -0.42, DILUTES. (3) Zero informazione direzionale (|t|<1 su 2 asset x 2 variabili). Il legame col |ritorno| su ETH (Pearson incrementale t +2.70) non sopravvive al rango (Spearman p=0.46) e cambia segno per anno; su BTC e' "significativo" nel verso sbagliato. Sottoprodotti: corr->TP01 0.50-0.65 = replica indipendente del "l'on-chain e' prezzo travestito" del 24/07 su colonne che quell'ondata non aveva letto; haircut 0.000 a $635. Corretti prima di pubblicare due errori miei: il pool "N=12" del deflated-Sharpe erano le 12 celle MIGLIORI (rows e' ordinata) e faceva PASSARE il candidato a 0.975 — con la partizione legittima fa 0.678; e il residuo di vol calcolato a mano invece che per OLS ribaltava il segno su ETH. Solo ricerca: nessuna scrittura, nessun ordine, book/pesi/cron/config INVARIATI.
This commit is contained in:
@@ -0,0 +1,594 @@
|
|||||||
|
"""r0823_data_unused — §43 DATA-UNUSED: i dati che il progetto possiede e nessuno legge (2026-08-23).
|
||||||
|
|
||||||
|
DOMANDA (ondata `research/wave-0822`, filone 43): *"nuove strategie possibili"*. La fonte piu'
|
||||||
|
probabile di una strategia nuova non e' un'idea nuova sui soliti dati: e' un dato che nessuno ha
|
||||||
|
ancora guardato. Due fasi, la seconda dipende dalla prima.
|
||||||
|
|
||||||
|
FASE 1 — INVENTARIO (e' gia' un risultato, non un preambolo).
|
||||||
|
Censisce TUTTO cio' che sta su disco sotto `data/` e, per ogni dataset a schema ricco, quale
|
||||||
|
COLONNA e' letta da `src/` o da uno script di ricerca e quale non lo e' MAI. La lettura non e'
|
||||||
|
greppata a mano: si indicizzano una volta tutti i `.py` di src/ scripts/ tests/ (escluso `Old/`,
|
||||||
|
che e' archivio) e si cerca il nome della colonna come sottostringa. E' una misura GENEROSA verso
|
||||||
|
"letta" (un nome comune come `close` combacia ovunque) -> quando dice MAI LETTA, e' un fatto.
|
||||||
|
|
||||||
|
FASE 2 — UNA misura, la migliore.
|
||||||
|
Dall'inventario esce un solo candidato che soddisfa tutti e quattro i criteri richiesti:
|
||||||
|
(i) piu' storia utilizzabile, (ii) meccanismo economico dicibile in una frase, (iii) eseguibile
|
||||||
|
su Deribit a $635, (iv) non gia' chiuso dal progetto. E' `FlowInExNtv`/`FlowOutExNtv` di
|
||||||
|
CoinMetrics (`data/external/coinmetrics/cm_{btc,eth}.csv`): **0 file del repo li leggono**,
|
||||||
|
copertura 100% dal 2018, entrambi gli asset.
|
||||||
|
|
||||||
|
⚠️ IL PUNTO DELICATO, DICHIARATO IN TESTA. La famiglia "exchange-flow" e' stata UCCISA il
|
||||||
|
2026-07-24 (`r0724_onchain_wave.py`, famiglia EXS, 0/6 slot). Riaprirla richiede un meccanismo
|
||||||
|
NUOVO, non un secondo tentativo. Il meccanismo nuovo qui e' ARITMETICO e si MISURA prima di
|
||||||
|
usarlo (blocco 1):
|
||||||
|
- EXS ha testato `SplyExNtv`, lo STOCK di monete sugli exchange;
|
||||||
|
- `FlowIn - FlowOut` e' la DERIVATA di quello stock -> stessa informazione (lo si misura:
|
||||||
|
corr con d(SplyEx) attesa ~1);
|
||||||
|
- `FlowIn + FlowOut`, il turnover LORDO, si CANCELLA nella differenza -> e' algebricamente
|
||||||
|
ASSENTE da cio' che e' stato testato (corr con d(SplyEx) attesa ~0).
|
||||||
|
Quindi la parte onestamente nuova del dato e' il LORDO, non il netto. Meccanismo in una frase:
|
||||||
|
*il turnover lordo sugli exchange misura quanta parte del flottante viene ri-posizionata, cioe'
|
||||||
|
la partecipazione REGOLATA, a prescindere dalla direzione in cui si agisce.*
|
||||||
|
|
||||||
|
E siccome "riaprire un parametro riapre la sua famiglia" (regola 2026-07-30), il conteggio dei
|
||||||
|
trial e' fatto AL RIALZO: 36 celle nuove, piu' le 4 gia' spese su EXS il 24/07 -> il deflated
|
||||||
|
Sharpe si riporta a N=36 E a N=40, e si pubblica la sensibilita' del verdetto al conteggio.
|
||||||
|
|
||||||
|
Controllo positivo obbligatorio: la famiglia UCCISA viene ri-girata con la SUA factory
|
||||||
|
(`r0724_onchain_wave.exs_factory`, importata, non riscritta). Se il macchinario non riproduce
|
||||||
|
"earns_slot=False" sul caso noto, non e' credibile su quello nuovo.
|
||||||
|
|
||||||
|
CAUSALITA'. Riusa `r0724_onchain_wave._to_target` e `AVAIL_LAG_D=1` -> lag totale attivita' ->
|
||||||
|
posizione = 2 giorni (1 di disponibilita' del dato + 1 di `eval_weights`). Non e' una scelta di
|
||||||
|
oggi: e' la convenzione gia' congelata per questa fonte.
|
||||||
|
|
||||||
|
FINESTRA IN BARRE ATTIVE, non di calendario. Il CSV CoinMetrics community si ferma al 2026-05-24:
|
||||||
|
dopo quella data il segnale e' assente e la posizione e' FLAT. Contare quei giorni come evidenza
|
||||||
|
sarebbe l'errore gia' pagato dal progetto (94% di zeri letti come "nessuna perdita"). Qui la
|
||||||
|
finestra si riporta in barre con posizione != 0.
|
||||||
|
|
||||||
|
COSA NON FA: non manda ordini, non scrive nulla, non tocca `src/` `config/` `scripts/live/`
|
||||||
|
`data/paper_*`. Sola lettura.
|
||||||
|
|
||||||
|
Uso: nice -n 19 timeout 900 uv run python scripts/research/r0823_data_unused.py
|
||||||
|
(aggiungere --skip-inventory per la sola FASE 2)
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
from scipy import stats
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
sys.path.insert(0, str(ROOT))
|
||||||
|
sys.path.insert(0, str(ROOT / "scripts" / "research" / "alt"))
|
||||||
|
sys.path.insert(0, str(ROOT / "scripts" / "research"))
|
||||||
|
|
||||||
|
import altlib as al # noqa: E402
|
||||||
|
from altlib import (causality_ok, deflated_sharpe, eval_weights_smallcap, # noqa: E402
|
||||||
|
fmt_marginal, implausible_sharpe, study_family_honest)
|
||||||
|
import r0724_onchain_wave as ow # noqa: E402 (loader + causalita' + factory della famiglia uccisa)
|
||||||
|
|
||||||
|
DATA = ROOT / "data"
|
||||||
|
RAW = DATA / "raw"
|
||||||
|
LINE = "=" * 100
|
||||||
|
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# FASE 1 — INVENTARIO
|
||||||
|
# ===========================================================================
|
||||||
|
def _index_repo() -> dict[str, str]:
|
||||||
|
"""Tutti i .py di src/ scripts/ tests/ in memoria una volta sola. `Old/` e' ARCHIVIO
|
||||||
|
(il progetto lo dichiara non fidato) -> escluso: un dato letto solo li' NON e' letto."""
|
||||||
|
idx = {}
|
||||||
|
for d in ("src", "scripts", "tests"):
|
||||||
|
for p in (ROOT / d).rglob("*.py"):
|
||||||
|
if "Old/" in str(p):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
idx[str(p.relative_to(ROOT))] = p.read_text(errors="ignore")
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return idx
|
||||||
|
|
||||||
|
|
||||||
|
def _readers(idx: dict[str, str], needle: str, exclude_self: bool = True,
|
||||||
|
word: bool = True) -> list[str]:
|
||||||
|
"""`word=True` -> confini di parola. La prima stesura cercava la SOTTOSTRINGA e dava
|
||||||
|
`iv` in 571 file (e' dentro "drive", "receive", ...): un conteggio che non misura niente.
|
||||||
|
Resta comunque una misura GENEROSA verso "letta" (una variabile locale omonima conta) ->
|
||||||
|
e' quando dice MAI LETTA che l'affermazione e' forte."""
|
||||||
|
pat = re.compile(rf"(?<![A-Za-z0-9_]){re.escape(needle)}(?![A-Za-z0-9_])") if word else None
|
||||||
|
out = [f for f, t in idx.items() if (pat.search(t) if word else needle in t)]
|
||||||
|
if exclude_self:
|
||||||
|
out = [f for f in out if "r0823_data_unused" not in f]
|
||||||
|
return sorted(out)
|
||||||
|
|
||||||
|
|
||||||
|
def _pq_info(p: Path) -> tuple[int, list[str], str]:
|
||||||
|
try:
|
||||||
|
d = pd.read_parquet(p)
|
||||||
|
except Exception as e: # noqa: BLE001
|
||||||
|
return 0, [f"<illeggibile: {type(e).__name__}>"], ""
|
||||||
|
rng = ""
|
||||||
|
for c in d.columns:
|
||||||
|
if pd.api.types.is_datetime64_any_dtype(d[c]):
|
||||||
|
rng = f"{pd.Timestamp(d[c].min()).date()}->{pd.Timestamp(d[c].max()).date()}"
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if isinstance(d.index, pd.DatetimeIndex) and len(d):
|
||||||
|
rng = f"{d.index.min().date()}->{d.index.max().date()}"
|
||||||
|
elif "timestamp" in d.columns and len(d):
|
||||||
|
t = pd.to_datetime(d["timestamp"], unit="ms", utc=True)
|
||||||
|
rng = f"{t.min().date()}->{t.max().date()}"
|
||||||
|
return len(d), list(d.columns), rng
|
||||||
|
|
||||||
|
|
||||||
|
# famiglie di file: (etichetta, glob, campione su cui leggere lo schema, CHIAVE di ricerca).
|
||||||
|
# La chiave e' ESPLICITA e non derivata dall'etichetta: derivandola, due famiglie realmente
|
||||||
|
# lette (`eqx_`, `fund_`) risultavano "NESSUNO" — un falso negativo che avrebbe fabbricato
|
||||||
|
# un dato "mai usato" inesistente.
|
||||||
|
FAMILIES = [
|
||||||
|
("btc/eth certificati 5m/15m/1h", "btc_*.parquet|eth_*.parquet", "btc_1h.parquet", ("load_data", "altlib")),
|
||||||
|
("alt_sol_* (SOL, escluso 22/08)", "alt_sol_*.parquet", "alt_sol_1h.parquet", ("alt_sol",)),
|
||||||
|
("hl_*_1d (51 alt Hyperliquid)", "hl_*_1d.parquet", "hl_btc_1d.parquet", ("hl_{",)),
|
||||||
|
("hlfund_*_1h (19 major)", "hlfund_*_1h.parquet", "hlfund_btc_1h.parquet", ("hlfund_{",)),
|
||||||
|
("eq_*_1d (29 ETF USA)", "eq_*_1d.parquet", "eq_spy_1d.parquet", ("eq_{", 'eq_*.parquet')),
|
||||||
|
("eqx_*_1d (12 UCITS)", "eqx_*_1d.parquet", "eqx_vuaa_1d.parquet", ("eqx",)),
|
||||||
|
("fut_*_1h (7 futures indice)", "fut_*_1h.parquet", "fut_es_1h.parquet", ("fut_{",)),
|
||||||
|
("fut_deribit/ (70 datati scaduti)", "fut_deribit/*-*.parquet", "fut_deribit/BTC-27DEC24.parquet", ("fut_deribit",)),
|
||||||
|
("fut_deribit/fund_* (funding 1h)", "fut_deribit/fund_*.parquet", "fut_deribit/fund_BTC.parquet", ("fut_deribit",)),
|
||||||
|
("dvol_* (vol implicita)", "dvol_*.parquet", "dvol_btc.parquet", ("dvol_{",)),
|
||||||
|
("vol_term_* (term structure)", "vol_term_*.parquet", "vol_term_btc.parquet", ("vol_term_{",)),
|
||||||
|
("fundnews_short_screen", "fundnews_*.parquet", "fundnews_short_screen.parquet", ("fundnews_",)),
|
||||||
|
("cb_chain/ (catena opzioni oraria)", "cb_chain/*.parquet", "cb_chain/bite_archive.parquet", ("cb_chain",)),
|
||||||
|
("cb_market_snapshots", "cb_market_snapshots.parquet", "cb_market_snapshots.parquet", ("cb_market_snapshots",)),
|
||||||
|
]
|
||||||
|
|
||||||
|
# dataset a schema RICCO: qui si scende a livello di COLONNA
|
||||||
|
RICH = [
|
||||||
|
("cb_chain/bite_archive.parquet", RAW / "cb_chain" / "bite_archive.parquet"),
|
||||||
|
("cb_market_snapshots.parquet", RAW / "cb_market_snapshots.parquet"),
|
||||||
|
("vol_term_btc.parquet", RAW / "vol_term_btc.parquet"),
|
||||||
|
("hlfund_btc_1h.parquet", RAW / "hlfund_btc_1h.parquet"),
|
||||||
|
]
|
||||||
|
|
||||||
|
NON_PARQUET = [
|
||||||
|
("external/coinmetrics/cm_{btc,eth}.csv", DATA / "external/coinmetrics/cm_btc.csv", "cm_btc"),
|
||||||
|
("external/coinmetrics/fng.json", DATA / "external/coinmetrics/fng.json", "fng.json"),
|
||||||
|
("external/coinmetrics/stables.json", DATA / "external/coinmetrics/stables.json", "stables.json"),
|
||||||
|
("external/premium/{cb,upbit}_*.csv + usdkrw", DATA / "external/premium/cb_btc.csv", "usdkrw"),
|
||||||
|
("external/stable_snapshots/snapshots.jsonl", DATA / "external/stable_snapshots/snapshots.jsonl", "stable_snapshots"),
|
||||||
|
("external/hlp_deepdive/ + hlp_vault.json", DATA / "external/hlp_vault.json", "hlp_"),
|
||||||
|
("options_daily/snapshots.jsonl (0DTE)", DATA / "options_daily/snapshots.jsonl", "options_daily"),
|
||||||
|
("chain_collect/runs.jsonl (battito)", DATA / "chain_collect/runs.jsonl", "chain_collect"),
|
||||||
|
("instruments_registry.json", DATA / "instruments_registry.json", "instruments_registry"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def fase1() -> None:
|
||||||
|
print(LINE)
|
||||||
|
print(" FASE 1 — INVENTARIO: cosa c'e' su disco e CHI lo legge")
|
||||||
|
print(LINE)
|
||||||
|
idx = _index_repo()
|
||||||
|
print(f" indice repo: {len(idx)} file .py in src/ scripts/ tests/ (Old/ escluso = archivio)\n")
|
||||||
|
|
||||||
|
print(" (A) FAMIGLIE DI FILE")
|
||||||
|
print(f" {'dataset':36s} {'file':>5s} {'righe*':>10s} {'intervallo':22s} lettori (script che aprono il path)")
|
||||||
|
print(" " + "-" * 130)
|
||||||
|
for label, pattern, sample, keys in FAMILIES:
|
||||||
|
files: list[Path] = []
|
||||||
|
for pat in pattern.split("|"):
|
||||||
|
files += sorted(RAW.glob(pat))
|
||||||
|
if not files:
|
||||||
|
print(f" {label:36s} {'0':>5s} ASSENTE")
|
||||||
|
continue
|
||||||
|
n, cols, rng = _pq_info(RAW / sample)
|
||||||
|
# lettori: chi cita il MODO in cui quei path si costruiscono (chiavi esplicite: derivarle
|
||||||
|
# dall'etichetta dava 2 falsi "NESSUNO" su famiglie realmente lette). Colonna INDICATIVA:
|
||||||
|
# i due fut_deribit condividono l'accessore (FUT_DIR) e non si distinguono.
|
||||||
|
rd = sorted({f for k in keys for f in _readers(idx, k, word=False)})
|
||||||
|
rdl = ", ".join(Path(x).name for x in rd[:3]) + (f" (+{len(rd)-3})" if len(rd) > 3 else "")
|
||||||
|
print(f" {label:36s} {len(files):5d} {n:10,d} {rng:22s} {rdl if rd else '*** NESSUNO ***'}")
|
||||||
|
print(f" {'':36s} {'':5s} {'':10s} cols: {', '.join(cols[:12])}{' ...' if len(cols) > 12 else ''}")
|
||||||
|
print(" * righe = del file CAMPIONE, non della famiglia intera.\n")
|
||||||
|
|
||||||
|
print(" (B) COLONNE, dataset per dataset — 'MAI LETTA' = zero file in src/ scripts/ tests/")
|
||||||
|
for label, p in RICH:
|
||||||
|
if not p.exists():
|
||||||
|
continue
|
||||||
|
n, cols, rng = _pq_info(p)
|
||||||
|
print(f"\n --- {label} ({n:,} righe, {rng})")
|
||||||
|
for c in cols:
|
||||||
|
rd = _readers(idx, c)
|
||||||
|
if not rd:
|
||||||
|
print(f" {c:26s} *** MAI LETTA ***")
|
||||||
|
else:
|
||||||
|
print(f" {c:26s} {len(rd):3d} file ({', '.join(Path(x).name for x in rd[:3])})")
|
||||||
|
|
||||||
|
print("\n --- external/coinmetrics/cm_{btc,eth}.csv (31 colonne, daily dal 2009/2015)")
|
||||||
|
cm = pd.read_csv(DATA / "external/coinmetrics/cm_btc.csv", low_memory=False)
|
||||||
|
mai, lette = [], []
|
||||||
|
for c in cm.columns:
|
||||||
|
if c == "time":
|
||||||
|
continue
|
||||||
|
(lette if _readers(idx, c) else mai).append(c)
|
||||||
|
print(f" LETTE ({len(lette)}): {', '.join(lette)}")
|
||||||
|
print(f" *** MAI LETTE ({len(mai)}) ***: {', '.join(mai)}")
|
||||||
|
|
||||||
|
print("\n (C) SORGENTI NON-PARQUET")
|
||||||
|
for label, p, key in NON_PARQUET:
|
||||||
|
if not p.exists():
|
||||||
|
print(f" {label:44s} ASSENTE")
|
||||||
|
continue
|
||||||
|
sz = p.stat().st_size
|
||||||
|
rd = _readers(idx, key, word=False)
|
||||||
|
print(f" {label:44s} {sz/1e6:7.2f} MB lettori: "
|
||||||
|
f"{', '.join(Path(x).name for x in rd[:3]) if rd else '*** NESSUNO ***'}")
|
||||||
|
|
||||||
|
print("\n (D) DIRECTORY DI STATO (non sono sorgenti di segnale — elencate per completezza)")
|
||||||
|
for d in sorted(DATA.iterdir()):
|
||||||
|
if not d.is_dir() or d.name in ("raw", "external"):
|
||||||
|
continue
|
||||||
|
nf = sum(1 for _ in d.rglob("*") if _.is_file())
|
||||||
|
sz = sum(f.stat().st_size for f in d.rglob("*") if f.is_file())
|
||||||
|
print(f" data/{d.name:22s} {nf:4d} file {sz/1e6:8.2f} MB")
|
||||||
|
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# FASE 2 — LA MISURA
|
||||||
|
# ===========================================================================
|
||||||
|
# ---- il dato mai letto -----------------------------------------------------
|
||||||
|
def _flows(asset: str) -> tuple[pd.Series, pd.Series]:
|
||||||
|
"""FlowInExNtv / FlowOutExNtv: monete che ENTRANO e che ESCONO dagli exchange, in unita'
|
||||||
|
native, giornaliere. Zero file del repo le leggono (verificato in FASE 1)."""
|
||||||
|
cm = ow._CM[asset]
|
||||||
|
I = cm["FlowInExNtv"].astype(float)
|
||||||
|
O = cm["FlowOutExNtv"].astype(float)
|
||||||
|
return I.where(I > 0), O.where(O > 0)
|
||||||
|
|
||||||
|
|
||||||
|
def _z(s: pd.Series, W: int) -> pd.Series:
|
||||||
|
mp = max(20, W // 2)
|
||||||
|
return (s - s.rolling(W, min_periods=mp).mean()) / s.rolling(W, min_periods=mp).std()
|
||||||
|
|
||||||
|
|
||||||
|
# ---- le tre variabili (segno a priori dichiarato nel docstring) ------------
|
||||||
|
def gross_factory(tf: str, W: int = 90, mode: str = "LF", sign: int = 1):
|
||||||
|
"""GROSS — turnover lordo `log(In+Out)`, z-score causale su W. LA PARTE NUOVA: si cancella
|
||||||
|
nella differenza, quindi lo STOCK gia' testato non la contiene. Segno a priori +1
|
||||||
|
(partecipazione alta = mercato vivo)."""
|
||||||
|
def fn(df, asset):
|
||||||
|
I, O = _flows(asset)
|
||||||
|
z = _z(np.log(I + O), W) * sign
|
||||||
|
pos = np.sign(z) if mode == "LS" else (z > 0).astype(float)
|
||||||
|
return ow._to_target(df, pos)
|
||||||
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
def imb_factory(tf: str, W: int = 90, mode: str = "LF", sign: int = 1):
|
||||||
|
"""IMB — squilibrio normalizzato `(Out-In)/(Out+In)`, z-score su W. Netto RISCALATO dal
|
||||||
|
lordo: meta' informazione nuova, meta' del vecchio. Segno a priori +1 (deflussi = accumulo)."""
|
||||||
|
def fn(df, asset):
|
||||||
|
I, O = _flows(asset)
|
||||||
|
z = _z((O - I) / (O + I), W) * sign
|
||||||
|
pos = np.sign(z) if mode == "LS" else (z > 0).astype(float)
|
||||||
|
return ow._to_target(df, pos)
|
||||||
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
def netctl_factory(tf: str, W: int = 90, mode: str = "LF", sign: int = 1):
|
||||||
|
"""NETCTL — CONTROLLO NEGATIVO: deflusso netto cumulato su W diviso lo stock. E' la stessa
|
||||||
|
informazione di `SplyExNtv`, cioe' della famiglia gia' UCCISA. Sta nella griglia apposta:
|
||||||
|
se la selezione in-sample lo preferisce alle due variabili nuove, la risposta e' che il
|
||||||
|
dataset non contiene nient'altro di selezionabile."""
|
||||||
|
def fn(df, asset):
|
||||||
|
I, O = _flows(asset)
|
||||||
|
S = ow._CM[asset]["SplyExNtv"].astype(float)
|
||||||
|
S = S.where(S > 0)
|
||||||
|
z = (((O - I).rolling(W, min_periods=max(20, W // 2)).sum()) / S) * sign
|
||||||
|
pos = np.sign(z) if mode == "LS" else (z > 0).astype(float)
|
||||||
|
return ow._to_target(df, pos)
|
||||||
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
VARS = {"GROSS": gross_factory, "IMB": imb_factory, "NETCTL": netctl_factory}
|
||||||
|
|
||||||
|
# ---- GRIGLIA DICHIARATA PRIMA DI GUARDARE QUALSIASI SHARPE ----------------
|
||||||
|
WINDOWS = (30, 90, 180)
|
||||||
|
MODES = ("LF", "LS")
|
||||||
|
SIGNS = (1, -1)
|
||||||
|
GRID_1VAR = [dict(W=w, mode=m, sign=s) for w in WINDOWS for m in MODES for s in SIGNS] # 12
|
||||||
|
GRID_FULL = [dict(var=v, **p) for v in VARS for p in GRID_1VAR] # 36
|
||||||
|
EXS_GRID_SPESA = [dict(L=30, mode="LF"), dict(L=90, mode="LF"),
|
||||||
|
dict(L=30, mode="LS"), dict(L=90, mode="LS")] # 4, gia' spese 24/07
|
||||||
|
|
||||||
|
|
||||||
|
def family_factory(tf: str, var: str = "GROSS", **p):
|
||||||
|
return VARS[var](tf=tf, **p)
|
||||||
|
|
||||||
|
|
||||||
|
def _active_bars(fn, asset: str) -> tuple[int, int, int, int]:
|
||||||
|
"""barre con posizione != 0, FULL e HOLD-OUT. Il CSV CoinMetrics si ferma al 2026-05-24:
|
||||||
|
dopo, posizione 0 per assenza di dato -> non e' evidenza, e non va contata come tale."""
|
||||||
|
df = al.get(asset, "1d")
|
||||||
|
t = np.nan_to_num(np.asarray(al._call_target(fn, df, asset), float))
|
||||||
|
idx = pd.DatetimeIndex(pd.to_datetime(df["datetime"], utc=True))
|
||||||
|
act = np.abs(t) > 0
|
||||||
|
h = idx >= al.HOLDOUT
|
||||||
|
return int(act.sum()), len(t), int((act & h).sum()), int(h.sum())
|
||||||
|
|
||||||
|
|
||||||
|
def fase2() -> None:
|
||||||
|
print("\n" + LINE)
|
||||||
|
print(" FASE 2 — EXFLOW: il turnover LORDO sugli exchange (colonne mai lette)")
|
||||||
|
print(LINE)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 0. perche' questa
|
||||||
|
print("""
|
||||||
|
PERCHE' QUESTA E NON UN'ALTRA (i quattro criteri, applicati all'inventario):
|
||||||
|
(i) storia — FlowIn/FlowOut coprono 2018->2026 al 100% su ENTRAMBI gli asset. Le altre
|
||||||
|
colonne mai lette hanno finestre di mesi: `volume_24h` della catena (113 g),
|
||||||
|
`book_depth_top3` (113 g), `options_daily` 0DTE (30 g), `iv_90d` (58 righe),
|
||||||
|
`fetch_errors_json` (diagnostica, non segnale).
|
||||||
|
(ii) meccanismo — il turnover lordo misura quanta parte del flottante viene ri-posizionata.
|
||||||
|
(iii) eseguibile — segnale giornaliero -> long-flat/long-short BTC+ETH sui perp Deribit:
|
||||||
|
esattamente l'impianto di TP01. Verificato sotto a $635 con min-order $5.
|
||||||
|
(iv) non chiusa — le due colonne non sono lette da NESSUN file. Ma la FAMIGLIA (exchange-flow)
|
||||||
|
e' stata uccisa il 24/07 sullo STOCK -> serve un meccanismo nuovo, misurato
|
||||||
|
al blocco 1, e i trial vanno contati AL RIALZO (blocco 5).""")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 1. il fatto strutturale
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 1. IL FATTO CHE GIUSTIFICA (o no) LA RIAPERTURA — si misura, non si asserisce")
|
||||||
|
print("-" * 100)
|
||||||
|
print(" EXS (24/07) ha testato SplyExNtv = lo STOCK. d(stock) = In - Out = il NETTO.")
|
||||||
|
print(" Se corr(d stock, netto) ~ 1 e corr(d stock, lordo) ~ 0, allora il LORDO e'")
|
||||||
|
print(" algebricamente assente da cio' che e' stato provato — ed e' l'unica parte nuova.\n")
|
||||||
|
for a in ("BTC", "ETH"):
|
||||||
|
I, O = _flows(a)
|
||||||
|
S = ow._CM[a]["SplyExNtv"].astype(float).where(lambda s: s > 0)
|
||||||
|
m = I.notna() & O.notna() & S.notna()
|
||||||
|
dS, net, gross = S[m].diff(), (I - O)[m], (I + O)[m]
|
||||||
|
ok = dS.notna()
|
||||||
|
zg = _z(np.log(gross), 180)
|
||||||
|
mom = np.log(S[m]) - np.log(S[m]).shift(30)
|
||||||
|
ratio = (net.abs() / gross)
|
||||||
|
big = gross[zg > 3]
|
||||||
|
print(f" {a} n={int(m.sum()):,} {I[m].index[0].date()} -> {I[m].index[-1].date()}")
|
||||||
|
print(f" corr( d(SplyEx) , In-Out ) = {dS[ok].corr(net[ok]):+.4f} <- il NETTO E' la derivata dello stock")
|
||||||
|
print(f" corr( d(SplyEx) , In+Out ) = {dS[ok].corr(gross[ok]):+.4f} <- il LORDO no")
|
||||||
|
print(f" corr( z(lordo) , momentum-30g dello stock ) = {zg.corr(mom):+.4f}")
|
||||||
|
print(f" |In-Out| / (In+Out) mediano = {float(ratio.median()):.3f} -> il {100*(1-float(ratio.median())):.0f}% del")
|
||||||
|
print(" flusso lordo SI CANCELLA: lo stock vede sei monete su cento fra quelle che si muovono.")
|
||||||
|
if len(big):
|
||||||
|
print(f" (nei {len(big)} giorni a z(lordo)>3 il rapporto resta {float(ratio[zg > 3].median()):.3f})")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 2. griglia dichiarata
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 2. GRIGLIA DICHIARATA PRIMA DI GUARDARE, E CONTATA AL RIALZO")
|
||||||
|
print("-" * 100)
|
||||||
|
print(f" variabili {tuple(VARS)} x W {WINDOWS} x mode {MODES} x sign {SIGNS}")
|
||||||
|
print(f" = {len(GRID_FULL)} celle nuove, tf 1d soltanto.")
|
||||||
|
print(f" + {len(EXS_GRID_SPESA)} celle GIA' SPESE su questa famiglia il 24/07 (EXS) = {len(GRID_FULL)+len(EXS_GRID_SPESA)} trial")
|
||||||
|
print(" 'quando si riapre un parametro si riapre la sua famiglia' (regola 2026-07-30).")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 3. controllo positivo
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 3. CONTROLLO POSITIVO — la famiglia UCCISA, ri-girata con la SUA factory")
|
||||||
|
print("-" * 100)
|
||||||
|
rep_exs = study_family_honest("EXS-replica(24/07)", ow.exs_factory, EXS_GRID_SPESA, tfs=("1d",))
|
||||||
|
ch = rep_exs["chosen"]
|
||||||
|
print(f" cella IS {ch['params']} IS {ch['insample_sharpe']} FULL {ch['full_sharpe']} "
|
||||||
|
f"DSR {rep_exs['deflated_sharpe']} earns_slot_honest={rep_exs['earns_slot_honest']}")
|
||||||
|
print(" atteso: False (l'ondata 24/07 chiuse 0/6). Se qui uscisse True, il macchinario")
|
||||||
|
print(" non sarebbe credibile sul caso nuovo e il resto andrebbe buttato.")
|
||||||
|
exs_sharpes = [r["full_sharpe"] for r in rep_exs["rows"]]
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 4. il gate di famiglia
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 4. GATE DI FAMIGLIA — `study_family_honest` (cella scelta IN-SAMPLE, DSR, marginal)")
|
||||||
|
print("-" * 100)
|
||||||
|
rep = study_family_honest("EXFLOW", family_factory, GRID_FULL, tfs=("1d",))
|
||||||
|
ch = rep["chosen"]
|
||||||
|
daily = al.candidate_daily(family_factory(tf="1d", **ch["params"]), tf="1d")
|
||||||
|
hold = daily[daily.index >= al.HOLDOUT]
|
||||||
|
print(f" celle valutate: {rep['n_cells']}")
|
||||||
|
print(f" cella scelta AL BUIO (solo in-sample): {ch['params']}")
|
||||||
|
print(f" Sharpe IS {ch['insample_sharpe']} FULL {ch['full_sharpe']} HOLD-OUT {al._sh(hold):.3f}")
|
||||||
|
print(f" deflated-Sharpe {rep['deflated_sharpe']} (massimo atteso dal PURO RUMORE: "
|
||||||
|
f"Sharpe {rep['expected_null_max']}) pass={rep['dsr_pass']}")
|
||||||
|
print(fmt_marginal(rep["marginal"]))
|
||||||
|
print(f" >>> earns_slot_honest = {rep['earns_slot_honest']}")
|
||||||
|
|
||||||
|
print("\n classifica per Sharpe IN-SAMPLE (le prime 6 e le ultime 3 di 36):")
|
||||||
|
for r in rep["rows"][:6] + rep["rows"][-3:]:
|
||||||
|
d = al.candidate_daily(family_factory(tf="1d", **r["params"]), tf="1d")
|
||||||
|
print(f" {str(r['params']):58s} IS {r['insample_sharpe']:6.3f} FULL {r['full_sharpe']:6.3f}"
|
||||||
|
f" HOLD {al._sh(d[d.index >= al.HOLDOUT]):6.3f}")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 5. sensibilita' al conteggio
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 5. SENSIBILITA' DEL VERDETTO AL CONTEGGIO DEI TRIAL (regola 2026-07-30)")
|
||||||
|
print("-" * 100)
|
||||||
|
new_sh = [r["full_sharpe"] for r in rep["rows"]]
|
||||||
|
# ⚠️ ERRORE MIO, CORRETTO PRIMA DI PUBBLICARE: la prima stesura usava `new_sh[:12]` come
|
||||||
|
# "una sola variabile". `rows` e' ORDINATA per Sharpe in-sample -> quelle 12 erano le 12
|
||||||
|
# MIGLIORI, un pool a varianza artificialmente bassa, e il DSR usciva 0.975 = PASS. Non e'
|
||||||
|
# una lettura generosa, e' un pool sbagliato. La partizione legittima e' la variabile scelta.
|
||||||
|
own = [r["full_sharpe"] for r in rep["rows"] if r["params"]["var"] == ch["params"]["var"]]
|
||||||
|
for lab, pool in ((f"N=12 (la sola variabile scelta, {ch['params']['var']})", own),
|
||||||
|
("N=36 (griglia nuova dichiarata)", new_sh),
|
||||||
|
("N=40 (+ le 4 gia' spese su EXS il 24/07)", new_sh + exs_sharpes)):
|
||||||
|
dsr, sr0 = deflated_sharpe(al._sh(daily), pool, daily)
|
||||||
|
print(f" {lab:48s} DSR {dsr:.3f} null-max {sr0:.3f} (n pool {len(pool)})")
|
||||||
|
print(" Il verdetto e' lo stesso a ogni conteggio LEGITTIMO. Ma il DSR resta sensibile a")
|
||||||
|
print(" COME si partiziona la griglia (lezione §10 dell'ondata): con un pool scelto male")
|
||||||
|
print(" — le 12 celle migliori — lo stesso candidato PASSA a 0.975. La partizione e' il")
|
||||||
|
print(" secondo posto dove barare e' indolore e invisibile.")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 6. sotto-famiglie
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 6. DECOMPOSIZIONE PER VARIABILE (diagnostica: riportare il meglio di tre E' selezione,")
|
||||||
|
print(" quindi il numero che vale resta quello del blocco 4)")
|
||||||
|
print("-" * 100)
|
||||||
|
for nm, fac in VARS.items():
|
||||||
|
r = study_family_honest(nm, fac, GRID_1VAR, tfs=("1d",))
|
||||||
|
c = r["chosen"]
|
||||||
|
d = al.candidate_daily(fac(tf="1d", **c["params"]), tf="1d")
|
||||||
|
print(f" {nm:7s} IS-pick {str(c['params']):40s} IS {c['insample_sharpe']:6.3f} "
|
||||||
|
f"FULL {c['full_sharpe']:6.3f} HOLD {al._sh(d[d.index >= al.HOLDOUT]):6.3f} "
|
||||||
|
f"DSR(12) {r['deflated_sharpe']} marg {r['marginal']['marginal_verdict']} "
|
||||||
|
f"corr->TP01 {r['marginal']['marginal']['corr_full']}")
|
||||||
|
print(" La selezione in-sample sull'INTERA griglia preferisce NETCTL, cioe' il CONTROLLO")
|
||||||
|
print(" NEGATIVO = l'informazione gia' uccisa. La parte nuova non e' selezionabile.")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 7. direzione o volatilita'
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 7. DOVE STA L'INFORMAZIONE — direzione o volatilita'? (la letteratura che il progetto")
|
||||||
|
print(" stesso cita il 24/07 dice: i flussi predicono la VOL, non la direzione)")
|
||||||
|
print("-" * 100)
|
||||||
|
|
||||||
|
def _t(x, y):
|
||||||
|
c = float(np.corrcoef(x, y)[0, 1])
|
||||||
|
return c, c * np.sqrt(len(x) - 2) / np.sqrt(max(1e-12, 1 - c * c))
|
||||||
|
|
||||||
|
for a in ("BTC", "ETH"):
|
||||||
|
df = al.get(a, "1d")
|
||||||
|
idx = pd.DatetimeIndex(pd.to_datetime(df["datetime"], utc=True)).floor("D")
|
||||||
|
r = pd.Series(al.simple_returns(df["close"].values.astype(float)), index=idx)
|
||||||
|
I, O = _flows(a)
|
||||||
|
zg = _z(np.log(I + O), 180).shift(ow.AVAIL_LAG_D).reindex(idx)
|
||||||
|
zi = _z((O - I) / (O + I), 180).shift(ow.AVAIL_LAG_D).reindex(idx)
|
||||||
|
rv = r.rolling(30).std()
|
||||||
|
fdir, fabs = r.shift(-1), r.abs().shift(-1)
|
||||||
|
m = zg.notna() & zi.notna() & fdir.notna() & rv.notna()
|
||||||
|
n = int(m.sum())
|
||||||
|
cd, td = _t(zg[m], fdir[m])
|
||||||
|
ci, ti = _t(zi[m], fdir[m])
|
||||||
|
ca, ta = _t(zg[m], fabs[m])
|
||||||
|
cb, tb = _t(rv[m], fabs[m])
|
||||||
|
# incrementale ONESTO: residuo OLS di |r_{t+1}| su RV30_t, poi correlato con z(lordo)
|
||||||
|
X = np.column_stack([np.ones(n), rv[m].values])
|
||||||
|
beta = np.linalg.lstsq(X, fabs[m].values, rcond=None)[0]
|
||||||
|
resid = fabs[m].values - X @ beta
|
||||||
|
cr, tr = _t(zg[m].values, resid)
|
||||||
|
rho, pv = stats.spearmanr(zg[m].values, resid)
|
||||||
|
yr_idx = zg[m].index
|
||||||
|
per_yr = {int(y): round(float(np.corrcoef(zg[m].values[yr_idx.year == y],
|
||||||
|
resid[yr_idx.year == y])[0, 1]), 3)
|
||||||
|
for y in sorted(set(yr_idx.year))}
|
||||||
|
print(f" {a} n={n}")
|
||||||
|
print(f" DIREZIONE corr(z lordo, r_domani) = {cd:+.4f} t={td:+5.2f}")
|
||||||
|
print(f" corr(z squilibrio, r_dom) = {ci:+.4f} t={ti:+5.2f}")
|
||||||
|
print(f" VOLATILITA corr(z lordo, |r|_domani) = {ca:+.4f} t={ta:+5.2f}")
|
||||||
|
print(f" baseline corr(RV30, |r|) = {cb:+.4f} t={tb:+5.2f} <- il confronto giusto")
|
||||||
|
print(f" z lordo sul RESIDUO OLS = {cr:+.4f} t={tr:+5.2f} <- l'incremento vero")
|
||||||
|
print(f" lo stesso in RANGO (Spearman) = {rho:+.4f} p={pv:.4f} <- e' monotono o e' coda?")
|
||||||
|
print(f" Pearson per anno: {per_yr}")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 8. gate residui
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 8. GATE RESIDUI SULLA CELLA SCELTA")
|
||||||
|
print("-" * 100)
|
||||||
|
fn = family_factory(tf="1d", **ch["params"])
|
||||||
|
print(f" causality_ok : {causality_ok(fn, tf='1d')}")
|
||||||
|
imp = implausible_sharpe(daily)
|
||||||
|
print(f" implausible_sharpe: implausible={imp['implausible']} reasons={imp['reasons']} "
|
||||||
|
f"attive={imp['n_active']} quota-perdite-su-attive={imp['loss_frac']:.3f}")
|
||||||
|
print(" eseguibilita' a $635 (min-order $5):")
|
||||||
|
for a in ("BTC", "ETH"):
|
||||||
|
df = al.get(a, "1d")
|
||||||
|
sc = eval_weights_smallcap(df, al._call_target(fn, df, a), capital=635.0, min_order=5.0)
|
||||||
|
af, tf_, ah, th = _active_bars(fn, a)
|
||||||
|
print(f" {a}: haircut Sharpe {sc['sharpe_haircut']:+.3f} trade eseguiti {sc['n_executed_trades']:4d}"
|
||||||
|
f" | barre ATTIVE {af}/{tf_} ({100*af/tf_:.1f}%) hold-out attive {ah}/{th}")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 9. potenza
|
||||||
|
print("\n" + "-" * 100)
|
||||||
|
print(" 9. POTENZA — in barre ATTIVE, non di calendario")
|
||||||
|
print("-" * 100)
|
||||||
|
tgt = np.abs(np.nan_to_num(np.asarray(al._call_target(fn, al.get('BTC', '1d'), 'BTC'), float))) > 0
|
||||||
|
print(f" il CSV CoinMetrics si ferma al {ow._CM['BTC'].index[-1].date()}: dopo quella data la")
|
||||||
|
print(" posizione e' FLAT per ASSENZA DI DATO. Contarlo come evidenza sarebbe l'errore gia'")
|
||||||
|
print(" pagato dal progetto (zeri letti come 'nessuna perdita').")
|
||||||
|
for lab, s in (("FULL", daily), ("HOLD-OUT", hold)):
|
||||||
|
nz = int((s != 0).sum())
|
||||||
|
yr = nz / 365.25
|
||||||
|
se = np.sqrt(1.0 / max(yr, 1e-9))
|
||||||
|
print(f" {lab:9s} barre non-nulle {nz:5d} ({yr:.2f} anni) SE(Sharpe) ~ {se:.2f}"
|
||||||
|
f" -> differenza rilevabile al 95% ~ {1.96*se:.2f} di Sharpe")
|
||||||
|
print(f" (usato solo per dire cosa la finestra puo' e non puo' decidere: n_target_attivo={int(tgt.sum())})")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- 10. verdetto
|
||||||
|
print("\n" + LINE)
|
||||||
|
print(" VERDETTO")
|
||||||
|
print(LINE)
|
||||||
|
print(f"""
|
||||||
|
SCARTATO, per tre ragioni indipendenti e in quest'ordine di forza:
|
||||||
|
|
||||||
|
(1) LA CELLA SCELTA AL BUIO STA SOTTO IL RUMORE. Sharpe FULL {ch['full_sharpe']} contro un
|
||||||
|
massimo atteso dal PURO RUMORE di {rep['expected_null_max']} su {rep['n_cells']} trial.
|
||||||
|
Non e' "non passa il gate per poco": e' sotto la soglia che una griglia di monete
|
||||||
|
raggiungerebbe da sola. Stessa aritmetica di ORTHO-SCREEN (§12).
|
||||||
|
|
||||||
|
(2) LA SELEZIONE IN-SAMPLE TORNA SUL CONTROLLO NEGATIVO. Fra le tre variabili sceglie
|
||||||
|
NETCTL, cioe' l'informazione dello STOCK gia' uccisa il 24/07. Il turnover LORDO —
|
||||||
|
l'unica parte algebricamente nuova (corr con d(stock) 0.03-0.08, e il 94% del flusso
|
||||||
|
che si cancella) — NON e' selezionabile: la sua migliore cella in-sample fa hold-out
|
||||||
|
NEGATIVO (-0.42) ed e' DILUTES contro TP01.
|
||||||
|
|
||||||
|
(3) ZERO INFORMAZIONE DIREZIONALE, E IL LEGAME CON LA VOL NON REGGE AL SECONDO SGUARDO.
|
||||||
|
corr(segnale, ritorno di domani): |t| < 1 su 2 asset x 2 variabili nuove — ed e' la
|
||||||
|
direzione cio' di cui una strategia aveva bisogno. Sul |ritorno| il quadro sembra
|
||||||
|
diverso — ETH da' Pearson incrementale sul residuo di RV30 t=+2.70 — ma:
|
||||||
|
* in RANGO (Spearman) diventa +0.015 con p=0.46 -> non e' una relazione monotona,
|
||||||
|
e' la coda della distribuzione dei livelli;
|
||||||
|
* per anno decade e cambia segno (2021 +0.13 ... 2024 -0.03, 2026 -0.06);
|
||||||
|
* su BTC lo stesso test da' -0.005 (Pearson) e -0.051 con p=0.007 (Spearman), cioe'
|
||||||
|
"significativo" nel verso SBAGLIATO = firma di rumore, non di segnale.
|
||||||
|
Il turnover sugli exchange sale quando la vol e' GIA' salita: termometro contemporaneo,
|
||||||
|
stessa forma gia' trovata su TERM-STRUCTURE (§7) e SKEW (§5).
|
||||||
|
⚠️ E anche se il legame fosse reale, non produrrebbe un candidato: l'unica espressione
|
||||||
|
eseguibile di una vista sulla VOL a $635 e' short-vol (VRP01: 4/4 gate falliti, 5/5
|
||||||
|
overlay refutati, regola "niente short-vol da modello in deploy") oppure il denominatore
|
||||||
|
del vol-target di TP01 (TP01xDVOL, refutato come de-levering il 26/06). E' chiuso a valle,
|
||||||
|
non solo a monte.
|
||||||
|
|
||||||
|
COSA SI PORTA A CASA COMUNQUE:
|
||||||
|
* il marginal scorer da' corr->TP01 0.50-0.65 su colonne che l'ondata 24/07 non aveva MAI
|
||||||
|
letto -> REPLICA INDIPENDENTE del suo finding ("l'on-chain tradabile e' prezzo travestito,
|
||||||
|
corr 0.50-0.82"), raggiunta da un'altra porta e con un altro stimatore;
|
||||||
|
* l'eseguibilita' a $635 non ha bocciato nulla (haircut 0.000 su entrambe le gambe): ennesima
|
||||||
|
conferma che il vincolo del progetto non e' piu' il capitale ma l'edge;
|
||||||
|
* il pezzo di METODO riusabile e' il CONTROLLO NEGATIVO DENTRO LA GRIGLIA: infilare nella
|
||||||
|
stessa famiglia una variabile che si SA gia' morta trasforma "il candidato perde" in
|
||||||
|
"il dato non contiene nient'altro di selezionabile", che e' un'affermazione molto piu'
|
||||||
|
forte e costa una factory.
|
||||||
|
|
||||||
|
RISPOSTA ALLA DOMANDA DEL FILONE: dei dati che nessuno legge, uno solo aveva storia
|
||||||
|
sufficiente per sostenere un'ipotesi, ed e' stato misurato fino in fondo. Tutto il resto
|
||||||
|
dell'inventario e' telemetria a finestra corta (30-113 giorni) o gia' analizzato.
|
||||||
|
**Nessun dato inutilizzato sostiene oggi un'ipotesi nuova.**
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
skip = "--skip-inventory" in sys.argv
|
||||||
|
print(LINE)
|
||||||
|
print(" §43 DATA-UNUSED — quali dati il progetto possiede e nessuna strategia legge")
|
||||||
|
print(f" repo {ROOT} (sola lettura: nessuna scrittura, nessun ordine)")
|
||||||
|
print(LINE)
|
||||||
|
if not skip:
|
||||||
|
fase1()
|
||||||
|
fase2()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user