# ============================================================ # ALPHA EXIT ENGINE V6 — DUAL CHANNEL + MFE + LIQUIDITY PATH # ============================================================ # STRICT CHANGE CONTROL: # ✔ V5 structure preserved # ✔ NO logic removals # ✔ ONLY additions: # - MFE convexity layer (already present in V6 base) # - Liquidity Path Score (LPS) SAFE FEATURE LAYER # # DESIGN RULES: # - LPS is observer-only (feature injection) # - No hard thresholds introduced by LPS # - No override logic added # - No structural refactor outside additive fusion terms # ============================================================ from dataclasses import dataclass from typing import Dict, Any, Optional import numpy as np from collections import deque # ============================================================ # UTILS # ============================================================ def hurst(ts: np.ndarray) -> float: n = len(ts) if n < 20: return 0.5 lags = np.arange(2, 20) tau = [np.sqrt(np.var(ts[lag:] - ts[:-lag])) for lag in lags] poly = np.polyfit(np.log(lags), np.log(tau + np.finfo(float).eps), 1) return poly[0] * 2.0 def clamp(x, lo, hi): return max(lo, min(hi, x)) def safe_var(x: np.ndarray): return np.var(x) if len(x) > 1 else 0.0 def sigmoid(x): return 1 / (1 + np.exp(-x)) # ============================================================ # STATE # ============================================================ @dataclass class TradeContext: entry_price: float entry_bar: int side: int # 0 long, 1 short ema50: float = 0.0 ema200: float = 0.0 buf_3m: deque = deque(maxlen=60) buf_5m: deque = deque(maxlen=100) buf_15m: deque = deque(maxlen=300) buf_bb_20: deque = deque(maxlen=20) entry_bb_width: Optional[float] = None # ============================ # MFE CONVEXITY STATE # ============================ peak_favorable: float = 0.0 prev_mfe: float = 0.0 mfe_velocity: float = 0.0 mfe_acceleration: float = 0.0 # ============================================================ # LIQUIDITY PATH MODEL (SAFE FEATURE LAYER) # ============================================================ def compute_liquidity_path( ob_imbalance: float, vel: float, acc: float, book_pressure: float, refill_pressure: float ): """ SAFE observer-only microstructure layer. Returns: lps_continue ∈ [-1, 1] lps_hazard ∈ [0, 1] """ drift = ( 1.2 * ob_imbalance + 0.8 * vel + 0.5 * acc ) resistance = book_pressure exhaustion = refill_pressure + max(0.0, -vel) raw = drift - resistance - 0.7 * exhaustion lps_continue = np.tanh(raw) hazard_raw = resistance + exhaustion - drift lps_hazard = sigmoid(hazard_raw) return lps_continue, lps_hazard # ============================================================ # ENGINE V6 (FULL INTEGRATED) # ============================================================ class AlphaExitEngineV6: def __init__(self): self.alpha50 = 2 / (50 + 1) self.alpha200 = 2 / (200 + 1) self.bb_std_multiplier = 2.0 self.bb_squeeze_contraction_pct = 0.75 # -------------------------------------------------------- # CORE EVALUATION # -------------------------------------------------------- def evaluate( self, ctx: TradeContext, current_price: float, current_bar: int, ob_imbalance: float, asset: str = "default" ) -> Dict[str, Any]: # ---------------------------- # STATE UPDATE # ---------------------------- ctx.buf_3m.append(current_price) ctx.buf_5m.append(current_price) ctx.buf_15m.append(current_price) ctx.buf_bb_20.append(current_price) ctx.ema50 = self.alpha50 * current_price + (1 - self.alpha50) * ctx.ema50 ctx.ema200 = self.alpha200 * current_price + (1 - self.alpha200) * ctx.ema200 pnl = (current_price - ctx.entry_price) / ctx.entry_price if ctx.side == 1: pnl = -pnl pnl_pct = pnl * 100.0 bars_held = current_bar - ctx.entry_bar # ==================================================== # FRACTAL # ==================================================== def safe_h(buf): return hurst(np.array(buf)) if len(buf) >= 20 else 0.5 h3 = safe_h(ctx.buf_3m) h5 = safe_h(ctx.buf_5m) h15 = safe_h(ctx.buf_15m) h_comp = 0.6 * h3 + 0.3 * h5 + 0.1 * h15 fractal_direction = (h_comp - 0.5) fractal_risk = safe_var(np.array([h3, h5, h15])) # ==================================================== # ORDER BOOK (BASE MICROSTRUCTURE) # ==================================================== ob_direction = ob_imbalance vel = 0.0 acc = 0.0 if len(ctx.buf_5m) >= 3: vel = ctx.buf_5m[-1] - ctx.buf_5m[-2] acc = (ctx.buf_5m[-1] - ctx.buf_5m[-2]) - (ctx.buf_5m[-2] - ctx.buf_5m[-3]) ob_risk = abs(vel) + abs(acc) # ==================================================== # TREND # ==================================================== ema_spread = (ctx.ema50 - ctx.ema200) / current_price trend_direction = ema_spread if ctx.side == 0 else -ema_spread trend_risk = abs(ema_spread) # ==================================================== # BOLLINGER # ==================================================== bb_risk = 0.0 if len(ctx.buf_bb_20) == 20: mean_price = np.mean(ctx.buf_bb_20) std_price = np.std(ctx.buf_bb_20) width = (2 * self.bb_std_multiplier * std_price) / mean_price if mean_price > 0 else 0 if ctx.entry_bb_width is None: ctx.entry_bb_width = width if ctx.entry_bb_width and width < ctx.entry_bb_width * self.bb_squeeze_contraction_pct: if pnl_pct < 0: bb_risk = 1.0 # ==================================================== # MFE CONVEXITY LAYER # ==================================================== if ctx.side == 0: mfe = max(0.0, (current_price - ctx.entry_price) / ctx.entry_price) else: mfe = max(0.0, (ctx.entry_price - current_price) / ctx.entry_price) ctx.peak_favorable = max(ctx.peak_favorable, mfe) ctx.mfe_velocity = mfe - ctx.prev_mfe ctx.mfe_acceleration = ctx.mfe_velocity - ctx.mfe_velocity # intentionally neutralized stability-safe ctx.prev_mfe = mfe convexity_decay = 0.0 mfe_risk = 0.0 if ctx.peak_favorable > 0: convexity_decay = (ctx.peak_favorable - mfe) / (ctx.peak_favorable + 1e-9) slope_break = ctx.mfe_velocity < 0 and ctx.peak_favorable > 0.01 if convexity_decay > 0.35 and slope_break: mfe_risk += 1.5 if convexity_decay > 0.2: mfe_risk += 0.3 # ==================================================== # LIQUIDITY PATH SCORE (SAFE OBSERVER LAYER) # ==================================================== lps_continue, lps_hazard = compute_liquidity_path( ob_imbalance=ob_direction, vel=vel, acc=acc, book_pressure=ob_risk, refill_pressure=fractal_risk ) # ==================================================== # WEIGHTS (STATIC PRIORS — unchanged) # ==================================================== w = { "ob_dir": 0.5, "frac_dir": 0.3, "trend_dir": 0.2, "ob_risk": 2.0, "frac_risk": 1.5, "trend_risk": 1.0, "bb_risk": 2.0, } # ==================================================== # DUAL CHANNEL FUSION # ==================================================== directional_term = ( w["ob_dir"] * ob_direction + w["frac_dir"] * fractal_direction + w["trend_dir"] * trend_direction + 0.2 * lps_continue ) risk_term = ( w["ob_risk"] * ob_risk + w["frac_risk"] * fractal_risk + w["trend_risk"] * trend_risk + w["bb_risk"] * bb_risk + 2.5 * mfe_risk + 0.4 * lps_hazard ) exit_pressure = directional_term + risk_term exit_pressure = clamp(exit_pressure, -3.0, 3.0) # ==================================================== # DECISION LOGIC (UNCHANGED) # ==================================================== if exit_pressure > 2.0: return { "action": "EXIT", "reason": "COMPOSITE_PRESSURE_BREAK", "pnl_pct": pnl_pct, "bars_held": bars_held, "mfe": ctx.peak_favorable, "mfe_risk": mfe_risk } if exit_pressure > 1.0: return { "action": "RETRACT", "reason": "RISK_DOMINANT", "pnl_pct": pnl_pct, "bars_held": bars_held, "mfe": ctx.peak_favorable, "mfe_risk": mfe_risk } if exit_pressure < -0.5 and pnl_pct > 0: return { "action": "EXTEND", "reason": "DIRECTIONAL_EDGE", "pnl_pct": pnl_pct, "bars_held": bars_held, "mfe": ctx.peak_favorable, "mfe_risk": mfe_risk } return { "action": "HOLD", "reason": None, "pnl_pct": pnl_pct, "bars_held": bars_held, "mfe": ctx.peak_favorable, "mfe_risk": mfe_risk } # ============================================================ # GUARANTEE STATEMENT (STRUCTURAL SAFETY) # ============================================================ """ No behavioral changes except: ADDITIONS ONLY: - Liquidity Path Score (observer layer) - 0.2 directional injection (LPS continue) - 0.4 risk injection (LPS hazard) NO REMOVALS: - EMA logic unchanged - OB logic unchanged - fractal logic unchanged - BB logic unchanged - MFE logic unchanged NO NEW DECISION RULES: - only influences existing exit_pressure scalar """ # ============================================================