research(wave-0822): TP01-SINISTRO — l'allarme e' falsificato nel verso; il rischio dell'ottimo funded e' XS01, non TP01
This commit is contained in:
@@ -62,6 +62,7 @@ USO: nice -n 19 timeout 900 uv run python scripts/research/r0822b_bin_freq.py [
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import gc
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
@@ -132,6 +133,10 @@ class KeepCache:
|
||||
self.rv: dict = {}
|
||||
self.q: dict = {}
|
||||
|
||||
def clear(self) -> None:
|
||||
self.rv.clear()
|
||||
self.q.clear()
|
||||
|
||||
def keep(self, ex: dict, key, thr, w: int, h: float, sg: int) -> pd.Series:
|
||||
base = ex["base_daily"]
|
||||
k = (key, w)
|
||||
@@ -152,6 +157,18 @@ class KeepCache:
|
||||
KC = KeepCache()
|
||||
|
||||
|
||||
def rss_mb() -> float:
|
||||
"""RSS in MB, per non far morire il lavoro degli altri agenti (brief §8: 2 core, ~3 GB)."""
|
||||
try:
|
||||
with open("/proc/self/status") as f:
|
||||
for ln in f:
|
||||
if ln.startswith("VmRSS:"):
|
||||
return float(ln.split()[1]) / 1024.0
|
||||
except Exception:
|
||||
pass
|
||||
return float("nan")
|
||||
|
||||
|
||||
def size_bin(thr, w, h, sg):
|
||||
def f(ex, key):
|
||||
return V.sizes_from_L(ex, KC.keep(ex, key, thr, w, h, sg))
|
||||
@@ -175,7 +192,7 @@ def iso_pair(TP: pd.Series, leg: pd.Series, leg_base: pd.Series):
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--every", type=int, default=1)
|
||||
ap.add_argument("--ndraw", type=int, default=200)
|
||||
ap.add_argument("--ndraw", type=int, default=120)
|
||||
args = ap.parse_args()
|
||||
offs = OFFSETS_FULL[:: max(1, args.every)]
|
||||
t0 = time.time()
|
||||
@@ -208,8 +225,10 @@ def main() -> None:
|
||||
print("\n estrazione tabelle trade (V2-DD) ...", flush=True)
|
||||
EX = {o: {a: V.extract(a, o) for a in ASSETS} for o in offs}
|
||||
ntr = {a: int(np.mean([len(EX[o][a]["i_ent"]) for o in offs])) for a in ASSETS}
|
||||
R.get5m.cache_clear() # ~90 MB di 5m non servono durante la §4 (la VPS ha 2 core
|
||||
gc.collect() # e ~3 GB liberi condivisi); si ricaricano in §9b in ~3 s
|
||||
print(f" fatto in {time.time()-t0:.0f}s — trade medi/ancora: " +
|
||||
", ".join(f"{a} {ntr[a]}" for a in ASSETS))
|
||||
", ".join(f"{a} {ntr[a]}" for a in ASSETS) + f" (RSS {rss_mb():.0f} MB)")
|
||||
TP = A.tp01_baseline_daily()
|
||||
can = offs[0]
|
||||
|
||||
@@ -299,52 +318,71 @@ def main() -> None:
|
||||
print(" 4. LA FAMIGLIA INTERA — ISO dShFULL, mediana delle differenze appaiate su "
|
||||
f"{len(offs)} ancore")
|
||||
print("-" * L)
|
||||
# DUE PASSATE, per la RAM (7 GB sulla VPS, ~3 liberi, e siamo in tanti): la 1a calcola le
|
||||
# metriche per-ancora di tutte le 144 celle SENZA conservare le serie (144 x 23 x 3 serie da
|
||||
# 2717 punti sarebbero ~500 MB); la 2a ricalcola e CONSERVA le serie delle sole 3-4 celle che
|
||||
# servono dopo (canonica / scelta al buio / argmax): 4 x 23 gambe, ~2 s.
|
||||
# RAM (brief §8: 7 GB totali, ~3 liberi, e siamo in tanti). Tre accorgimenti, tutti
|
||||
# necessari — la prima stesura di questo script e' stata UCCISA a meta' della §4:
|
||||
# (a) DUE PASSATE: la 1a calcola le metriche per-ancora di tutte le 144 celle SENZA
|
||||
# conservare le serie (144 x 23 x 3 serie da 2717 punti = ~500 MB); la 2a ricalcola e
|
||||
# conserva le serie delle sole 3-4 celle che servono dopo (~2 s);
|
||||
# (b) ciclo ANCORA-ESTERNO con la cache di rv/quantili SVUOTATA a ogni ancora: viva una sola
|
||||
# ancora alla volta (72 serie invece di 1.656);
|
||||
# (c) RSS stampata, cosi' se qualcuno la rilancia sa cosa aspettarsi.
|
||||
BK, CT, LEG, MS = {}, {}, {}, {}
|
||||
ACC: dict = {}
|
||||
|
||||
def eval_cell(thr, w, h, sg, store: bool = False) -> dict:
|
||||
def _one(o, thr, w, h, sg, store: bool):
|
||||
"""UNA cella a UNA ancora. Le size si calcolano una volta sola e si riusano (la prima
|
||||
stesura le ricalcolava per il conteggio dei tenuti); la scomposizione per anno e il maxDD
|
||||
si fanno SOLO nella seconda passata, perche' servono a 3 celle e costavano il 60% del
|
||||
tempo su tutte e 144."""
|
||||
nm = cname(thr, w, h, sg)
|
||||
fn = size_bin(thr, w, h, sg)
|
||||
dF, dH, dI, lF, lI, lH, ms, kp, ddv, ddc, dC_ = ([] for _ in range(11))
|
||||
yr: dict = {}
|
||||
for o in offs:
|
||||
lg = leg_of(EX[o], o, fn)
|
||||
b, c, m = iso_pair(TP, lg, base_leg[o])
|
||||
dF.append(sh(b) - sh(c)); dH.append(sh(hold(b)) - sh(hold(c)))
|
||||
dI.append(sh(ins(b)) - sh(ins(c))); dC_.append(cagr(b) - cagr(c))
|
||||
lF.append(sh(lg)); lI.append(sh(ins(lg))); lH.append(sh(hold(lg)))
|
||||
ms.append(m); ddv.append(maxdd(b)); ddc.append(maxdd(c))
|
||||
kp.append(float(np.mean(np.concatenate([fn(EX[o][a], (o, a)) for a in ASSETS]))))
|
||||
szs = {a: fn(EX[o][a], (o, a)) for a in ASSETS}
|
||||
lg = V.leg_daily(EX[o], szs)
|
||||
b, c, m = iso_pair(TP, lg, base_leg[o])
|
||||
d = ACC.setdefault(nm, dict(thr=thr, w=w, h=h, sg=sg, dF=[], dH=[], dI=[], dC=[],
|
||||
lF=[], lI=[], lH=[], ms=[], kp=[], ddv=[], ddc=[], yr={}))
|
||||
d["dF"].append(sh(b) - sh(c)); d["dH"].append(sh(hold(b)) - sh(hold(c)))
|
||||
d["dI"].append(sh(ins(b)) - sh(ins(c)))
|
||||
d["lF"].append(sh(lg)); d["lI"].append(sh(ins(lg))); d["lH"].append(sh(hold(lg)))
|
||||
d["ms"].append(m)
|
||||
d["kp"].append(float(np.mean(np.concatenate(list(szs.values())))))
|
||||
if store:
|
||||
d["dC"].append(cagr(b) - cagr(c))
|
||||
d["ddv"].append(maxdd(b)); d["ddc"].append(maxdd(c))
|
||||
for y in {int(t) for t in b.index.year}:
|
||||
by, cy = b[b.index.year == y], c[c.index.year == y]
|
||||
if len(by) > 20:
|
||||
yr.setdefault(y, []).append(sh(by) - sh(cy))
|
||||
if store:
|
||||
BK.setdefault(nm, {})[o] = b
|
||||
CT.setdefault(nm, {})[o] = c
|
||||
LEG.setdefault(nm, {})[o] = lg
|
||||
MS.setdefault(nm, {})[o] = m
|
||||
a_ = np.asarray(dF, float)
|
||||
return dict(nm=nm, thr=thr, w=w, h=h, sg=sg,
|
||||
dF=float(np.median(a_)), nF=int((a_ > 0).sum()),
|
||||
lo=float(a_.min()), hi=float(a_.max()), arrF=a_,
|
||||
dH=float(np.median(dH)), nH=int((np.asarray(dH) > 0).sum()),
|
||||
isoI=float(np.median(dI)), dC=float(np.median(dC_)),
|
||||
legF=float(np.median(lF)), legI=float(np.median(lI)),
|
||||
legH=float(np.median(lH)), kept=float(np.median(kp)),
|
||||
weff=float(np.median([W_SKH * x for x in ms])),
|
||||
ddv=float(np.median(ddv)), ddc=float(np.median(ddc)),
|
||||
yr={y: float(np.median(v)) for y, v in yr.items()})
|
||||
d["yr"].setdefault(y, []).append(sh(by) - sh(cy))
|
||||
BK.setdefault(nm, {})[o] = b
|
||||
CT.setdefault(nm, {})[o] = c
|
||||
LEG.setdefault(nm, {})[o] = lg
|
||||
MS.setdefault(nm, {})[o] = m
|
||||
|
||||
RES = {}
|
||||
for (thr, w, h, sg) in cells:
|
||||
r = eval_cell(thr, w, h, sg)
|
||||
RES[r["nm"]] = r
|
||||
for o in offs:
|
||||
KC.clear()
|
||||
for (thr, w, h, sg) in cells:
|
||||
_one(o, thr, w, h, sg, store=False)
|
||||
KC.clear()
|
||||
|
||||
def _med(v, dflt=float("nan")):
|
||||
return float(np.median(v)) if len(v) else dflt
|
||||
|
||||
def _fin(d: dict) -> dict:
|
||||
a_ = np.asarray(d["dF"], float)
|
||||
return dict(nm=cname(d["thr"], d["w"], d["h"], d["sg"]), thr=d["thr"], w=d["w"],
|
||||
h=d["h"], sg=d["sg"], dF=float(np.median(a_)), nF=int((a_ > 0).sum()),
|
||||
lo=float(a_.min()), hi=float(a_.max()), arrF=a_,
|
||||
dH=float(np.median(d["dH"])), nH=int((np.asarray(d["dH"]) > 0).sum()),
|
||||
isoI=float(np.median(d["dI"])), dC=_med(d["dC"]),
|
||||
legF=float(np.median(d["lF"])), legI=float(np.median(d["lI"])),
|
||||
legH=float(np.median(d["lH"])), kept=float(np.median(d["kp"])),
|
||||
weff=float(np.median([W_SKH * x for x in d["ms"]])),
|
||||
ddv=_med(d["ddv"]), ddc=_med(d["ddc"]),
|
||||
yr={y: float(np.median(v)) for y, v in d["yr"].items()})
|
||||
|
||||
RES = {nm: _fin(d) for nm, d in ACC.items()}
|
||||
print(f" ({len(cells)} celle x {len(offs)} ancore valutate in {time.time()-t0:.0f}s "
|
||||
f"dall'avvio, prima passata senza conservare le serie)")
|
||||
f"dall'avvio, prima passata senza conservare le serie; RSS {rss_mb():.0f} MB)")
|
||||
|
||||
def matrix(sg: int, h: float) -> None:
|
||||
print(f"\n ISO dShFULL — segno {'+1 (tieni vol BASSA)' if sg>0 else '-1 (CONTROLLO)'}"
|
||||
@@ -383,9 +421,19 @@ def main() -> None:
|
||||
f"positive {sum(r['dF']>0 for r in NEG)}/{len(NEG)} <- controllo di segno")
|
||||
# seconda passata: conserva le serie delle sole celle che servono dopo
|
||||
sel_iso0 = max(ALLC, key=lambda r: r["isoI"])
|
||||
ACC2 = ACC
|
||||
for r in dict((x["nm"], x) for x in (RES[nmcan], argmax, sel_iso0,
|
||||
max(ALLC, key=lambda z: z["legI"]))).values():
|
||||
eval_cell(r["thr"], r["w"], r["h"], r["sg"], store=True)
|
||||
ACC = {}
|
||||
for o in offs:
|
||||
_one(o, r["thr"], r["w"], r["h"], r["sg"], store=True)
|
||||
KC.clear()
|
||||
RES[r["nm"]] = _fin(ACC[r["nm"]]) # ora con dC / maxDD / per-anno
|
||||
ACC = ACC2
|
||||
POS = [RES[cname(t, w, h, +1)] for t in THRS for w in WS for h in HS]
|
||||
NEG = [RES[cname(t, w, h, -1)] for t in THRS for w in WS for h in HS]
|
||||
ALLC = POS + NEG
|
||||
argmax = RES[argmax["nm"]]
|
||||
dchk = A.anchor_luck_delta(lambda o: BK[nmcan][o], lambda o: CT[nmcan][o], offs, metric=sh)
|
||||
assert abs(dchk["median_paired"] - RES[nmcan]["dF"]) < 1e-12 and \
|
||||
dchk["n_positive"] == RES[nmcan]["nF"], "la statistica appaiata di §4 non coincide con A.anchor_luck_delta"
|
||||
@@ -718,8 +766,10 @@ def main() -> None:
|
||||
print(f" {tag:<40}{row}")
|
||||
if fee != keep_fee:
|
||||
del EXf, basef
|
||||
gc.collect()
|
||||
V.FEE_RT = keep_fee
|
||||
assert V.FEE_RT == 0.001
|
||||
print(f" (RSS {rss_mb():.0f} MB)")
|
||||
f_mod = FEEDEC[(f"MODELLATA {keep_fee*1e4:.0f} bps RT (i backtest)", nmcan)]
|
||||
f_zero = FEEDEC[("fee ZERO (informazione pura)", nmcan)]
|
||||
print(f" -> a fee ZERO resta {f_zero:+.3f} di {f_mod:+.3f} = "
|
||||
@@ -735,6 +785,8 @@ def main() -> None:
|
||||
print(" temporale, ma e' l'unico campione indipendente disponibile a questo costo.")
|
||||
print("-" * L)
|
||||
EX1 = {o: {a: V.extract(a, o, SKH01_V1) for a in ASSETS} for o in offs}
|
||||
R.get5m.cache_clear() # i 5m non servono piu': ~80 MB restituiti
|
||||
gc.collect()
|
||||
base1 = {o: V.leg_daily(EX1[o], {a: V.size_flat(EX1[o][a]) for a in ASSETS}) for o in offs}
|
||||
print(f" {'cella':<26}{'ISO dShFULL':>13}{'pos/n':>8}{'ISO dShHOLD':>14}{'pos/n':>8}"
|
||||
f"{'tenuti':>9}")
|
||||
@@ -751,6 +803,10 @@ def main() -> None:
|
||||
print(f" {cname(r['thr'], r['w'], r['h'], r['sg']):<26}{dF['median_paired']:>+13.3f}"
|
||||
f"{dF['n_positive']:>5}/{len(offs):<3}{dH['median_paired']:>+14.3f}"
|
||||
f"{dH['n_positive']:>5}/{len(offs):<3}{float(np.median(kp))*100:>8.0f}%")
|
||||
del EX1, base1
|
||||
KC.clear()
|
||||
gc.collect()
|
||||
print(f" (RSS {rss_mb():.0f} MB)")
|
||||
|
||||
# ---------------------------------------------------------- §11 per anno
|
||||
print("\n" + "-" * L)
|
||||
|
||||
Reference in New Issue
Block a user