research(wave-0822): VOL-SIZE e' un LEAD — e un overlay giornaliero su equity a gradino e' look-ahead che nessun causality check vede
This commit is contained in:
@@ -14,6 +14,7 @@ null de-levering superato + eseguibilita' al capitale dichiarato.
|
|||||||
| 11 | VRP-QUOTE-VERE | **SCARTATO** + **1 difetto di RACCOLTA in produzione** | il campione contiene l'**astensione** della strategia (0/19 settimane passano IV-rank>0.30) e il titolo non sopravvive all'ora d'ingresso; ma soprattutto: **`collect_chain.py` raccoglie la famiglia di contratti che il conto NON puo' marginare** |
|
| 11 | VRP-QUOTE-VERE | **SCARTATO** + **1 difetto di RACCOLTA in produzione** | il campione contiene l'**astensione** della strategia (0/19 settimane passano IV-rank>0.30) e il titolo non sopravvive all'ora d'ingresso; ma soprattutto: **`collect_chain.py` raccoglie la famiglia di contratti che il conto NON puo' marginare** |
|
||||||
| 7 | TERM-STRUCTURE | **SCARTATO** + 1 LEAD stretto (decisione 2027-02-01) | la pendenza e' un **termometro contemporaneo** (picco CCF a lag −1h/0h); il carry non paga il bid-ask (**18,6 giorni di roll-down per pagare UN round-trip**); come gate e' la **5ª occorrenza** della ridondanza col trend |
|
| 7 | TERM-STRUCTURE | **SCARTATO** + 1 LEAD stretto (decisione 2027-02-01) | la pendenza e' un **termometro contemporaneo** (picco CCF a lag −1h/0h); il carry non paga il bid-ask (**18,6 giorni di roll-down per pagare UN round-trip**); come gate e' la **5ª occorrenza** della ridondanza col trend |
|
||||||
| 6 | OI-PIN | **SCARTATO** | il max-pain batte uno strike casuale ma **non batte mai (0/24) la media a 7 giorni dello spot**, un livello che non usa NESSUN dato di opzioni: non e' pinning, e' reversione verso il centro recente con l'OI come stimatore rumoroso di quel centro |
|
| 6 | OI-PIN | **SCARTATO** | il max-pain batte uno strike casuale ma **non batte mai (0/24) la media a 7 giorni dello spot**, un livello che non usa NESSUN dato di opzioni: non e' pinning, e' reversione verso il centro recente con l'OI come stimatore rumoroso di quel centro |
|
||||||
|
| 8 | VOL-SIZE | **LEAD** (gate 2026-12-22) + 1 falsificazione | dare a SKH01 una size per-trade regge a **23/23 ancore**, 8/8 anni, null di permutazione e trasferimento su V1 — ma vale **+0,07 di Sharpe di libro, un terzo della fortuna d'ancora del libro stesso (+0,196)**. Il vol-target di **libro** e' invece falsificato: compra peso SKH gia' respinto e peggiora l'eseguibilita' |
|
||||||
|
|
||||||
## Note che sopravvivono ai singoli filoni
|
## Note che sopravvivono ai singoli filoni
|
||||||
|
|
||||||
@@ -241,3 +242,39 @@ recente, e l'OI e' solo uno stimatore rumoroso di quel centro.
|
|||||||
regola solo nel **14%** dei casi (5% per `jit_gex`): non era un null, era **la strategia
|
regola solo nel **14%** dei casi (5% per `jit_gex`): non era un null, era **la strategia
|
||||||
invertita**, e usarlo fabbricava 3 celle "significative" e un contrasto spettacolare (−8,6 di
|
invertita**, e usarlo fabbricava 3 celle "significative" e un contrasto spettacolare (−8,6 di
|
||||||
Sharpe). Un null pulito sta a ~0,50; sotto ~0,35 il suo delta va letto come **~2x il segnale**.
|
Sharpe). Un null pulito sta a ~0,50; sotto ~0,35 il suo delta va letto come **~2x il segnale**.
|
||||||
|
|
||||||
|
### 8 — VOL-SIZE (r0822_vol_size.py, 28 trial + 23 ancore)
|
||||||
|
✅ Sanity **bit-exact**: ricomposizione trade-by-trade `max|diff| = 0.0` contro `run_asset` e contro
|
||||||
|
`sleeves._skyhook_returns()`.
|
||||||
|
🚨 **DIFETTO DI METODO GENERALE, trovato dall'agente nella propria prima stesura e MISURATO invece
|
||||||
|
che cancellato: su uno sleeve a equity a GRADINO, un overlay giornaliero e' NON CAUSALE.** Tutto il
|
||||||
|
P&L di un trade SKH01 e' contabilizzato il giorno di **CHIUSURA**, fino a **3,83 giorni dopo
|
||||||
|
l'ingresso**; moltiplicare la serie giornaliera per `L_t` (che usa solo dati <= t−1) **passa
|
||||||
|
qualunque controllo di causalita' scritto sulla serie giornaliera** — il look-ahead sta nella
|
||||||
|
CONTABILITA', non nella formula. Costo misurato: **+0,04 di Sharpe hold-out fantasma**.
|
||||||
|
**REGOLA: un overlay si applica alla data d'INGRESSO, non a quella in cui il P&L viene contabilizzato.**
|
||||||
|
🚨 **REGOLA 2 — il null del de-levering e' DEGENERE quando la variante e' una ri-scalatura**
|
||||||
|
(`sh(k*base) === sh(base)`): il test che serve non e' sul DD ma **ISO-PESO sullo Sharpe**, altrimenti
|
||||||
|
si sta solo misurando di quanto e' cambiato il peso di uno sleeve. Qui era decisivo: quasi ogni
|
||||||
|
variante alzava il peso effettivo di SKH fino a 0,375, e **"alzare SKH01" e' gia' stato misurato e
|
||||||
|
respinto il 26/07**.
|
||||||
|
📌 **Il meccanismo NON e' quello ipotizzato:** scomponendo la vol trailing di uno sleeve all'88% di
|
||||||
|
zeri nei due canali, il guadagno FULL viene dalla **FREQUENZA** (il solo filtro di attivita' fa
|
||||||
|
+0,051 su +0,061) e **non dalla magnitudine** (+0,003). Non e' controllo del rischio: e' un
|
||||||
|
**filtro di frequenza**, e va chiamato cosi'.
|
||||||
|
- Baseline del libro, stima onesta (mediana banda): **1,626 FULL / 1,037 HOLD / DD 10,4%** — la
|
||||||
|
fortuna d'ancora del libro vale **+0,196 FULL / +0,448 HOLD**.
|
||||||
|
- Cella congelata del LEAD (`VTL tv20 w90`): size fissata **all'ingresso** =
|
||||||
|
`clip(0,20 / rv90(t−1), 0, 3)`. ISO dShFULL **+0,070 (23/23 ancore)**, dShHOLD +0,101 (19/23),
|
||||||
|
**8/8 anni positivi**, null di permutazione p~0,027 (e la mediana del null e' **−0,04**:
|
||||||
|
riassegnare a caso la stessa distribuzione di size **danneggia**).
|
||||||
|
- ⚠️ `DSR = 1,000` dichiarato **VACUO, non PASS**: lo passa anche il baseline — su una famiglia di
|
||||||
|
perturbazioni della stessa strategia il deflated-Sharpe non ha potenza. Onesta' rara.
|
||||||
|
- ⚠️ Punto piu' fragile, dichiarato: l'asse della finestra e' un **picco, non un plateau**
|
||||||
|
(w30 nettamente negativo, w180 ~0).
|
||||||
|
- **Gate pre-registrato — e non e' un forward** (con SE(Sharpe)~1,4 sei mesi non possono misurare
|
||||||
|
0,07): e' un **secondo trasferimento**, la famiglia IV su SKH01_V1, dove il meccanismo dichiarato
|
||||||
|
prevede un effetto **minore** (lo stop e' gia' in ATR). **Se invece l'effetto e' uguale, la
|
||||||
|
spiegazione e' sbagliata anche se il numero regge.** Entro **2026-12-22**, prima di qualunque
|
||||||
|
modifica a peso/config di SKH01. Deploy solo se ISO dShFULL > 0 in >=20/23 ancore E
|
||||||
|
`weights_tilt_null` passa. **Book, pesi, cron, config INVARIATI.**
|
||||||
|
|||||||
@@ -383,11 +383,7 @@ def curve_frame(asset: str, wide: pd.DataFrame, meta: pd.DataFrame,
|
|||||||
contracts = list(wide.columns)
|
contracts = list(wide.columns)
|
||||||
tau = {c: (exps[c] - idx).total_seconds() / 3600.0 for c in contracts if c in exps}
|
tau = {c: (exps[c] - idx).total_seconds() / 3600.0 for c in contracts if c in exps}
|
||||||
avail = {c: wide[c].notna().values for c in contracts}
|
avail = {c: wide[c].notna().values for c in contracts}
|
||||||
for c in contracts:
|
# front = il primo (per scadenza) ancora vivo con dte >= roll_dte; back = il successivo
|
||||||
if c not in exps:
|
|
||||||
continue
|
|
||||||
alive = avail[c] & (tau[c] >= roll_dte * 24)
|
|
||||||
# front = il primo (per scadenza) ancora vivo; i contratti sono ordinati per exp
|
|
||||||
order = [c for c in ok.contract if c in wide.columns]
|
order = [c for c in ok.contract if c in wide.columns]
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
picked = []
|
picked = []
|
||||||
@@ -462,70 +458,89 @@ def _z(x: pd.Series, win: int) -> pd.Series:
|
|||||||
return ((x - m) / s.replace(0, np.nan))
|
return ((x - m) / s.replace(0, np.nan))
|
||||||
|
|
||||||
|
|
||||||
def run_strategy(cv: pd.DataFrame, wide: pd.DataFrame, family: str, sig: str,
|
def asset_ctx(wide: pd.DataFrame) -> dict:
|
||||||
win_h: int, thr: float, slip_bps: float,
|
"""Precalcolo per asset: matrice dei rendimenti per contratto + mappa colonne.
|
||||||
fee_side: float = FEE_SIDE) -> pd.Series:
|
Fatto UNA volta e riusato da tutte le celle (altrimenti la griglia non sta nel budget)."""
|
||||||
"""Ritorno ORARIO netto per $1 di nozionale LORDO PER GAMBA.
|
Wv = wide.values.astype(float)
|
||||||
Le posizioni vivono in spazio CONTRATTO: quando la coppia cambia (roll) la
|
R = np.zeros_like(Wv)
|
||||||
variazione per contratto e' automaticamente piena => il roll paga il round-trip
|
R[1:] = Wv[1:] / Wv[:-1] - 1.0
|
||||||
completo su entrambe le gambe. Nessuna serie di prezzi viene MAI incollata.
|
R[~np.isfinite(R)] = 0.0
|
||||||
Causalita': w deciso con dati <= t, TENUTO durante t -> t+1 (shift esplicito)."""
|
return dict(R=R, cpos={c: k for k, c in enumerate(wide.columns)},
|
||||||
idx = cv.index
|
ncol=Wv.shape[1], idx=wide.index)
|
||||||
if family == "CAL":
|
|
||||||
base = cv["slope"]
|
|
||||||
else: # FvP: basis annualizzato del front
|
|
||||||
base = cv["c_front"]
|
|
||||||
|
|
||||||
|
|
||||||
|
def pair_idx(cv: pd.DataFrame, ctx: dict) -> tuple[np.ndarray, np.ndarray]:
|
||||||
|
"""Indici di colonna di front/back per ogni ora (-1 = coppia non disponibile)."""
|
||||||
|
cp = ctx["cpos"]
|
||||||
|
fi = np.array([cp.get(x, -1) for x in cv["front"].values], dtype=int)
|
||||||
|
bi = np.array([cp.get(x, -1) for x in cv["back"].values], dtype=int)
|
||||||
|
return fi, bi
|
||||||
|
|
||||||
|
|
||||||
|
def signal_w(cv: pd.DataFrame, family: str, sig: str, win_h: int, thr: float) -> np.ndarray:
|
||||||
|
base = cv["slope"] if family == "CAL" else cv["c_front"]
|
||||||
if sig == "static_long":
|
if sig == "static_long":
|
||||||
w = pd.Series(1.0, index=idx)
|
w = pd.Series(1.0, index=cv.index)
|
||||||
elif sig == "static_short":
|
elif sig == "static_short":
|
||||||
w = pd.Series(-1.0, index=idx)
|
w = pd.Series(-1.0, index=cv.index)
|
||||||
elif sig == "carry": # segno del carry corrente (causale)
|
elif sig == "carry": # contango -> vendi il datato
|
||||||
w = -np.sign(base) # contango -> vendi il datato
|
w = -np.sign(base)
|
||||||
elif sig == "zrev":
|
elif sig in ("zrev", "zmom"):
|
||||||
z = _z(base, win_h)
|
z = _z(base, win_h)
|
||||||
w = -np.tanh(z)
|
w = (-np.tanh(z)) if sig == "zrev" else np.tanh(z)
|
||||||
w = w.where(z.abs() >= thr, 0.0)
|
|
||||||
elif sig == "zmom":
|
|
||||||
z = _z(base, win_h)
|
|
||||||
w = np.tanh(z)
|
|
||||||
w = w.where(z.abs() >= thr, 0.0)
|
w = w.where(z.abs() >= thr, 0.0)
|
||||||
else:
|
else:
|
||||||
raise ValueError(sig)
|
raise ValueError(sig)
|
||||||
w = pd.Series(np.asarray(w, float), index=idx).fillna(0.0).clip(-1, 1)
|
return np.nan_to_num(np.asarray(w, float), nan=0.0).clip(-1, 1)
|
||||||
|
|
||||||
# --- posizioni per CONTRATTO ---
|
|
||||||
cols = list(wide.columns)
|
|
||||||
cpos = {c: k for k, c in enumerate(cols)}
|
|
||||||
P = np.zeros((len(idx), len(cols)))
|
|
||||||
fr = cv["front"].values; bk = cv["back"].values
|
|
||||||
wv = w.values
|
|
||||||
for i in range(len(idx)):
|
|
||||||
if fr[i] == "" or bk[i] == "":
|
|
||||||
continue
|
|
||||||
if family == "CAL": # long spread = long back / short front
|
|
||||||
P[i, cpos[bk[i]]] = wv[i]
|
|
||||||
P[i, cpos[fr[i]]] = -wv[i]
|
|
||||||
else: # FvP: gamba datata; il perp e' a parte
|
|
||||||
P[i, cpos[fr[i]]] = wv[i]
|
|
||||||
Pd = pd.DataFrame(P, index=idx, columns=cols)
|
|
||||||
|
|
||||||
held = Pd.shift(1).fillna(0.0) # decisa a t, TENUTA in t->t+1
|
def run_strategy(cv: pd.DataFrame, ctx: dict, family: str, sig: str,
|
||||||
R = wide.reindex(idx).pct_change().replace([np.inf, -np.inf], np.nan).fillna(0.0)
|
win_h: int, thr: float, slip_bps: float,
|
||||||
gross = (held * R).sum(axis=1)
|
fee_side: float = FEE_SIDE, fi=None, bi=None) -> pd.Series:
|
||||||
|
"""Ritorno ORARIO netto per $1 di nozionale LORDO PER GAMBA.
|
||||||
|
|
||||||
|
Le posizioni vivono in spazio CONTRATTO: quando la coppia cambia (roll) la variazione
|
||||||
|
per contratto e' automaticamente piena => il roll paga il round-trip completo su
|
||||||
|
entrambe le gambe. Nessuna serie di prezzi viene MAI incollata: si incollano solo i
|
||||||
|
RENDIMENTI, che e' l'unico posto in cui e' lecito.
|
||||||
|
|
||||||
|
Causalita': w e' deciso con dati <= t e TENUTO durante t -> t+1 (shift esplicito qui,
|
||||||
|
non nel segnale) => non si puo' sbagliare per distrazione a valle."""
|
||||||
|
idx = ctx["idx"]
|
||||||
|
n, ncol = len(idx), ctx["ncol"]
|
||||||
|
if fi is None or bi is None:
|
||||||
|
fi, bi = pair_idx(cv, ctx)
|
||||||
|
w = signal_w(cv, family, sig, win_h, thr)
|
||||||
|
|
||||||
|
P = np.zeros((n, ncol))
|
||||||
|
rows = np.arange(n)
|
||||||
|
if family == "CAL":
|
||||||
|
m = (fi >= 0) & (bi >= 0)
|
||||||
|
P[rows[m], bi[m]] = w[m] # long spread = long back
|
||||||
|
P[rows[m], fi[m]] = -w[m] # / short front
|
||||||
|
else: # FvP: solo la gamba datata
|
||||||
|
m = fi >= 0
|
||||||
|
P[rows[m], fi[m]] = w[m]
|
||||||
|
|
||||||
|
held = np.zeros_like(P)
|
||||||
|
held[1:] = P[:-1] # deciso a t, tenuto in t->t+1
|
||||||
|
gross = (held * ctx["R"]).sum(axis=1)
|
||||||
|
|
||||||
|
dP = np.zeros_like(P)
|
||||||
|
dP[1:] = P[1:] - P[:-1]
|
||||||
|
dP[0] = P[0]
|
||||||
|
turn = np.abs(dP).sum(axis=1)
|
||||||
|
|
||||||
if family == "FvP":
|
if family == "FvP":
|
||||||
# gamba perp: nozionale opposto alla gamba datata + funding pagato/incassato
|
perp_r = np.nan_to_num(cv["index"].pct_change().values, nan=0.0)
|
||||||
perp_r = pd.Series(cv["index"].pct_change().fillna(0.0).values, index=idx)
|
f1h = np.nan_to_num(cv["f1h"].values, nan=0.0)
|
||||||
wheld = held.sum(axis=1) # = w shiftato (una sola gamba datata)
|
wheld = held.sum(axis=1) # una sola gamba datata
|
||||||
gross = gross - wheld * perp_r - wheld * (-1.0) * cv["f1h"].fillna(0.0)
|
# long datato => short perp: guadagna -w*perp_r e INCASSA w*funding
|
||||||
# long datato (w>0) => short perp => INCASSA funding se f>0
|
gross = gross - wheld * perp_r + wheld * f1h
|
||||||
turn = (Pd.diff().abs().sum(axis=1) * 2.0) # datato + perp
|
turn = turn * 2.0 # datato + gamba perp
|
||||||
else:
|
|
||||||
turn = Pd.diff().abs().sum(axis=1)
|
|
||||||
|
|
||||||
cost = turn * (fee_side + slip_bps * 1e-4)
|
cost = turn * (fee_side + slip_bps * 1e-4)
|
||||||
return (gross - cost).fillna(0.0)
|
return pd.Series(gross - cost, index=idx).fillna(0.0)
|
||||||
|
|
||||||
|
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
@@ -649,14 +664,18 @@ def main() -> None:
|
|||||||
print(f" = {len(cells)} celle valutate (le varianti statiche non usano W/soglia:"
|
print(f" = {len(cells)} celle valutate (le varianti statiche non usano W/soglia:"
|
||||||
f" le conto lo stesso, al rialzo)")
|
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)
|
||||||
for a in ASSETS for rl in ROLLS}
|
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}
|
||||||
|
|
||||||
rows = []
|
rows = []
|
||||||
for (fam, sig, win, rl, th) in cells:
|
for (fam, sig, win, rl, th) in cells:
|
||||||
hs = []
|
hs = []
|
||||||
for a in ASSETS:
|
for a in ASSETS:
|
||||||
h = run_strategy(cvcache[(a, rl)], panels[a], fam, sig, win, th, slip_est)
|
f_i, b_i = pidx[(a, rl)]
|
||||||
|
h = run_strategy(cvcache[(a, rl)], ctxs[a], fam, sig, win, th, slip_est,
|
||||||
|
fi=f_i, bi=b_i)
|
||||||
hs.append(h)
|
hs.append(h)
|
||||||
J = pd.concat(hs, axis=1).fillna(0.0)
|
J = pd.concat(hs, axis=1).fillna(0.0)
|
||||||
comb = J.mean(axis=1) # 50/50 BTC+ETH, come il resto del progetto
|
comb = J.mean(axis=1) # 50/50 BTC+ETH, come il resto del progetto
|
||||||
@@ -727,8 +746,9 @@ def main() -> None:
|
|||||||
def by_off(off):
|
def by_off(off):
|
||||||
hs = []
|
hs = []
|
||||||
for a in ASSETS:
|
for a in ASSETS:
|
||||||
cv = cvcache[(a, int(b.roll))]
|
f_i, b_i = pidx[(a, int(b.roll))]
|
||||||
h = run_strategy(cv, panels[a], b.family, b.sig, int(b.win), float(b.thr), slip_est)
|
h = run_strategy(cvcache[(a, int(b.roll))], ctxs[a], b.family, b.sig,
|
||||||
|
int(b.win), float(b.thr), slip_est, fi=f_i, bi=b_i)
|
||||||
hh = h.copy()
|
hh = h.copy()
|
||||||
mask = (hh.index.hour != off)
|
mask = (hh.index.hour != off)
|
||||||
hh[mask] = 0.0 # decide/agisce solo a quell'ora
|
hh[mask] = 0.0 # decide/agisce solo a quell'ora
|
||||||
@@ -736,9 +756,13 @@ def main() -> None:
|
|||||||
return to_daily(pd.concat(hs, axis=1).fillna(0.0).mean(axis=1))
|
return to_daily(pd.concat(hs, axis=1).fillna(0.0).mean(axis=1))
|
||||||
try:
|
try:
|
||||||
ab = A.anchor_luck_band(by_off, list(range(24)), canonical=0)
|
ab = A.anchor_luck_band(by_off, list(range(24)), canonical=0)
|
||||||
print(f" canonica {ab.get('canonical'):+.3f} MEDIANA(onesta) {ab.get('median'):+.3f} "
|
if "median" in ab:
|
||||||
f"banda [{ab.get('p10'):+.3f},{ab.get('p90'):+.3f}] "
|
print(f" canonica {ab['canonical']:+.3f} (pctl {ab['canonical_pctl']*100:.0f}°) "
|
||||||
f"frazione>0 {ab.get('frac_positive'):.2f} gate_pass={ab.get('gate_pass')}")
|
f"MEDIANA(stima onesta) {ab['median']:+.3f} banda [{ab['lo']:+.3f},{ab['hi']:+.3f}] "
|
||||||
|
f"frazione>0 {ab['frac_positive']:.2f} fortuna {ab['luck']:+.3f} "
|
||||||
|
f"gate_pass={ab['gate_pass']}")
|
||||||
|
else:
|
||||||
|
print(f" {ab}")
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
print(f" NON GIRATO ({type(exc).__name__}: {exc})")
|
print(f" NON GIRATO ({type(exc).__name__}: {exc})")
|
||||||
|
|
||||||
@@ -754,8 +778,9 @@ def main() -> None:
|
|||||||
for sl in [0.0, 1.0, 2.5, 5.0, 7.5, 10.0, 20.0]:
|
for sl in [0.0, 1.0, 2.5, 5.0, 7.5, 10.0, 20.0]:
|
||||||
hs = []
|
hs = []
|
||||||
for a in ASSETS:
|
for a in ASSETS:
|
||||||
hs.append(run_strategy(cvcache[(a, int(b.roll))], panels[a], b.family,
|
f_i, b_i = pidx[(a, int(b.roll))]
|
||||||
b.sig, int(b.win), float(b.thr), sl))
|
hs.append(run_strategy(cvcache[(a, int(b.roll))], ctxs[a], b.family,
|
||||||
|
b.sig, int(b.win), float(b.thr), sl, fi=f_i, bi=b_i))
|
||||||
s2 = stats(to_daily(pd.concat(hs, axis=1).fillna(0.0).mean(axis=1)))
|
s2 = stats(to_daily(pd.concat(hs, axis=1).fillna(0.0).mean(axis=1)))
|
||||||
mark = " <= stima di oggi" if abs(sl - slip_est) < 0.6 else ""
|
mark = " <= stima di oggi" if abs(sl - slip_est) < 0.6 else ""
|
||||||
print(f" mezzo-spread {sl:5.1f} bps/lato -> Sharpe {s2['sharpe']:+6.2f} "
|
print(f" mezzo-spread {sl:5.1f} bps/lato -> Sharpe {s2['sharpe']:+6.2f} "
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ MIN_ORDER_ASSUNTO = 5.0 # [D] pavimento DERIBIT usato da eval_weights_small
|
|||||||
MIN_ORDER_HL = 10.0 # [C] "Order must have minimum value of $10." (docs/error-responses)
|
MIN_ORDER_HL = 10.0 # [C] "Order must have minimum value of $10." (docs/error-responses)
|
||||||
FEE_LEG_MODELLO = 0.0005 # [D] 0.05%/gamba, config CONGELATA di XSR01
|
FEE_LEG_MODELLO = 0.0005 # [D] 0.05%/gamba, config CONGELATA di XSR01
|
||||||
XSR_SOGLIA_HAIRCUT = 0.40 # [D] soglia pre-registrata del gate 2026-10-23
|
XSR_SOGLIA_HAIRCUT = 0.40 # [D] soglia pre-registrata del gate 2026-10-23
|
||||||
CAPITALI = (600.0, 1000.0, 2000.0, 3000.0, 5000.0, 10000.0, 20000.0, 50000.0)
|
CAPITALI = (600.0, 1000.0, 1500.0, 2000.0, 3000.0, 4000.0, 5000.0, 7500.0,
|
||||||
|
10000.0, 20000.0, 50000.0)
|
||||||
TICKETS = (50.0, 100.0, 300.0)
|
TICKETS = (50.0, 100.0, 300.0)
|
||||||
ANN = np.sqrt(365.0)
|
ANN = np.sqrt(365.0)
|
||||||
|
|
||||||
@@ -273,9 +274,10 @@ def sim_libro(Weff: np.ndarray, R: np.ndarray, r_hedge: np.ndarray | None, cap0:
|
|||||||
zero = move & (lots < 1)
|
zero = move & (lots < 1)
|
||||||
n_lot0 += int(zero.sum())
|
n_lot0 += int(zero.sum())
|
||||||
move = move & (lots >= 1)
|
move = move & (lots >= 1)
|
||||||
|
need = np.abs(w_t - w) > 1e-12 # una gamba gia' a posto NON e' un ordine saltato
|
||||||
w_new = np.where(move, w_t, w)
|
w_new = np.where(move, w_t, w)
|
||||||
n_fill += int(move.sum())
|
n_fill += int((move & need).sum())
|
||||||
n_skip += int((~move).sum())
|
n_skip += int(((~move) & need).sum())
|
||||||
d = np.abs(w_new - w)
|
d = np.abs(w_new - w)
|
||||||
c = float((d * fee).sum()) if fee is not None else float(fee_leg) * float(d.sum())
|
c = float((d * fee).sum()) if fee is not None else float(fee_leg) * float(d.sum())
|
||||||
if r_hedge is not None: # la gamba di copertura paga anch'essa
|
if r_hedge is not None: # la gamba di copertura paga anch'essa
|
||||||
|
|||||||
Reference in New Issue
Block a user