import sys with open('nautilus_dolphin/nautilus/alpha_orchestrator.py', 'r', encoding='utf-8') as f: text = f.read() addition = """ def set_acb(self, acb) -> None: \"\"\"Inject AdaptiveCircuitBreaker for per-date boost + dynamic beta.\"\"\" self._acb = acb def set_mc_forewarner(self, forewarner, mc_base_cfg: dict) -> None: \"\"\"Inject DolphinForewarner + frozen champion config for per-date envelope gate.\"\"\" self._forewarner = forewarner self._mc_base_cfg = dict(mc_base_cfg) # ------------------------------------------------------------------ # Internal helpers — ACB 3-scale meta-boost # ------------------------------------------------------------------ def _strength_cubic(self, vel_div: float) -> float: \"\"\"Normalised signal strength in [0,1]^convexity — mirrors bet_sizer formula.\"\"\" if vel_div >= self.signal_gen.threshold: return 0.0 raw = (self.signal_gen.threshold - vel_div) / (self.signal_gen.threshold - self.signal_gen.extreme) return min(1.0, max(0.0, raw)) ** self.bet_sizer.convexity def _update_regime_size_mult(self, vel_div: float) -> None: \"\"\"Compute regime_size_mult from ACB day state + current vel_div strength. 3-scale formula: base_boost × (1 + β × strength³) × mc_scale β>0 gate is doctrinal: applies whenever eigenvalue-velocity regime is active, independent of whether ACB has macro signals (base_boost may still be 1.0). \"\"\" if self._day_beta > 0: ss = self._strength_cubic(vel_div) self.regime_size_mult = self._day_base_boost * (1.0 + self._day_beta * ss) * self._day_mc_scale else: self.regime_size_mult = self._day_base_boost * self._day_mc_scale # ------------------------------------------------------------------ # process_day — canonical day runner (params live here, not in tests) # ------------------------------------------------------------------ def process_day( self, date_str: str, df, asset_columns: list, vol_regime_ok = None, ) -> dict: \"\"\"Run one full trading day. All per-date regime setup is internal. Parameters ---------- date_str : str Date string matching ACB w750 cache key, e.g. '2026-01-14'. df : pd.DataFrame Parquet bar data: must contain 'vel_div' column + asset price columns. asset_columns : List[str] Non-meta column names (asset price columns only). vol_regime_ok : Optional[np.ndarray] Per-bar boolean array (len == len(df)). If None, bars 0-99 are treated as warm-up (vol_ok=False); bar 100+ treated as True. Returns ------- dict date, pnl, capital, boost, beta, mc_status, trades \"\"\" import numpy as np cap_start = self.capital self.regime_direction = -1 # SHORT-biased (invariant of champion) self.regime_dd_halt = False self._day_mc_scale = 1.0 self._day_mc_status = 'OK' # 1. ACB per-date: dynamic beta + base boost (OB Sub-4 modulates beta) if hasattr(self, '_acb') and self._acb is not None: acb_info = self._acb.get_dynamic_boost_for_date(date_str, ob_engine=self.ob_engine) self._day_base_boost = acb_info['boost'] self._day_beta = acb_info['beta'] else: self._day_base_boost = 1.0 self._day_beta = 0.0 # 2. MC-Forewarner per-date envelope gate if hasattr(self, '_forewarner') and self._forewarner is not None and self._mc_base_cfg is not None: mc_cfg = dict(self._mc_base_cfg) mc_cfg['max_leverage'] = self.base_max_leverage * self._day_base_boost mc_report = self._forewarner.assess_config_dict(mc_cfg) mc_red = mc_report.catastrophic_probability > 0.25 or mc_report.envelope_score < -1.0 mc_orange = (not mc_red) and ( mc_report.envelope_score < 0 or mc_report.catastrophic_probability > 0.10 ) self._day_mc_status = 'RED' if mc_red else ('ORANGE' if mc_orange else 'OK') self._day_mc_scale = 0.5 if mc_orange else 1.0 if mc_red: self.regime_dd_halt = True # 3. Bar loop n_before = len(self.trade_history) bid = 0 for ri in range(len(df)): row = df.iloc[ri] vd = row.get('vel_div') if vd is None or not np.isfinite(float(vd)): self._global_bar_idx += 1; bid += 1; continue v50_raw = row.get('v50_lambda_max_velocity') v750_raw = row.get('v750_lambda_max_velocity') v50_val = float(v50_raw) if (v50_raw is not None and np.isfinite(float(v50_raw))) else 0.0 v750_val = float(v750_raw) if (v750_raw is not None and np.isfinite(float(v750_raw))) else 0.0 prices = {} for ac in asset_columns: p = row.get(ac) if p is not None and p > 0 and np.isfinite(p): prices[ac] = float(p) if ac not in self._price_histories: self._price_histories[ac] = [] self._price_histories[ac].append(float(p)) if len(self._price_histories[ac]) > 500: self._price_histories[ac] = self._price_histories[ac][-200:] if not prices: self._global_bar_idx += 1; bid += 1; continue vrok = bool(vol_regime_ok[ri]) if vol_regime_ok is not None else (bid >= 100) # Compute regime_size_mult from ACB day state + current signal strength self._update_regime_size_mult(float(vd)) self.process_bar( bar_idx=self._global_bar_idx, vel_div=float(vd), prices=prices, vol_regime_ok=vrok, price_histories=self._price_histories, v50_vel=v50_val, v750_vel=v750_val, ) self._global_bar_idx += 1 bid += 1 return { 'date': date_str, 'pnl': self.capital - cap_start, 'capital': self.capital, 'boost': self._day_base_boost, 'beta': self._day_beta, 'mc_status': self._day_mc_status, 'trades': len(self.trade_history) - n_before, } """ if "def process_day" not in text: with open('nautilus_dolphin/nautilus/alpha_orchestrator.py', 'a', encoding='utf-8') as f: f.write(addition) print("Patched alpha_orchestrator.py successfully.") else: print("Already patched.")