research(wave-0822): MAKER scartato (il segno dipende da < contro <=) + CRITICO — la cucitura dell'ondata, non i filoni
This commit is contained in:
@@ -369,7 +369,9 @@ def test_calendario(q: pd.DataFrame, dte_min: float, ogni: int = 4) -> dict:
|
||||
iv_need = np.sqrt(np.maximum(x["w"].to_numpy(), 0) / np.maximum(nxt_T, 1e-9)) * 100.0
|
||||
amp_pt = np.where(ok, iv_need - nxt_iv, np.nan)
|
||||
|
||||
res = {"i_n": int(ok.sum()), "i_viol": int(viol_i.sum()),
|
||||
room = amp_pt[ok] # <0 = margine, >0 = violazione
|
||||
res = {"room_med_pt": float(np.nanmedian(room)), "room_p5_pt": float(np.nanpercentile(room, 5)),
|
||||
"i_n": int(ok.sum()), "i_viol": int(viol_i.sum()),
|
||||
"i_quota": float(viol_i.sum() / max(1, ok.sum())),
|
||||
"i_amp_med_pt": float(np.nanmedian(amp_pt[viol_i])) if viol_i.any() else np.nan,
|
||||
"i_amp_p95_pt": float(np.nanpercentile(amp_pt[viol_i], 95)) if viol_i.any() else np.nan}
|
||||
@@ -471,6 +473,37 @@ def persistenza(bf: pd.DataFrame, viol_col: str) -> dict:
|
||||
return {"n": int(m.sum()), "resta": float(nxt[m].mean()) if m.any() else np.nan}
|
||||
|
||||
|
||||
def controfattuale_usdc(bf: pd.DataFrame, asset: str, rel_usdc: float) -> dict:
|
||||
"""SE la famiglia USDC quotasse la STESSA superficie col SUO spread, sarebbe eseguibile?
|
||||
|
||||
Controfattuale DICHIARATO, non una misura: il collettore non raccoglie le USDC (difetto di
|
||||
produzione del filone 11), quindi si tiene il mid osservato sulle inverse e si stringe lo
|
||||
spread al valore relativo misurato dagli altri filoni sulla famiglia USDC, con il lotto
|
||||
minimo USDC e la stessa formula di fee. Assunzione dichiarata: stessa griglia di tick
|
||||
(una griglia piu' grossa peggiorerebbe il risultato, quindi questo e' un LIMITE SUPERIORE).
|
||||
"""
|
||||
x = bf[(bf["asset"] == asset)].dropna(subset=["mid", "mid_p", "mid_n"]).copy()
|
||||
x = x[np.isclose(x["lam"], 0.5, atol=0.02)]
|
||||
lot = MIN_LOT_USDC[asset]
|
||||
out = {}
|
||||
for nome, rel in (("inverse osservato", None), (f"{asset}_USDC controfattuale", rel_usdc)):
|
||||
if rel is None:
|
||||
b, a_p, a_n = x["bid"], x["ask_p"], x["ask_n"]
|
||||
l = MIN_LOT[asset]
|
||||
else:
|
||||
b = x["mid"] * (1 - rel / 2)
|
||||
a_p = x["mid_p"] * (1 + rel / 2)
|
||||
a_n = x["mid_n"] * (1 + rel / 2)
|
||||
l = lot
|
||||
cred = (b.to_numpy() * 2 * l - a_p.to_numpy() * l - a_n.to_numpy() * l)
|
||||
f = (fee_coin(b.to_numpy(), 2 * l) + fee_coin(a_p.to_numpy(), l) + fee_coin(a_n.to_numpy(), l))
|
||||
netto = (cred - f) * x["spot_feed"].to_numpy()
|
||||
out[nome] = {"n": int(len(x)), "pos": int(np.nansum(netto > 0)),
|
||||
"max": float(np.nanmax(netto)), "p999": float(np.nanpercentile(netto, 99.9)),
|
||||
"lotto_usd": float(np.nanmedian(x["spot_feed"]) * l)}
|
||||
return out
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- controlli positivi
|
||||
|
||||
def _finto(rows) -> pd.DataFrame:
|
||||
@@ -657,6 +690,12 @@ def main() -> None:
|
||||
print(f" (ii) log-moneyness FISSO, con interpolazione (1 snapshot ogni {c['ii_ogni']}): "
|
||||
f"{c['ii_viol']:,}/{c['ii_n']:,} = {c['ii_quota']:.3%} · ampiezza mediana {c['ii_amp_med_pt']:.3f} pt-vol")
|
||||
print(f" -> contributo dell'INTERPOLATORE = {c['ii_quota'] - c['i_quota']:+.3%} di quota di violazione")
|
||||
if "i_val_usd_med" in c:
|
||||
print(f" valore mediano della violazione (i) al lotto minimo ${c['i_val_usd_med']:.2f} "
|
||||
f"contro un costo di 2 gambe (spread + fee) di ${c['i_costo_usd_med']:.2f}")
|
||||
print(f" margine di monotonia sull'intera superficie: la iv lunga sta {-c['room_med_pt']:.2f} pt-vol "
|
||||
f"SOPRA il minimo che la non-arbitraggio richiede (p5 {-c['room_p5_pt']:.2f}) "
|
||||
f"-> la superficie non e' nemmeno VICINA al bordo")
|
||||
|
||||
print("\n" + "=" * 100)
|
||||
print("5. TICK E PERSISTENZA — le due difese contro 'la mia incoerenza e' un artefatto'")
|
||||
@@ -674,6 +713,23 @@ def main() -> None:
|
||||
f"(mediana {np.median(nt):.0f} tick) · resta in violazione allo snapshot dopo "
|
||||
f"{p.get('resta', float('nan')):.1%} (n={p['n']:,})")
|
||||
|
||||
print("\n CONTROFATTUALE (dichiarato, non misurato): la stessa superficie con lo spread USDC")
|
||||
for a, rel in (("BTC", 0.082), ("ETH", 0.026)):
|
||||
if a not in set(bf["asset"]):
|
||||
continue
|
||||
cf = controfattuale_usdc(bf, a, rel)
|
||||
for nome, r in cf.items():
|
||||
print(f" {a} {nome:<28}: lotto ${r['lotto_usd']:,.0f} · farfalle a credito netto>0 "
|
||||
f"{r['pos']:,}/{r['n']:,} · migliore ${r['max']:.2f} · p99.9 ${r['p999']:.2f}")
|
||||
|
||||
print("\n QUANTO MANCA per essere eseguibile (near-miss, triple equispaziate):")
|
||||
for a in sorted(bf["asset"].unique()):
|
||||
x = bf[(bf["asset"] == a) & np.isclose(bf["lam"], 0.5, atol=0.02)]
|
||||
c = x["cost_exec"].to_numpy() * 2 * MIN_LOT[a] * x["spot_feed"].to_numpy() # >0 = costo
|
||||
print(f" {a}: costo della farfalla eseguibile — migliore ${np.nanmin(c):.2f} · "
|
||||
f"p0.1 ${np.nanpercentile(c, 0.1):.2f} · mediana ${np.nanmedian(c):.2f} "
|
||||
f"(negativo = credito riskless)")
|
||||
|
||||
print("\n" + "=" * 100)
|
||||
print("6. IL RESIDUO SI RICOMPONE? (l'ipotesi del filone, misurata invece che assunta)")
|
||||
print("=" * 100)
|
||||
|
||||
Reference in New Issue
Block a user