research(wave-0822): VRP-QUOTE-VERE scartato — e collect_chain raccoglie la famiglia di contratti che il conto non puo' marginare
This commit is contained in:
@@ -205,11 +205,15 @@ def _panel_index(start: str) -> pd.DatetimeIndex:
|
||||
_RG_CACHE: dict = {}
|
||||
|
||||
|
||||
def book_RG(w: dict, start: str = START_WIN) -> tuple[np.ndarray, np.ndarray]:
|
||||
def book_RG(w: dict, start: str = START_WIN,
|
||||
drift_mult: tuple = ()) -> tuple[np.ndarray, np.ndarray]:
|
||||
"""(R, gap) giornalieri di un libro a pesi arbitrari sui 5 sleeve.
|
||||
Crypto TP01+SKH01: minimo ESATTO sul path orario condiviso (r0725_prop_coupled).
|
||||
XS01/VRP01/GTAA01: il loro minimo si SOMMA (worst simultaneo — convenzione del 25/07)."""
|
||||
key = (start,) + tuple(round(float(w.get(nm, 0.0)), 6) for nm in SLEEVES)
|
||||
XS01/VRP01/GTAA01: il loro minimo si SOMMA (worst simultaneo — convenzione del 25/07).
|
||||
`drift_mult` = (("XS01", 0.5), ...): taglia il DRIFT di quello sleeve (non la vol) — serve
|
||||
per lo stress giudiziale su uno sleeve scoperto DENTRO la finestra di misura."""
|
||||
dm = dict(drift_mult)
|
||||
key = (start, drift_mult) + tuple(round(float(w.get(nm, 0.0)), 6) for nm in SLEEVES)
|
||||
if key in _RG_CACHE:
|
||||
return _RG_CACHE[key]
|
||||
idx = _panel_index(start)
|
||||
@@ -218,15 +222,25 @@ def book_RG(w: dict, start: str = START_WIN) -> tuple[np.ndarray, np.ndarray]:
|
||||
M = np.zeros(len(idx))
|
||||
if w_tp > 0 or w_skh > 0:
|
||||
c = _crypto(w_tp, w_skh).reindex(idx)
|
||||
R += c["R"].values
|
||||
cr = c["R"].values
|
||||
if w_tp > 0 and dm.get("TP01", 1.0) != 1.0 or w_skh > 0 and dm.get("SKH01", 1.0) != 1.0:
|
||||
raise NotImplementedError("stress sul drift crypto: il minimo e' path-esatto, non separabile")
|
||||
R += cr
|
||||
M += c["m"].values
|
||||
for nm, fr in (("XS01", pc.xsec_daily_tuples()), ("VRP01", vrp_daily_tuples()),
|
||||
("GTAA01", gtaa_daily_tuples())):
|
||||
wt = w.get(nm, 0.0)
|
||||
if wt > 0:
|
||||
f = fr.reindex(idx)
|
||||
R += wt * f["R"].values
|
||||
M += wt * f["m"].values
|
||||
rv = np.nan_to_num(f["R"].values)
|
||||
mv = np.nan_to_num(f["m"].values)
|
||||
mult = dm.get(nm, 1.0)
|
||||
if mult != 1.0: # taglia il drift, lascia la forma della coda
|
||||
cut = (1.0 - mult) * rv.mean() # NB: media PRIMA del taglio
|
||||
rv = rv - cut
|
||||
mv = mv - cut
|
||||
R += wt * rv
|
||||
M += wt * mv
|
||||
R = np.nan_to_num(R)
|
||||
M = np.nan_to_num(M)
|
||||
_RG_CACHE[key] = (R, np.minimum(M, R) - R)
|
||||
@@ -299,21 +313,34 @@ def funded_sim(R: np.ndarray, G: np.ndarray, idx: np.ndarray, lev: float, firm:
|
||||
if (t + 1) % 365 == 0:
|
||||
alive_at[(t + 1) // 365] = float(alive.mean())
|
||||
return dict(p_alive=float(alive.mean()), alive_at=alive_at,
|
||||
e_payout=float(payout.mean()), payout=payout)
|
||||
e_payout=float(payout.mean()), payout=payout, alive=alive)
|
||||
|
||||
|
||||
def objective(w: dict, lev: float, firm: str, ev_idx: np.ndarray, fu_idx: np.ndarray,
|
||||
lens: str = "coupled", factor: float = DELUCK,
|
||||
notional: float = 100_000.0) -> dict:
|
||||
R, G = book_RG(w)
|
||||
notional: float = 100_000.0, drift_mult: tuple = ()) -> dict:
|
||||
R, G = book_RG(w, drift_mult=drift_mult)
|
||||
R = deluck(R, factor)
|
||||
e = eval_sim(R, G, ev_idx, lev, firm, lens)
|
||||
f = funded_sim(R, G, fu_idx, lev, firm, notional, lens)
|
||||
ann = float(R.mean() * 365.0)
|
||||
vol = float(R.std() * np.sqrt(365.0))
|
||||
# stimatore per-percorso di J: eval e funded girano su indici di bootstrap INDIPENDENTI,
|
||||
# quindi mean(passed_i * alive_i) stima p_pass*p_alive ed e' APPAIABILE fra configurazioni.
|
||||
jvec = (e["passed"] & f["alive"]).astype(float)
|
||||
return dict(J=e["p_pass"] * f["p_alive"], p_pass=e["p_pass"], p_alive=f["p_alive"],
|
||||
e_payout=f["e_payout"], sharpe=(ann / vol if vol > 0 else 0.0),
|
||||
vol=vol, drift=ann, t_pass=e["t_pass"])
|
||||
vol=vol, drift=ann, t_pass=e["t_pass"], jvec=jvec)
|
||||
|
||||
|
||||
def paired_delta(wA: dict, levA: float, wB: dict, levB: float, firm: str,
|
||||
ev_idx: np.ndarray, fu_idx: np.ndarray) -> tuple[float, float]:
|
||||
"""Differenza APPAIATA di J fra due configurazioni (stessi indici di bootstrap) + errore
|
||||
standard della differenza. Il livello di J ha SE ~0.01; la DIFFERENZA molto meno."""
|
||||
a = objective(wA, levA, firm, ev_idx, fu_idx)["jvec"]
|
||||
b = objective(wB, levB, firm, ev_idx, fu_idx)["jvec"]
|
||||
d = a - b
|
||||
return float(d.mean()), float(d.std(ddof=1) / np.sqrt(len(d)))
|
||||
|
||||
|
||||
# ================================================================== §2. IL CONTO ANALITICO
|
||||
@@ -358,7 +385,8 @@ def grid_scan(grid: list[dict], levs: tuple, firm: str, ev_idx: np.ndarray, fu_i
|
||||
for w in grid:
|
||||
for lev in levs:
|
||||
o = objective(w, lev, firm, ev_idx, fu_idx, lens, factor)
|
||||
rows.append(dict(w=wkey(w), lev=lev, **{k: v for k, v in o.items()}))
|
||||
rows.append(dict(w=wkey(w), lev=lev,
|
||||
**{k: v for k, v in o.items() if k != "jvec"}))
|
||||
return pd.DataFrame(rows)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user