initial: import DOLPHIN baseline 2026-04-21 from dolphinng5_predict working tree
Includes core prod + GREEN/BLUE subsystems: - prod/ (BLUE harness, configs, scripts, docs) - nautilus_dolphin/ (GREEN Nautilus-native impl + dvae/ preserved) - adaptive_exit/ (AEM engine + models/bucket_assignments.pkl) - Observability/ (EsoF advisor, TUI, dashboards) - external_factors/ (EsoF producer) - mc_forewarning_qlabs_fork/ (MC regime/envelope) Excludes runtime caches, logs, backups, and reproducible artifacts per .gitignore.
This commit is contained in:
358
prod/docs/alpha_exit_v6_spec.py
Executable file
358
prod/docs/alpha_exit_v6_spec.py
Executable file
@@ -0,0 +1,358 @@
|
||||
# ============================================================
|
||||
# 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
|
||||
"""
|
||||
# ============================================================
|
||||
Reference in New Issue
Block a user