research(wave-0822): VOL-SIZE — il p-value del null di permutazione si cita col segno, non col decimale (3 ancore su 23)
This commit is contained in:
@@ -318,6 +318,14 @@ def certify(asset: str, wide: pd.DataFrame, vwide: pd.DataFrame, meta: pd.DataFr
|
||||
print(f" convergenza a scadenza |ln(F/indice)| ultima ora: "
|
||||
f"mediana {np.median(conv):.1f} bps, max {np.max(conv):.1f} bps (n={len(conv)})")
|
||||
|
||||
# (c-bis) scarto PERP vs INDICE: la gamba FvP lo assume piccolo, quindi si misura
|
||||
pj = perp.reindex(fund.set_index("ts").index).dropna()
|
||||
if len(pj) > 1000:
|
||||
ii = fund.set_index("ts")["index"].reindex(pj.index)
|
||||
pb = (np.log(pj / ii) * 1e4).replace([np.inf, -np.inf], np.nan).dropna()
|
||||
print(f" perp vs indice: mediana {pb.median():+.1f} bps, p95 |scarto| "
|
||||
f"{pb.abs().quantile(0.95):.1f} bps (n={len(pb):,}) — la gamba FvP e' sul PERP")
|
||||
|
||||
# (d) CROSS-CHECK INDIPENDENTE: il forward implicito nella catena opzioni
|
||||
xchk = cross_check_option_forward(asset, wide, ok)
|
||||
return dict(flat=fb, vol=vb, conv=conv, xchk=xchk)
|
||||
@@ -370,7 +378,8 @@ def cross_check_option_forward(asset: str, wide: pd.DataFrame, meta: pd.DataFram
|
||||
# 2. CURVA — front/back trimestrali, basis annualizzato, slope forward
|
||||
# ==========================================================================
|
||||
def curve_frame(asset: str, wide: pd.DataFrame, meta: pd.DataFrame,
|
||||
fund: pd.DataFrame, roll_dte: int) -> pd.DataFrame:
|
||||
fund: pd.DataFrame, roll_dte: int,
|
||||
perp: pd.Series | None = None) -> pd.DataFrame:
|
||||
"""Per ogni ora: front = trimestrale piu' vicino con dte >= roll_dte, back = il successivo.
|
||||
Ritorna prezzi, tau, basis annualizzati, slope forward e funding."""
|
||||
ok = meta[meta.status == "ok"].sort_values("exp")
|
||||
@@ -408,6 +417,15 @@ def curve_frame(asset: str, wide: pd.DataFrame, meta: pd.DataFrame,
|
||||
out["tau_front_h"], out["tau_back_h"] = tf, tb
|
||||
out["index"] = F["index"].values
|
||||
out["f1h"] = F["f1h"].values
|
||||
# gamba perp: il PERP CERTIFICATO, non l'indice (l'indice non si compra).
|
||||
# fallback all'indice solo se il perp non copre l'ora, e lo si dichiara.
|
||||
if perp is not None:
|
||||
pp = perp.reindex(idx)
|
||||
out["perp"] = pp.where(pp.notna(), out["index"]).values
|
||||
out["perp_from_index"] = pp.isna().values
|
||||
else:
|
||||
out["perp"] = out["index"].values
|
||||
out["perp_from_index"] = True
|
||||
# basis annualizzato di ciascuna gamba vs INDICE
|
||||
out["c_front"] = np.log(Ff / out["index"]) * HOURS_Y / tf
|
||||
out["c_back"] = np.log(Fb / out["index"]) * HOURS_Y / tb
|
||||
@@ -532,7 +550,7 @@ def run_strategy(cv: pd.DataFrame, ctx: dict, family: str, sig: str,
|
||||
turn = np.abs(dP).sum(axis=1)
|
||||
|
||||
if family == "FvP":
|
||||
perp_r = np.nan_to_num(cv["index"].pct_change().values, nan=0.0)
|
||||
perp_r = np.nan_to_num(cv["perp"].pct_change().values, nan=0.0)
|
||||
f1h = np.nan_to_num(cv["f1h"].values, nan=0.0)
|
||||
wheld = held.sum(axis=1) # una sola gamba datata
|
||||
# long datato => short perp: guadagna -w*perp_r e INCASSA w*funding
|
||||
@@ -609,11 +627,14 @@ def main() -> None:
|
||||
|
||||
# ---------------- STEP 2: certificazione ----------------
|
||||
print("\n[2] CERTIFICAZIONE (regola 4: un edge su un book fermo non e' un edge)")
|
||||
certs = {}
|
||||
certs, perps = {}, {}
|
||||
for a in ASSETS:
|
||||
perp = A.get(a, "1h").set_index(pd.DatetimeIndex(
|
||||
pd.to_datetime(A.get(a, "1h")["datetime"], utc=True)))["close"]
|
||||
certs[a] = certify(a, panels[a], vwides[a], metas[a], funds[a], perp)
|
||||
pdf = A.get(a, "1h")
|
||||
perps[a] = pd.Series(
|
||||
pdf["close"].astype(float).values,
|
||||
index=pd.DatetimeIndex(pd.to_datetime(pdf["datetime"], utc=True))).sort_index()
|
||||
perps[a] = perps[a][~perps[a].index.duplicated()]
|
||||
certs[a] = certify(a, panels[a], vwides[a], metas[a], funds[a], perps[a])
|
||||
x = certs[a]["xchk"]
|
||||
if x.get("status") == "ok" and len(x["table"]):
|
||||
t = x["table"]
|
||||
@@ -628,7 +649,7 @@ def main() -> None:
|
||||
print("\n[3] Q1 — LA CURVA E' PREVEDIBILE?")
|
||||
curves = {}
|
||||
for a in ASSETS:
|
||||
cv = curve_frame(a, panels[a], metas[a], funds[a], roll_dte=7)
|
||||
cv = curve_frame(a, panels[a], metas[a], funds[a], roll_dte=7, perp=perps[a])
|
||||
curves[a] = cv
|
||||
describe_curve(a, cv)
|
||||
|
||||
@@ -665,7 +686,7 @@ def main() -> None:
|
||||
f" le conto lo stesso, al rialzo)")
|
||||
|
||||
ctxs = {a: asset_ctx(panels[a]) for a in ASSETS}
|
||||
cvcache = {(a, rl): curve_frame(a, panels[a], metas[a], funds[a], rl)
|
||||
cvcache = {(a, rl): curve_frame(a, panels[a], metas[a], funds[a], rl, perp=perps[a])
|
||||
for a in ASSETS for rl in ROLLS}
|
||||
pidx = {(a, rl): pair_idx(cvcache[(a, rl)], ctxs[a]) for a in ASSETS for rl in ROLLS}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user