Overall Statistics
Total Orders
38
Average Win
0.40%
Average Loss
-0.24%
Compounding Annual Return
13.724%
Drawdown
31.100%
Expectancy
0.138
Start Equity
1000000
End Equity
2799897.81
Net Profit
179.990%
Sharpe Ratio
0.492
Sortino Ratio
0.505
Probabilistic Sharpe Ratio
12.227%
Loss Rate
58%
Win Rate
42%
Profit-Loss Ratio
1.70
Alpha
-0.001
Beta
0.949
Annual Standard Deviation
0.154
Annual Variance
0.024
Information Ratio
-0.386
Tracking Error
0.012
Treynor Ratio
0.08
Total Fees
$37.67
Estimated Strategy Capacity
$31000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
Portfolio Turnover
0.04%
Drawdown Recovery
708
# region imports
from AlgorithmImports import *
from collections import deque
from datetime import timedelta, datetime
# endregion


class SPXTailHedgeVega64_RussellTail(QCAlgorithm):
    """
    SPY core + IWM tail puts + optional SPX kicker + shocks + crisis + IV/Vega plateau + Slack intents + EOD report.

    Production-lean edits (CPU + robustness):
      - min contract thresholds (avoid -1/-2 micro trades)
      - batched rehedge (min hedge_cash, min qty)
      - kicker gated to crisis/imminent + cooldown
      - tail establish max-per-day
      - slightly wider limit band + faster stale cancel
      - restart rebind (RebuildStateFromPortfolio)
      - single-pass option selectors (avoid extra list allocs)
      - daily IVP caching (avoid repeated O(N) percentile scans)
      - LIVE hardeners:
          (1) guaranteed first DailyCheck even if algo starts late
          (2) force first core allocation with SetHoldings (bypass HITL/caps)
          (3) live-only early tail seed window
    """

    def Initialize(self):
        # ===== Params / toggles =====
        self.Debug(f"INIT START | Live={self.LiveMode} | Time={self.Time}")
        self.SetWarmUp(0)

        self.DEBUG = (self.GetParameter("debug") or "1") == "1"

        self.SLACK_ENABLED = (self.GetParameter("slack_enable") or "1") != "0"
        self.SLACK_TRADE_INTENTS = (self.GetParameter("slack_trade_intents") or "1") != "0"
        self.SLACK_EOD_REPORT = (self.GetParameter("slack_eod_report") or "1") != "0"
        self.SLACK_MODE_ALERTS = (self.GetParameter("slack_mode_alerts") or "1") != "0"
        self.SLACK_MAX_ITEMS = int(self.GetParameter("slack_daily_max_items") or "12")

        self.ENABLE_TAIL_HEDGE = (self.GetParameter("tail_enable") or "1") != "0"
        self.ENABLE_SHOCKS = (self.GetParameter("shock_enable") or "1") != "0"
        self.ENABLE_KICKER = (self.GetParameter("kicker_enable") or "1") != "0"
        self.INTRA_ENABLED = (self.GetParameter("intra_enable") or "1") != "0"
        self.PLATEAU_METHOD = (self.GetParameter("plateau_method") or "iv").lower()  # "iv" or "vega"

        # HITL (live only)
        self.HITL_ENABLED = (self.GetParameter("hitl_enable") or "1") != "0"
        self.HITL_APPROVE_PARAM = (self.GetParameter("hitl_approve") or "0")
        self.HITL_USE_OBJECTSTORE = (self.GetParameter("hitl_use_objectstore") or "1") != "0"
        self.HITL_APPROVE_KEY = (self.GetParameter("hitl_approve_key") or "hitl_approve")
        self.HITL_APPROVE_ON_CRISIS_ONLY = (self.GetParameter("hitl_crisis_only") or "0") != "0"

        # ===== Trade batching / micro-trade suppression =====
        self.OPT_MIN_CONTRACTS = int(self.GetParameter("opt_min_contracts") or "5")
        self.TAIL_MIN_SELL_CONTRACTS = int(self.GetParameter("tail_min_sell_contracts") or "5")

        self.REHEDGE_MIN_CASH = float(self.GetParameter("rehedge_min_cash") or "25000")
        self.REHEDGE_MIN_CASH_PCT_TPV = float(self.GetParameter("rehedge_min_cash_pct_tpv") or "0.005")
        self.REHEDGE_MIN_QTY = int(self.GetParameter("rehedge_min_qty") or "5")

        self.TAIL_EST_MAX_ORDERS_PER_DAY = int(self.GetParameter("tail_est_max_orders_per_day") or "1")

        self.KICKER_REQUIRE_CRISIS_OR_IMMINENT = (self.GetParameter("kicker_require_crisis_or_imminent") or "1") != "0"
        self.KICKER_COOLDOWN_DAYS = int(self.GetParameter("kicker_cooldown_days") or "30")

        # Execution safety (tuned defaults)
        self.EXEC_MAX_CONTRACTS_PER_ORDER = int(self.GetParameter("exec_max_contracts_per_order") or "50")
        self.EXEC_MIN_MID = float(self.GetParameter("exec_min_mid") or "0.05")
        self.EXEC_MAX_SPREAD_PCT = float(self.GetParameter("exec_max_spread_pct") or "0.35")
        self.EXEC_LIMIT_BAND_PCT = float(self.GetParameter("exec_limit_band_pct") or "0.22")  # was 0.15
        self.EXEC_RETRY_MINUTES = int(self.GetParameter("exec_retry_minutes") or "5")
        self.EXEC_CANCEL_STALE_MINUTES = int(self.GetParameter("exec_cancel_stale_minutes") or "10")  # was 15

        # Core
        self.CORE_WEIGHT = float(self.GetParameter("core_weight") or "0.98")
        self.REBALANCE_DRIFT = float(self.GetParameter("rebalance_drift") or "0.005")
        self.CORE_DAILY_NOTIONAL_CAP_PCT = float(self.GetParameter("core_daily_cap_pct") or "1.00")
        self._core_notional_used_today = 0.0
        self._core_notional_day = None

        # Tail (IWM)
        self.TAIL_OTM = float(self.GetParameter("tail_otm") or "0.85")
        self.TAIL_DTE_TARGET = int(self.GetParameter("tail_dte") or "90")
        self.TAIL_ROLL_DTE = int(self.GetParameter("tail_roll_dte") or "60")
        self.TAIL_OTM_MIN = float(self.GetParameter("tail_otm_min") or "0.70")
        self.TAIL_OTM_MAX = float(self.GetParameter("tail_otm_max") or "0.95")
        self.MAX_HEDGE_PCT = float(self.GetParameter("max_hedge_pct") or "0.05")
        self.TAIL_MIN_QTY_FRAC = float(self.GetParameter("tail_min_qty_frac") or "0.50")
        self.MAX_TAIL_QTY_MULT = float(self.GetParameter("max_tail_qty_mult") or "1.75")
        self.TAIL_BUDGET_MULT = float(self.GetParameter("tail_budget_mult") or "0.85")
        self.TAIL_USE_IWM_IVP = (self.GetParameter("tail_use_iwm_ivp") or "1") != "0"
        self.TAIL_IVP_BUY_MAX = float(self.GetParameter("tail_ivp_buy_max") or "0.65")
        self.TAIL_IVP_MONETIZE_MIN = float(self.GetParameter("tail_ivp_monetize_min") or "0.70")

        # IV proxy (SPX)
        self.IV_LOOKBACK = int(self.GetParameter("iv_lookback") or "252")
        self.HEDGE_LOW_IV_PCT = float(self.GetParameter("hedge_low_iv_pct") or "0.40")
        self.HEDGE_MID_IV_PCT = float(self.GetParameter("hedge_mid_iv_pct") or "0.70")
        self.HEDGE_PCT_LOW = float(self.GetParameter("hedge_pct_low") or "0.004")
        self.HEDGE_PCT_MID = float(self.GetParameter("hedge_pct_mid") or "0.008")
        self.HEDGE_PCT_HIGH = float(self.GetParameter("hedge_pct_high") or "0.012")

        # Crisis gate
        self.IV_CRISIS_ENTER = float(self.GetParameter("iv_crisis_enter") or "0.92")
        self.IV_CRISIS_EXIT = float(self.GetParameter("iv_crisis_exit") or "0.75")
        self.CRISIS_EXIT_DAYS = int(self.GetParameter("crisis_exit_days") or "3")
        self.CRISIS_MIN_IVSLOPE_3D = float(self.GetParameter("crisis_min_iv_slope_3d") or "0.01")
        self.CRISIS_MIN_DD_5D = float(self.GetParameter("crisis_min_dd_5d") or "0.03")
        self.POST_CRISIS_COOLDOWN_DAYS = int(self.GetParameter("post_crisis_cooldown") or "7")

        # Ladder reset
        self.LADDER_RESET_ON_NEW_LOW = (self.GetParameter("ladder_reset_on_new_low") or "1") != "0"
        self.CRISIS_NEW_LOW_RESET_EPS = float(self.GetParameter("crisis_new_low_reset_eps") or "0.01")

        # Imminent crisis
        self.IMMINENT_CRISIS_ENABLED = (self.GetParameter("imminent_crisis_enable") or "1") != "0"
        self.IMMINENT_IVP = float(self.GetParameter("imminent_ivp") or "0.90")
        self.IMMINENT_DD5 = float(self.GetParameter("imminent_dd5") or "0.035")
        self.IMMINENT_IVSLOPE3D = float(self.GetParameter("imminent_ivslope3d") or "0.010")

        # Shocks
        self.SHOCK_SPY_DOWN = float(self.GetParameter("shock_spy_down") or "0.0125")
        self.SHOCK_TAIL_JUMP = float(self.GetParameter("shock_tail_jump") or "0.22")
        self.SHOCK_MULT_MIN = float(self.GetParameter("shock_mult_min") or "1.15")
        self.SHOCK_IV_MAX = float(self.GetParameter("shock_iv_max") or "0.85")
        self.GAP_SHOCK_SPY_DOWN = float(self.GetParameter("gap_shock_spy_down") or "0.010")
        self.GAP_SHOCK_TAIL_JUMP = float(self.GetParameter("gap_shock_tail_jump") or "0.16")
        self.REQUIRE_IWM_DOWN_FOR_SHOCKS = (self.GetParameter("require_iwm_down_for_shocks") or "1") != "0"
        self.SHOCK_IWM_DOWN = float(self.GetParameter("shock_iwm_down") or "0.015")
        self.GAP_SHOCK_IWM_DOWN = float(self.GetParameter("gap_shock_iwm_down") or "0.012")

        # Intraday pulse (30m)
        self.INTRA_SPY_DOWN_FROM_PEAK = float(self.GetParameter("intra_spy_down") or "0.012")
        self.INTRA_TAIL_UP_FROM_OPEN = float(self.GetParameter("intra_tail_up") or "0.15")
        self.INTRA_WINDOW_MIN = int(self.GetParameter("intra_window_min") or "20")
        self.INTRA_WINDOW_MAX = int(self.GetParameter("intra_window_max") or "180")
        self.INTRA_ONCE_PER_DAY = (self.GetParameter("intra_once_per_day") or "1") != "0"
        self.INTRA_REQUIRE_IWM_DOWN = (self.GetParameter("intra_require_iwm_down") or "1") != "0"
        self.INTRA_IWM_DOWN_FROM_PEAK = float(self.GetParameter("intra_iwm_down") or "0.016")

        # Crisis shock rules
        self.CRISIS_SHOCK_ENABLED = (self.GetParameter("crisis_shock_enable") or "1") != "0"
        self.CRISIS_SHOCK_MAX_PER_CRISIS = int(self.GetParameter("crisis_shock_max_per_crisis") or "2")
        self.CRISIS_SHOCK_SELL_FRAC_1 = float(self.GetParameter("crisis_shock_sell_frac_1") or "0.12")
        self.CRISIS_SHOCK_SELL_FRAC_2 = float(self.GetParameter("crisis_shock_sell_frac_2") or "0.08")
        self.CRISIS_SHOCK_MINMULT_1 = float(self.GetParameter("crisis_shock_minmult_1") or "1.20")
        self.CRISIS_SHOCK_MINMULT_STEP = float(self.GetParameter("crisis_shock_minmult_step") or "0.35")
        self.CRISIS_SHOCK_BOUNCE_MIN = float(self.GetParameter("crisis_shock_bounce_min") or "0.010")
        self.CRISIS_SHOCK_SKIP_ENTRY_DAY = (self.GetParameter("crisis_shock_skip_entry_day") or "1") != "0"
        self.CRISIS_SHOCK_RELIEF_GATE_FOR_CLOSE_GAP = (self.GetParameter("crisis_relief_gate_close_gap") or "1") != "0"

        # Plateau monetize (crisis only)
        self.IV_TIER1 = float(self.GetParameter("iv_tier1") or "0.95")
        self.MONETIZE_COOLDOWN_DAYS = int(self.GetParameter("monetize_cooldown") or "2")
        self.SHOCK_TIER_LOCKOUT_DAYS = int(self.GetParameter("shock_tier_lockout") or "3")
        self.TAIL_MULT_PLATEAU = float(self.GetParameter("tail_mult_plateau") or "1.6")
        self.DELTA_BAND_LOW = float(self.GetParameter("delta_band_low") or "0.10")
        self.DELTA_BAND_MID = float(self.GetParameter("delta_band_mid") or "0.25")
        self.PLATEAU_SLOPE_MAX = float(self.GetParameter("plateau_slope") or "0.03")
        self.PLATEAU_REQUIRE_1D_NONPOS = (self.GetParameter("plateau_require_1d_nonpos") or "1") != "0"
        self.TAIL_VEGA_WINDOW = int(self.GetParameter("tail_vega_window") or "4")
        self.TAIL_VEGA_PLATEAU_EPS = float(self.GetParameter("tail_vega_plateau_eps") or "0.05")

        # Re-hedge
        self.REHEDGE_COOLDOWN_DAYS = int(self.GetParameter("rehedge_cooldown") or "10")
        self.REHEDGE_MIN_SHORTFALL_FRAC = float(self.GetParameter("rehedge_shortfall_frac") or "0.50")
        self.REHEDGE_IV_MAX = float(self.GetParameter("rehedge_iv_max") or "0.90")
        self.CRISIS_CONT_REHEDGE = (self.GetParameter("crisis_cont_rehedge") or "1") != "0"
        self.CRISIS_REHEDGE_COOLDOWN_DAYS = int(self.GetParameter("crisis_rehedge_cooldown") or "4")
        self.CRISIS_REHEDGE_MIN_SHORTFALL_FRAC = float(self.GetParameter("crisis_rehedge_shortfall_frac") or "0.65")

        # Kicker (SPX puts)
        self.KICKER_OTM = float(self.GetParameter("kicker_otm") or "0.82")
        self.KICKER_DTE_MIN = int(self.GetParameter("kicker_dte_min") or "60")
        self.KICKER_DTE_MAX = int(self.GetParameter("kicker_dte_max") or "90")
        self.KICKER_BUDGET_PCT = float(self.GetParameter("kicker_budget") or "0.003")

        # ===== QC init =====
        self.SetStartDate(2018, 1, 1)
        self.SetEndDate(2025, 12, 31)
        self.SetCash(1000000)

        self.spy = self.AddEquity("SPY", Resolution.Minute).Symbol
        self.iwm = self.AddEquity("IWM", Resolution.Minute).Symbol
        self.SetBenchmark(self.spy)

        self.spx = self.AddIndex("SPX", Resolution.Minute).Symbol

        # CPU-safe option universes
        spxopt = self.AddIndexOption("SPX", Resolution.Minute)
        # spxopt.SetFilter(lambda u: u.PutsOnly().Expiration(25, 75).Strikes(-260, -25))
        spxopt.SetFilter(lambda u: u.PutsOnly().Expiration(25, 75).Strikes(-150, -25))
        self.spx_opt_symbol = spxopt.Symbol

        iwmopt = self.AddOption("IWM", Resolution.Minute)
        # iwmopt.SetFilter(lambda u: u.PutsOnly().Expiration(50, 130).Strikes(-28, -5))
        iwmopt.SetFilter(lambda u: u.PutsOnly().Expiration(50, 80).Strikes(-20, -5))
        self.iwm_opt_symbol = iwmopt.Symbol

        self.spy_ema50 = self.EMA(self.spy, 50, Resolution.Daily)
        self.spy_ema21 = self.EMA(self.spy, 21, Resolution.Daily)

        # ===== State =====
        self.last_spx_chain = None
        self.last_iwm_chain = None
        self.last_spx_price = None
        self.last_iwm_price = None

        self.tail_contract = None
        self.tail_entry_price = 0.0
        self.tail_base_qty = None

        self.kicker_contract = None
        self.kicker_deployed_this_crisis = False
        self._kicker_last_exit_day = None  # cooldown anchor

        self.hedge_cash = 0.0

        self.iv_history = deque(maxlen=self.IV_LOOKBACK)
        self.iv_daily = deque(maxlen=10)
        self.iwm_iv_history = deque(maxlen=self.IV_LOOKBACK)
        self.iwm_iv_daily = deque(maxlen=10)

        # daily IVP caching
        self._ivp_cache_day = None
        self._ivp_cache = None
        self._iwm_ivp_cache_day = None
        self._iwm_ivp_cache = None

        self.in_crisis = False
        self.crisis_entry_date = None
        self.crisis_shock_count = 0
        self.last_crisis_shock_day = None
        self.crisis_low_close = None

        self.consecutive_exit_days = 0
        self.consecutive_trend_days = 0
        self.post_crisis_until = None
        self.spy_5d_high = None
        self.last_dd5 = 0.0
        self.last_below_ema50 = False

        self.armed = False
        self.last_monetize = datetime.min
        self.last_shock_monetize = datetime.min

        self.spy_close_today = None
        self.spy_close_yesterday = None
        self.iwm_close_today = None
        self.iwm_close_yesterday = None
        self.tail_close_today = None
        self.tail_close_yesterday = None

        self.tail_vega_daily = deque(maxlen=8)
        self.tail_mid_daily = deque(maxlen=8)

        self.spy_open = None
        self.iwm_open = None
        self.tail_open = None
        self.spy_session_high = None
        self.spy_session_low = None
        self.iwm_session_high = None
        self.iwm_session_low = None
        self.last_intra_day = None

        self.last_rehedge = datetime.min

        self.pending_actions = deque(maxlen=200)
        self.last_exec_attempt = {}
        self.open_ticket_meta = {}

        self.state_rebuilt = False
        self.core_bootstrapped = False

        # --- LIVE HARDENER (3): live-only early tail seed window ---
        if self.LiveMode:
            self._tail_force_until = self.Time + timedelta(days=2)
        else:
            self._tail_force_until = self.StartDate + timedelta(days=3)

        self._slack_seen = set()
        self._slack_seen_day = None
        self._prev_in_crisis = None

        # tail establish throttling
        self._tail_est_day = None
        self._tail_est_count_today = 0

        # ===== Schedules =====
        self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.AfterMarketOpen(self.spy, 5), self.CaptureOpen)
        self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.AfterMarketOpen(self.spy, 7), self.RebuildStateFromPortfolio)
        self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.AfterMarketOpen(self.spy, 30), self.DailyCheck)

        self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.At(15, 55), self.UpdateIVProxyDaily)
        self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.At(15, 55), self.UpdateIwmIVProxyDaily)
        self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.At(15, 55), self.CaptureCloses)

        if self.ENABLE_SHOCKS:
            self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.At(15, 56), self.ShockCheckAfterClose)
            self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.AfterMarketOpen(self.spy, 5), self.ShockCheckAfterOpen)

        if self.ENABLE_SHOCKS and self.INTRA_ENABLED:
            self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.Every(timedelta(minutes=30)), self.IntradayShockPulse)

        self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.At(15, 58), self._SendEndOfDayReport)

        # --- LIVE HARDENER (1): guarantee at least one DailyCheck on start day ---
        if self.LiveMode:
            self.Schedule.On(self.DateRules.Today, self.TimeRules.AfterMarketOpen(self.spy, 35), self.DailyCheck)
        self.Debug(f"INIT END | Live={self.LiveMode} | Time={self.Time}")
    # ===== utils =====
    def D(self, msg):
        if self.DEBUG:
            self.Debug(str(msg))

    def _Slack(self, msg):
        if not self.SLACK_ENABLED:
            return
        try:
            hook = (self.GetParameter("slack_webhook") or "").strip()
            if hook:
                self.Notify.Slack(hook, msg)
        except:
            pass

    def _FmtSymbol(self, sym):
        try:
            if sym is None:
                return "?"
            return sym.Value if isinstance(sym, Symbol) else str(sym)
        except:
            return "?"

    def _ResetSlackDedupeIfNewDay(self):
        d = self.Time.date()
        if self._slack_seen_day != d:
            self._slack_seen_day = d
            self._slack_seen.clear()

    def _ActionToText(self, a):
        t = a.get("type")
        tag = (a.get("tag") or "").strip()
        if t == "order":
            sym = a.get("symbol")
            qty = int(a.get("qty") or 0)
            limit = a.get("limit", None)
            side = "BUY" if qty > 0 else "SELL"
            px = ("%.2f" % float(limit)) if limit is not None else "MKT"
            return "%s %d %s @ %s tag=%s" % (side, abs(qty), self._FmtSymbol(sym), px, tag)
        if t == "setholdings":
            sym = a.get("symbol")
            w = float(a.get("weight") or 0)
            return "SetHoldings %s -> %.1f%% tag=%s" % (self._FmtSymbol(sym), 100.0 * w, tag)
        if t == "liquidate":
            sym = a.get("symbol")
            return "Liquidate %s tag=%s" % (self._FmtSymbol(sym), tag)
        return "%s tag=%s" % (str(t), tag)

    # ===== OnData caches =====
    def OnData(self, data):
        if self.spx_opt_symbol in data.OptionChains:
            self.last_spx_chain = data.OptionChains[self.spx_opt_symbol]
        if self.iwm_opt_symbol in data.OptionChains:
            self.last_iwm_chain = data.OptionChains[self.iwm_opt_symbol]
        if self.spx in self.Securities:
            self.last_spx_price = self.Securities[self.spx].Price
        if self.iwm in self.Securities:
            self.last_iwm_price = self.Securities[self.iwm].Price

    # ===== HITL =====
    def _HitlApproved(self):
        if not self.LiveMode:
            return True
        if self.HITL_APPROVE_ON_CRISIS_ONLY and not self.in_crisis:
            return True
        if not self.HITL_ENABLED:
            return True
        if (self.HITL_APPROVE_PARAM or "0") == "1":
            return True
        if self.HITL_USE_OBJECTSTORE:
            try:
                if self.ObjectStore.ContainsKey(self.HITL_APPROVE_KEY):
                    v = self.ObjectStore.Read(self.HITL_APPROVE_KEY)
                    if str(v).strip() == "1":
                        return True
            except:
                pass
        return False

    def _MaybeSlackTradeInitiated(self, action, staged):
        if not self.SLACK_TRADE_INTENTS:
            return
        self._ResetSlackDedupeIfNewDay()
        txt = self._ActionToText(action)
        if not txt:
            return
        key = "%s|%s|%s" % (self.Time.strftime("%Y-%m-%d"), ("STG" if staged else "SUB"), txt)
        if key in self._slack_seen:
            return
        self._slack_seen.add(key)
        prefix = "TRADE STAGED" if staged else "TRADE INITIATED"
        self._Slack("%s\n%s\n_time_: %s" % (prefix, txt, self.Time.strftime("%Y-%m-%d %H:%M")))

    def _StageOrExecute(self, action):
        if self._HitlApproved():
            ok = self._ExecuteAction(action)
            if ok and action.get("type") in ["order", "setholdings", "liquidate"]:
                self._MaybeSlackTradeInitiated(action, False)
            return ok
        self.pending_actions.append(action)
        self._MaybeSlackTradeInitiated(action, True)
        return False

    def _ExecuteAction(self, action):
        t = action.get("type")
        sym = action.get("symbol")
        qty = action.get("qty")
        limit = action.get("limit")
        tag = action.get("tag", "")

        if t == "liquidate":
            if sym is None:
                return False
            self.Liquidate(sym, tag=tag)
            return True

        if t == "setholdings":
            w = action.get("weight", None)
            if w is None:
                return False
            self.SetHoldings(sym, w, tag=tag)
            return True

        if t == "order":
            if sym is None or qty is None or qty == 0:
                return False
            ticket = self.LimitOrder(sym, qty, limit, tag=tag) if limit is not None else self.MarketOrder(sym, qty, tag=tag)
            if ticket is not None:
                self.open_ticket_meta[ticket.OrderId] = {"t": self.Time, "sym": sym, "tag": tag}
            return True

        return False

    def _ProcessPendingActions(self):
        if not self.pending_actions or not self._HitlApproved():
            return
        n = len(self.pending_actions)
        for _ in range(n):
            a = self.pending_actions.popleft()
            ok = self._ExecuteAction(a)
            if ok and a.get("type") in ["order", "setholdings", "liquidate"]:
                self._MaybeSlackTradeInitiated(a, False)

    # ===== Execution safety for options =====
    def _OptionMidBidAsk(self, symbol):
        sec = self.Securities[symbol]
        bid, ask = sec.BidPrice, sec.AskPrice
        if bid is None or ask is None or bid <= 0 or ask <= 0:
            return (0.0, 0.0, 0.0)
        return (bid, ask, (bid + ask) / 2.0)

    def _PassSpreadAndMid(self, symbol):
        bid, ask, mid = self._OptionMidBidAsk(symbol)
        if mid <= 0 or mid < self.EXEC_MIN_MID:
            return False
        spr = ask - bid
        if spr <= 0:
            return True
        return (spr / max(mid, 1e-9)) <= self.EXEC_MAX_SPREAD_PCT

    def _ChunkQty(self, qty):
        if qty == 0:
            return []
        sign = 1 if qty > 0 else -1
        q = abs(int(qty))
        mx = max(1, int(self.EXEC_MAX_CONTRACTS_PER_ORDER))
        out = []
        while q > 0:
            take = min(mx, q)
            out.append(sign * take)
            q -= take
        return out

    def SafeOptionOrder(self, symbol, qty, tag):
        if qty == 0 or abs(int(qty)) < int(self.OPT_MIN_CONTRACTS):
            self.D(f"SafeOptionOrder {tag}: qty {qty} below min")
            return False
        if not self._PassSpreadAndMid(symbol):
            self.D(f"SafeOptionOrder {tag}: failed spread/mid check for {self._FmtSymbol(symbol)}")
            return False

        bid, ask, mid = self._OptionMidBidAsk(symbol)
        if mid <= 0:
            return False

        band = max(0.01, self.EXEC_LIMIT_BAND_PCT * mid)
        limit = min(ask, mid + band) if qty > 0 else max(bid, mid - band)

        key = "%s:%d:%s" % (symbol.Value, (1 if qty > 0 else -1), tag)
        last = self.last_exec_attempt.get(key, datetime.min)
        if (self.Time - last).total_seconds() < self.EXEC_RETRY_MINUTES * 60:
            return False
        self.last_exec_attempt[key] = self.Time

        for q in self._ChunkQty(qty):
            self._StageOrExecute({"type": "order", "symbol": symbol, "qty": q, "limit": float(limit), "tag": tag})
        return True

    def SafeLiquidate(self, symbol, tag):
        return self._StageOrExecute({"type": "liquidate", "symbol": symbol, "tag": tag})

    def OnOrderEvent(self, orderEvent):
        try:
            if orderEvent.Status in [OrderStatus.Filled, OrderStatus.Canceled, OrderStatus.Invalid]:
                oid = orderEvent.OrderId
                if oid in self.open_ticket_meta:
                    del self.open_ticket_meta[oid]
        except:
            pass

    def _CancelStaleOpenOrders(self):
        if not self.open_ticket_meta:
            return
        cutoff = timedelta(minutes=self.EXEC_CANCEL_STALE_MINUTES)
        for oid, meta in list(self.open_ticket_meta.items()):
            if (self.Time - meta.get("t", self.Time)) > cutoff:
                self.Transactions.CancelOrder(oid, "stale")
                if oid in self.open_ticket_meta:
                    del self.open_ticket_meta[oid]

    # ===== Restart rebind (live/paper robustness) =====
    def RebuildStateFromPortfolio(self):
        if self.state_rebuilt:
            return
        try:
            tail = None
            kicker = None
            for kv in self.Portfolio:
                sym, h = kv.Key, kv.Value
                if not h.Invested or sym.SecurityType != SecurityType.Option:
                    continue
                if sym.Underlying == self.iwm and sym.ID.OptionRight == OptionRight.Put:
                    tail = sym
                if sym.Underlying == self.spx and sym.ID.OptionRight == OptionRight.Put:
                    kicker = sym

            if tail is not None:
                self.tail_contract = tail
                avg = float(self.Portfolio[tail].AveragePrice)
                if avg > 0:
                    self.tail_entry_price = avg
                if self.tail_base_qty is None:
                    self.tail_base_qty = int(abs(self.Portfolio[tail].Quantity))
                self._InitTailCloseTrackers()

            if kicker is not None:
                self.kicker_contract = kicker
                self.kicker_deployed_this_crisis = True
        except Exception as e:
            self.D("RebuildStateFromPortfolio err: " + str(e))
        self.state_rebuilt = True

    def _InitTailCloseTrackers(self):
        if not self.tail_contract or self.tail_contract not in self.Securities:
            return
        sec = self.Securities[self.tail_contract]
        mid = (sec.BidPrice + sec.AskPrice) / 2.0
        if mid and mid > 0:
            self.tail_close_today = float(mid)
            self.tail_close_yesterday = float(mid)
            self.tail_mid_daily.clear()
            self.tail_mid_daily.append(float(mid))
            self.tail_vega_daily.clear()

    # ===== Single-pass selectors =====
    def _BestProxyPut(self, chain, spot, dte_min, dte_max, m_lo, m_hi, m_pref=0.92):
        if not chain or not spot or spot <= 0:
            return None
        best, best_score = None, 1e99
        for c in chain:
            if c.Right != OptionRight.Put:
                continue
            dte = (c.Expiry - self.Time).days
            if dte < dte_min or dte > dte_max:
                continue
            iv = float(c.ImpliedVolatility or 0)
            if iv <= 0:
                continue
            m = float(c.Strike) / float(spot)
            score = abs(m - m_pref) + (0.0 if (m_lo <= m <= m_hi) else 0.25)
            if score < best_score:
                best_score, best = score, c
        return best

    def _BestTailPut(self, chain, spot, dte_target, dte_band, otm_min, otm_max, strike_target):
        if not chain or not spot or spot <= 0:
            return None
        best, best_score = None, 1e99
        for c in chain:
            if c.Right != OptionRight.Put:
                continue
            dte = (c.Expiry - self.Time).days
            if abs(dte - int(dte_target)) > int(dte_band):
                continue
            m = float(c.Strike) / float(spot)
            if m < otm_min or m > otm_max:
                continue
            if (float(c.BidPrice or 0) + float(c.AskPrice or 0)) <= 0:
                continue
            score = abs(float(c.Strike) - float(strike_target)) + 0.02 * abs(dte - int(dte_target))
            if score < best_score:
                best_score, best = score, c
        return best

    # ===== IV proxies =====
    def UpdateIVProxyDaily(self):
        if not self.last_spx_chain:
            return
        spot = self.last_spx_price
        proxy = self._BestProxyPut(self.last_spx_chain, spot, 30, 45, 0.90, 0.95, 0.92)
        if proxy is None:
            return
        iv = float(proxy.ImpliedVolatility or 0)
        if iv > 0:
            self.iv_history.append(iv)
            self.iv_daily.append(iv)
            self._ivp_cache_day, self._ivp_cache = None, None

    def UpdateIwmIVProxyDaily(self):
        if not self.last_iwm_chain:
            return
        spot = self.last_iwm_price
        proxy = self._BestProxyPut(self.last_iwm_chain, spot, 30, 45, 0.90, 0.95, 0.92)
        if proxy is None:
            return
        iv = float(proxy.ImpliedVolatility or 0)
        if iv > 0:
            self.iwm_iv_history.append(iv)
            self.iwm_iv_daily.append(iv)
            self._iwm_ivp_cache_day, self._iwm_ivp_cache = None, None

    def IVPercentile(self):
        d = self.Time.date()
        if self._ivp_cache_day == d:
            return self._ivp_cache
        if len(self.iv_history) < 60:
            self._ivp_cache_day, self._ivp_cache = d, None
            return None
        iv = float(self.iv_history[-1])
        pct = float(sum(x <= iv for x in self.iv_history)) / float(len(self.iv_history))
        self._ivp_cache_day, self._ivp_cache = d, pct
        return pct

    def IwmIVPercentile(self):
        d = self.Time.date()
        if self._iwm_ivp_cache_day == d:
            return self._iwm_ivp_cache
        if len(self.iwm_iv_history) < 60:
            self._iwm_ivp_cache_day, self._iwm_ivp_cache = d, None
            return None
        iv = float(self.iwm_iv_history[-1])
        pct = float(sum(x <= iv for x in self.iwm_iv_history)) / float(len(self.iwm_iv_history))
        self._iwm_ivp_cache_day, self._iwm_ivp_cache = d, pct
        return pct

    def IVSlope3d(self):
        if len(self.iv_daily) < 4:
            return 0.0
        return float(self.iv_daily[-1] - self.iv_daily[-4])

    def IVSlope1d(self):
        if len(self.iv_daily) < 2:
            return 0.0
        return float(self.iv_daily[-1] - self.iv_daily[-2])

    def IVSlopeNorm3d(self):
        if len(self.iv_daily) < 4:
            return 0.0
        iv_now = max(float(self.iv_daily[-1]), 1e-6)
        return float(self.iv_daily[-1] - self.iv_daily[-4]) / iv_now

    def IsIVPlateau(self):
        if abs(self.IVSlopeNorm3d()) > self.PLATEAU_SLOPE_MAX:
            return False
        return (self.IVSlope1d() <= 0) if self.PLATEAU_REQUIRE_1D_NONPOS else True

    def TailIVPercentile(self):
        if self.TAIL_USE_IWM_IVP:
            x = self.IwmIVPercentile()
            if x is not None:
                return x
        return self.IVPercentile()

    # ===== Open/close tracking =====
    def CaptureOpen(self):
        spy_px = self.Securities[self.spy].Price
        iwm_px = self.Securities[self.iwm].Price
        self.spy_open = spy_px
        self.iwm_open = iwm_px
        self.spy_session_high = spy_px
        self.spy_session_low = spy_px
        self.iwm_session_high = iwm_px
        self.iwm_session_low = iwm_px
        if self.tail_contract and self.tail_contract in self.Securities:
            sec = self.Securities[self.tail_contract]
            mid = (sec.BidPrice + sec.AskPrice) / 2.0
            self.tail_open = float(mid) if mid and mid > 0 else None
        else:
            self.tail_open = None

    def CaptureCloses(self):
        self.spy_close_yesterday = self.spy_close_today
        self.iwm_close_yesterday = self.iwm_close_today
        self.tail_close_yesterday = self.tail_close_today

        self.spy_close_today = self.Securities[self.spy].Price
        self.iwm_close_today = self.Securities[self.iwm].Price

        if self.in_crisis and self.spy_close_today and self.spy_close_today > 0:
            if self.crisis_low_close is None:
                self.crisis_low_close = self.spy_close_today
            elif self.LADDER_RESET_ON_NEW_LOW:
                if self.spy_close_today < self.crisis_low_close * (1.0 - self.CRISIS_NEW_LOW_RESET_EPS):
                    self.crisis_low_close = self.spy_close_today
                    self.crisis_shock_count = 0
                    self.last_crisis_shock_day = None
                    self.armed = False

        if self.tail_contract and self.tail_contract in self.Securities:
            sec = self.Securities[self.tail_contract]
            mid = (sec.BidPrice + sec.AskPrice) / 2.0
            if mid and mid > 0:
                self.tail_close_today = float(mid)
                self.tail_mid_daily.append(float(mid))
            if self.PLATEAU_METHOD == "vega":
                try:
                    if sec.Greeks and sec.Greeks.Vega is not None:
                        self.tail_vega_daily.append(float(sec.Greeks.Vega))
                except:
                    pass

    # ===== Tail stats =====
    def TailMid(self):
        if not self.tail_contract or self.tail_contract not in self.Securities:
            return 0.0
        sec = self.Securities[self.tail_contract]
        mid = (sec.BidPrice + sec.AskPrice) / 2.0
        return float(mid) if mid and mid > 0 else 0.0

    def TailMultiple(self):
        if not self.tail_contract or self.tail_entry_price <= 0:
            return 0.0
        mid = self.TailMid()
        return (mid / float(self.tail_entry_price)) if mid > 0 else 0.0

    def TailDelta(self):
        if not self.tail_contract or self.tail_contract not in self.Securities:
            return 0.0
        sec = self.Securities[self.tail_contract]
        try:
            d = sec.Greeks.Delta if sec.Greeks else None
            return abs(float(d)) if d is not None else 0.0
        except:
            return 0.0

    def HedgeTargetPct(self, iv_pct):
        if iv_pct is None:
            return self.HEDGE_PCT_MID
        if iv_pct < self.HEDGE_LOW_IV_PCT:
            return self.HEDGE_PCT_LOW
        if iv_pct < self.HEDGE_MID_IV_PCT:
            return self.HEDGE_PCT_MID
        return self.HEDGE_PCT_HIGH

    def IsTailVegaPlateau(self):
        if len(self.tail_vega_daily) < max(2, self.TAIL_VEGA_WINDOW):
            return False
        w = min(self.TAIL_VEGA_WINDOW, len(self.tail_vega_daily))
        v_now = float(self.tail_vega_daily[-1])
        v_old = float(self.tail_vega_daily[-w])
        denom = max(abs(v_old), 1e-9)
        rel = (v_now - v_old) / denom
        return abs(rel) <= self.TAIL_VEGA_PLATEAU_EPS

    # ===== Crisis helpers/state =====
    def _IsImminentCrisis(self, iv_pct):
        if not self.IMMINENT_CRISIS_ENABLED or iv_pct is None:
            return False
        return (iv_pct >= self.IMMINENT_IVP and self.last_below_ema50 and self.IVSlope3d() >= self.IMMINENT_IVSLOPE3D and self.last_dd5 >= self.IMMINENT_DD5)

    def _ShouldUseCrisisShockRules(self, iv_pct):
        return self.CRISIS_SHOCK_ENABLED and (self.in_crisis or self._IsImminentCrisis(iv_pct))

    def _CrisisShockGateOpen(self):
        spy_price = self.Securities[self.spy].Price
        if self.spy_ema21.IsReady and spy_price > self.spy_ema21.Current.Value:
            return True
        if self.spy_session_low and self.spy_session_low > 0:
            bounce = (spy_price - self.spy_session_low) / self.spy_session_low
            if bounce >= self.CRISIS_SHOCK_BOUNCE_MIN:
                return True
        return False

    def _CrisisShockMinMult(self):
        return self.CRISIS_SHOCK_MINMULT_1 + self.crisis_shock_count * self.CRISIS_SHOCK_MINMULT_STEP

    def _CrisisShockSellFrac(self):
        return self.CRISIS_SHOCK_SELL_FRAC_1 if self.crisis_shock_count <= 0 else self.CRISIS_SHOCK_SELL_FRAC_2

    def UpdateCrisisState(self, iv_pct):
        spy_price = self.Securities[self.spy].Price
        spy_below_ema50 = self.spy_ema50.IsReady and spy_price < self.spy_ema50.Current.Value
        spy_above_ema21 = self.spy_ema21.IsReady and spy_price > self.spy_ema21.Current.Value
        iv_slope_3d = self.IVSlope3d()

        if self.spy_5d_high is None:
            self.spy_5d_high = spy_price
        self.spy_5d_high = max(self.spy_5d_high, spy_price)
        dd_5d = (self.spy_5d_high - spy_price) / max(self.spy_5d_high, 1e-9)

        self.last_dd5 = dd_5d
        self.last_below_ema50 = spy_below_ema50

        if (not self.in_crisis) and self.post_crisis_until is not None:
            if self.Time.date() <= self.post_crisis_until:
                return
            self.post_crisis_until = None

        if not self.in_crisis:
            enter = (iv_pct >= self.IV_CRISIS_ENTER and spy_below_ema50 and iv_slope_3d >= self.CRISIS_MIN_IVSLOPE_3D and dd_5d >= self.CRISIS_MIN_DD_5D)
            if enter:
                self.in_crisis = True
                self.consecutive_exit_days = 0
                self.consecutive_trend_days = 0
                self.spy_5d_high = spy_price
                self.kicker_deployed_this_crisis = False
                self.armed = False
                self.crisis_entry_date = self.Time.date()
                self.crisis_shock_count = 0
                self.last_crisis_shock_day = None
                self.crisis_low_close = self.spy_close_today if self.spy_close_today else spy_price
        else:
            if iv_pct <= self.IV_CRISIS_EXIT:
                self.consecutive_exit_days += 1
            else:
                self.consecutive_exit_days = 0

            if spy_above_ema21 and iv_slope_3d < 0:
                self.consecutive_trend_days += 1
            else:
                self.consecutive_trend_days = 0

            if self.consecutive_exit_days >= self.CRISIS_EXIT_DAYS or self.consecutive_trend_days >= self.CRISIS_EXIT_DAYS:
                self.in_crisis = False
                self.post_crisis_until = self.Time.date() + timedelta(days=self.POST_CRISIS_COOLDOWN_DAYS)
                if self.kicker_contract:
                    self.ExitKicker()
                self.consecutive_exit_days = 0
                self.consecutive_trend_days = 0
                self.spy_5d_high = self.Securities[self.spy].Price
                self.crisis_entry_date = None
                self.crisis_shock_count = 0
                self.last_crisis_shock_day = None
                self.crisis_low_close = None

    # ===== Tail establish/roll =====
    def _ResetTailEstCounterIfNewDay(self):
        d = self.Time.date()
        if self._tail_est_day != d:
            self._tail_est_day = d
            self._tail_est_count_today = 0

    def EstablishTail(self):
        self._ResetTailEstCounterIfNewDay()
        if self.TAIL_EST_MAX_ORDERS_PER_DAY > 0 and self._tail_est_count_today >= self.TAIL_EST_MAX_ORDERS_PER_DAY:
            self.D("EstablishTail: max orders per day reached")
            return

        if not self.last_iwm_chain or not self.last_iwm_price:
            self.D(f"EstablishTail: no chain data - chain={self.last_iwm_chain is not None}, price={self.last_iwm_price}")
            return

        macro_ivp = self.IVPercentile()
        imminent = self._IsImminentCrisis(macro_ivp)
        tail_ivp = None if self.Time <= self._tail_force_until else self.TailIVPercentile()

        if (not self.in_crisis) and (not imminent) and tail_ivp is not None and tail_ivp > self.TAIL_IVP_BUY_MAX:
            return

        spot = float(self.last_iwm_price)
        strike_target = spot * self.TAIL_OTM
        tail = self._BestTailPut(self.last_iwm_chain, spot, self.TAIL_DTE_TARGET, 10, self.TAIL_OTM_MIN, self.TAIL_OTM_MAX, strike_target)
        if tail is None:
            return

        price = (float(tail.BidPrice or 0) + float(tail.AskPrice or 0)) / 2.0
        if price <= 0:
            return

        iv_for_budget = macro_ivp if macro_ivp is not None else self.HEDGE_MID_IV_PCT
        target_pct = self.HedgeTargetPct(iv_for_budget)
        budget = min(target_pct * self.Portfolio.TotalPortfolioValue, self.MAX_HEDGE_PCT * self.Portfolio.TotalPortfolioValue)
        budget *= max(0.0, self.TAIL_BUDGET_MULT)

        qty = int(budget // (price * 100.0))
        if qty < int(self.OPT_MIN_CONTRACTS):
            self.D(f"EstablishTail: qty {qty} < min {self.OPT_MIN_CONTRACTS}, budget={budget:.2f}, price={price:.2f}")
            return

        if self.SafeOptionOrder(tail.Symbol, qty, tag="TAIL_EST"):
            self.tail_contract = tail.Symbol
            self.tail_entry_price = float(price)
            if self.tail_base_qty is None:
                self.tail_base_qty = int(qty)
            self._tail_est_count_today += 1

    def MaybeRollTail(self):
        if not self.tail_contract or self.tail_contract not in self.Securities:
            return
        try:
            dte = (self.Securities[self.tail_contract].Expiry - self.Time).days
        except:
            return
        if dte <= self.TAIL_ROLL_DTE:
            self.SafeLiquidate(self.tail_contract, tag="TAIL_ROLL_OUT")
            self.tail_contract = None
            self.tail_entry_price = 0.0
            self.tail_base_qty = None
            self.EstablishTail()

    def _CapSellQtyByTailFloor(self, desired_sell_qty):
        if not self.tail_contract or desired_sell_qty <= 0:
            return 0
        pos_qty = int(abs(self.Portfolio[self.tail_contract].Quantity))
        if pos_qty <= 0:
            return 0
        if self.tail_base_qty and self.tail_base_qty > 0:
            floor_qty = int(max(1, round(self.TAIL_MIN_QTY_FRAC * self.tail_base_qty)))
            remaining = pos_qty - desired_sell_qty
            if remaining < floor_qty:
                desired_sell_qty = max(0, pos_qty - floor_qty)

        desired_sell_qty = int(max(0, min(desired_sell_qty, pos_qty)))
        if desired_sell_qty > 0 and desired_sell_qty < int(self.TAIL_MIN_SELL_CONTRACTS):
            return 0
        return desired_sell_qty

    # ===== Shocks =====
    def ShockCheckAfterClose(self):
        if (not self.ENABLE_SHOCKS) or (not self.tail_contract):
            return
        macro_ivp = self.IVPercentile()
        if macro_ivp is None or macro_ivp >= self.SHOCK_IV_MAX:
            return
        if None in [self.spy_close_today, self.spy_close_yesterday, self.iwm_close_today, self.iwm_close_yesterday,
                    self.tail_close_today, self.tail_close_yesterday]:
            return
        if self.spy_close_yesterday <= 0 or self.iwm_close_yesterday <= 0 or self.tail_close_yesterday <= 0:
            return

        spy_ret = (self.spy_close_today - self.spy_close_yesterday) / self.spy_close_yesterday
        iwm_ret = (self.iwm_close_today - self.iwm_close_yesterday) / self.iwm_close_yesterday
        tail_jump = (self.tail_close_today - self.tail_close_yesterday) / self.tail_close_yesterday

        if spy_ret <= -self.SHOCK_SPY_DOWN and tail_jump >= self.SHOCK_TAIL_JUMP:
            if self.REQUIRE_IWM_DOWN_FOR_SHOCKS and iwm_ret > -self.SHOCK_IWM_DOWN:
                return
            self._MonetizeShock("close")

    def ShockCheckAfterOpen(self):
        if (not self.ENABLE_SHOCKS) or (not self.tail_contract):
            return
        if self.spy_close_yesterday is None or self.spy_close_yesterday <= 0:
            return
        if self.iwm_close_yesterday is None or self.iwm_close_yesterday <= 0:
            return
        if self.tail_close_yesterday is None or self.tail_close_yesterday <= 0:
            return

        macro_ivp = self.IVPercentile()
        if macro_ivp is None or macro_ivp >= self.SHOCK_IV_MAX:
            return

        spy_now = self.Securities[self.spy].Price
        iwm_now = self.Securities[self.iwm].Price
        if spy_now <= 0 or iwm_now <= 0:
            return

        spy_gap = (spy_now - self.spy_close_yesterday) / self.spy_close_yesterday
        iwm_gap = (iwm_now - self.iwm_close_yesterday) / self.iwm_close_yesterday

        tail_now = self.TailMid()
        if tail_now <= 0:
            return
        tail_gap = (tail_now - self.tail_close_yesterday) / self.tail_close_yesterday

        if spy_gap <= -self.GAP_SHOCK_SPY_DOWN and tail_gap >= self.GAP_SHOCK_TAIL_JUMP:
            if self.REQUIRE_IWM_DOWN_FOR_SHOCKS and iwm_gap > -self.GAP_SHOCK_IWM_DOWN:
                return
            self._MonetizeShock("gap")

    def IntradayShockPulse(self):
        if (not self.ENABLE_SHOCKS) or (not self.INTRA_ENABLED):
            return
        if (not self.tail_contract) or (self.spy_open is None) or (self.iwm_open is None):
            return

        today = self.Time.date()
        if self.INTRA_ONCE_PER_DAY and self.last_intra_day == today:
            return

        market_open = self.Time.replace(hour=9, minute=30, second=0, microsecond=0)
        mins = (self.Time - market_open).total_seconds() / 60.0
        if mins < self.INTRA_WINDOW_MIN or mins > self.INTRA_WINDOW_MAX:
            return

        spy_now = self.Securities[self.spy].Price
        iwm_now = self.Securities[self.iwm].Price

        self.spy_session_high = max(self.spy_session_high, spy_now) if self.spy_session_high else spy_now
        self.spy_session_low = min(self.spy_session_low, spy_now) if self.spy_session_low else spy_now
        self.iwm_session_high = max(self.iwm_session_high, iwm_now) if self.iwm_session_high else iwm_now
        self.iwm_session_low = min(self.iwm_session_low, iwm_now) if self.iwm_session_low else iwm_now

        drop_from_peak = (spy_now - self.spy_session_high) / self.spy_session_high if self.spy_session_high and self.spy_session_high > 0 else 0.0
        iwm_drop_from_peak = (iwm_now - self.iwm_session_high) / self.iwm_session_high if self.iwm_session_high and self.iwm_session_high > 0 else 0.0

        if self.tail_open is None or self.tail_open <= 0:
            return
        tail_now = self.TailMid()
        if tail_now <= 0:
            return
        tail_jump = (tail_now - self.tail_open) / self.tail_open

        if drop_from_peak <= -self.INTRA_SPY_DOWN_FROM_PEAK and tail_jump >= self.INTRA_TAIL_UP_FROM_OPEN:
            if self.INTRA_REQUIRE_IWM_DOWN and iwm_drop_from_peak > -self.INTRA_IWM_DOWN_FROM_PEAK:
                return
            self._MonetizeShock("intra")
            self.last_intra_day = today

    def _MonetizeShock(self, reason):
        if not self.tail_contract:
            return

        macro_ivp = self.IVPercentile()
        use_crisis_rules = self._ShouldUseCrisisShockRules(macro_ivp)

        tail_ivp = self.TailIVPercentile()
        if (not use_crisis_rules) and tail_ivp is not None and tail_ivp < self.TAIL_IVP_MONETIZE_MIN:
            return

        tail_mult = self.TailMultiple()
        if tail_mult < self.SHOCK_MULT_MIN:
            return

        today = self.Time.date()

        if use_crisis_rules:
            if self.CRISIS_SHOCK_SKIP_ENTRY_DAY and self.crisis_entry_date == today:
                return
            if self.in_crisis:
                if self.crisis_shock_count >= self.CRISIS_SHOCK_MAX_PER_CRISIS:
                    return
                if self.last_crisis_shock_day == today:
                    return
            if self.CRISIS_SHOCK_RELIEF_GATE_FOR_CLOSE_GAP and reason in ["close", "gap"]:
                if not self._CrisisShockGateOpen():
                    return
            if tail_mult < self._CrisisShockMinMult():
                return

            sell_frac = self._CrisisShockSellFrac()
            pos_qty = int(abs(self.Portfolio[self.tail_contract].Quantity))
            qty = self._CapSellQtyByTailFloor(int(pos_qty * sell_frac))
            if qty <= 0:
                return

            if self.SafeOptionOrder(self.tail_contract, -qty, tag="CSHK_%s" % str(reason)):
                mid = self.TailMid()
                if mid > 0:
                    self.hedge_cash += qty * mid * 100.0
                self.last_shock_monetize = self.Time
                if self.in_crisis:
                    self.crisis_shock_count += 1
                    self.last_crisis_shock_day = today
            return

        tail_delta = self.TailDelta()
        sell_frac = 0.35 if tail_delta < self.DELTA_BAND_LOW else (0.25 if tail_delta < self.DELTA_BAND_MID else 0.15)
        pos_qty = int(abs(self.Portfolio[self.tail_contract].Quantity))
        qty = self._CapSellQtyByTailFloor(int(pos_qty * sell_frac))
        if qty <= 0:
            return

        if self.SafeOptionOrder(self.tail_contract, -qty, tag="SHK_%s" % str(reason)):
            mid = self.TailMid()
            if mid > 0:
                self.hedge_cash += qty * mid * 100.0
            self.last_shock_monetize = self.Time

    # ===== Plateau monetize (crisis only) =====
    def MaybeCrisisPlateauMonetize(self, iv_pct):
        if (not self.tail_contract) or (not self.in_crisis):
            return
        if (self.Time.date() - self.last_monetize.date()).days < self.MONETIZE_COOLDOWN_DAYS:
            return
        if (self.Time.date() - self.last_shock_monetize.date()).days < self.SHOCK_TIER_LOCKOUT_DAYS:
            return

        if (not self.armed) and iv_pct >= self.IV_TIER1:
            self.armed = True
        if not self.armed:
            return

        tail_mult = self.TailMultiple()
        if tail_mult < self.TAIL_MULT_PLATEAU:
            return

        plateau = self.IsTailVegaPlateau() if self.PLATEAU_METHOD == "vega" else self.IsIVPlateau()
        if not plateau:
            return

        tail_delta = self.TailDelta()
        sell_frac = 0.50 if tail_delta < self.DELTA_BAND_LOW else (0.60 if tail_delta < self.DELTA_BAND_MID else 0.35)

        pos_qty = int(abs(self.Portfolio[self.tail_contract].Quantity))
        qty = self._CapSellQtyByTailFloor(int(pos_qty * sell_frac))
        if qty <= 0:
            return

        if self.SafeOptionOrder(self.tail_contract, -qty, tag="PLAT"):
            mid = self.TailMid()
            if mid > 0:
                self.hedge_cash += qty * mid * 100.0
            self.last_monetize = self.Time
            self.armed = False

    # ===== Re-hedge (batched) =====
    def MaybeRehedge(self, iv_pct):
        if (not self.tail_contract) or (not self.last_iwm_chain) or (not self.last_iwm_price):
            return
        if iv_pct is None or self.hedge_cash <= 0:
            return
        if (not self.in_crisis) and (iv_pct >= self.REHEDGE_IV_MAX):
            return

        tpv = float(self.Portfolio.TotalPortfolioValue)
        min_cash = max(float(self.REHEDGE_MIN_CASH), float(self.REHEDGE_MIN_CASH_PCT_TPV) * tpv)
        if float(self.hedge_cash) < min_cash:
            return

        cooldown = self.CRISIS_REHEDGE_COOLDOWN_DAYS if (self.in_crisis and self.CRISIS_CONT_REHEDGE) else self.REHEDGE_COOLDOWN_DAYS
        min_shortfall = self.CRISIS_REHEDGE_MIN_SHORTFALL_FRAC if (self.in_crisis and self.CRISIS_CONT_REHEDGE) else self.REHEDGE_MIN_SHORTFALL_FRAC
        if (self.Time.date() - self.last_rehedge.date()).days < cooldown:
            return

        pos = self.Portfolio[self.tail_contract]
        mid = self.TailMid()
        if mid <= 0:
            return
        cur_val = abs(pos.Quantity) * mid * 100.0
        cur_pct = cur_val / max(tpv, 1e-9)

        target_pct = self.HedgeTargetPct(iv_pct)
        if cur_pct >= target_pct * min_shortfall:
            return

        desired_add_pct = min(target_pct - cur_pct, target_pct * 0.50)
        budget = min(float(self.hedge_cash), desired_add_pct * tpv)
        if budget < 100:
            return

        existing_strike = self.Securities[self.tail_contract].StrikePrice
        spot = float(self.last_iwm_price)

        best, best_score = None, 1e99
        for c in self.last_iwm_chain:
            if c.Right != OptionRight.Put:
                continue
            dte = (c.Expiry - self.Time).days
            if abs(dte - self.TAIL_DTE_TARGET) > 20:
                continue
            m = float(c.Strike) / spot if spot > 0 else 0
            if m < self.TAIL_OTM_MIN or m > self.TAIL_OTM_MAX:
                continue
            if (float(c.BidPrice or 0) + float(c.AskPrice or 0)) <= 0:
                continue
            score = abs(float(c.Strike) - float(existing_strike)) + 0.02 * abs(dte - self.TAIL_DTE_TARGET)
            if score < best_score:
                best_score, best = score, c
        if best is None:
            return

        price = (float(best.BidPrice or 0) + float(best.AskPrice or 0)) / 2.0
        if price <= 0:
            return

        qty = int(budget // (price * 100.0))
        if qty < int(self.REHEDGE_MIN_QTY):
            return

        if self.tail_base_qty and self.MAX_TAIL_QTY_MULT > 0:
            max_total = int(max(1, round(self.tail_base_qty * self.MAX_TAIL_QTY_MULT)))
            cur_total = int(abs(self.Portfolio[self.tail_contract].Quantity))
            allowed = max(0, max_total - cur_total)
            qty = min(qty, allowed)
            if qty < int(self.REHEDGE_MIN_QTY):
                return

        if self.SafeOptionOrder(best.Symbol, qty, tag="REH"):
            self.hedge_cash -= qty * price * 100.0
            self.last_rehedge = self.Time

    # ===== Kicker (gated + cooldown) =====
    def MaybeBuyKickerOnce(self):
        if not self.ENABLE_KICKER:
            return

        macro_ivp = self.IVPercentile()
        imminent = self._IsImminentCrisis(macro_ivp)

        if self.KICKER_REQUIRE_CRISIS_OR_IMMINENT and (not self.in_crisis) and (not imminent):
            return

        if self.kicker_deployed_this_crisis or self.kicker_contract:
            return

        if self._kicker_last_exit_day is not None:
            if (self.Time.date() - self._kicker_last_exit_day).days < int(self.KICKER_COOLDOWN_DAYS):
                return

        if not self.last_spx_chain or not self.last_spx_price:
            return

        budget = self.KICKER_BUDGET_PCT * self.Portfolio.TotalPortfolioValue
        if budget < 100:
            return

        spot = float(self.last_spx_price)
        target_strike = spot * self.KICKER_OTM

        best, best_score = None, 1e99
        for c in self.last_spx_chain:
            if c.Right != OptionRight.Put:
                continue
            dte = (c.Expiry - self.Time).days
            if dte < self.KICKER_DTE_MIN or dte > self.KICKER_DTE_MAX:
                continue
            m = float(c.Strike) / spot if spot > 0 else 0
            if m < 0.78 or m > 0.90:
                continue
            if (float(c.BidPrice or 0) + float(c.AskPrice or 0)) <= 0:
                continue
            score = abs(float(c.Strike) - float(target_strike)) + 0.02 * abs(dte - ((self.KICKER_DTE_MIN + self.KICKER_DTE_MAX) / 2.0))
            if score < best_score:
                best_score, best = score, c

        if best is None:
            return

        price = (float(best.BidPrice or 0) + float(best.AskPrice or 0)) / 2.0
        if price <= 0:
            return

        qty = int(budget // (price * 100.0))
        if qty < int(self.OPT_MIN_CONTRACTS):
            return

        if self.SafeOptionOrder(best.Symbol, qty, tag="KICK"):
            self.kicker_contract = best.Symbol
            self.kicker_deployed_this_crisis = True

    def ExitKicker(self):
        if not self.kicker_contract:
            return
        if self.Portfolio[self.kicker_contract].Invested:
            self.SafeLiquidate(self.kicker_contract, tag="KICK_OUT")
        self.kicker_contract = None
        self._kicker_last_exit_day = self.Time.date()

    # ===== Core guards =====
    def _ResetCoreNotionalIfNewDay(self):
        d = self.Time.date()
        if self._core_notional_day != d:
            self._core_notional_day = d
            self._core_notional_used_today = 0.0

    def _CoreOrderAllowed(self, notional):
        self._ResetCoreNotionalIfNewDay()
        cap = self.CORE_DAILY_NOTIONAL_CAP_PCT * self.Portfolio.TotalPortfolioValue
        if cap <= 0:
            return True
        if (self._core_notional_used_today + abs(notional)) <= cap:
            self._core_notional_used_today += abs(notional)
            return True
        return False

    # --- LIVE HARDENER (2): force first core allocation (bypass HITL/caps/drift) ---
    def _BootstrapCore(self):
        if self.core_bootstrapped:
            return
        self.SetHoldings(self.spy, self.CORE_WEIGHT, tag="CORE_BOOT")
        self.core_bootstrapped = True

    # ===== EOD report (trimmed) =====
    def _SendEndOfDayReport(self):
        if not self.SLACK_EOD_REPORT:
            return
        staged = list(self.pending_actions) if self.pending_actions else []
        open_orders = list(self.open_ticket_meta.items()) if self.open_ticket_meta else []

        lines = []
        lines.append("QC Daily Report (%s)" % self.Time.strftime("%Y-%m-%d"))
        lines.append("TPV=$%s Cash=$%s crisis=%s tail=%s hedge_cash=$%s" % (
            format(self.Portfolio.TotalPortfolioValue, ",.0f"),
            format(float(self.Portfolio.Cash), ",.0f"),
            str(self.in_crisis),
            self._FmtSymbol(self.tail_contract) if self.tail_contract else "None",
            format(self.hedge_cash, ",.0f"),
        ))

        if staged:
            lines.append("STAGED(%d):" % len(staged))
            for a in staged[:self.SLACK_MAX_ITEMS]:
                lines.append("- " + self._ActionToText(a))

        if open_orders:
            lines.append("OPEN(%d):" % len(open_orders))
            for oid, meta in open_orders[:self.SLACK_MAX_ITEMS]:
                age_min = int((self.Time - meta.get("t", self.Time)).total_seconds() / 60.0)
                lines.append("- id=%s age=%dm %s tag=%s" % (
                    str(oid), age_min, self._FmtSymbol(meta.get("sym")), str(meta.get("tag", "")))
                )

        self._Slack("\n".join(lines))

    # ===== Daily orchestration =====
    def DailyCheck(self):
        self._ProcessPendingActions()
        self._CancelStaleOpenOrders()
        self._BootstrapCore()

        total = self.Portfolio.TotalPortfolioValue
        cur_val = self.Portfolio[self.spy].HoldingsValue
        if total > 0:
            w = cur_val / total
            drift = abs(w - self.CORE_WEIGHT)
            if self.core_bootstrapped and drift > self.REBALANCE_DRIFT:
                desired_val = self.CORE_WEIGHT * total
                delta_notional = desired_val - cur_val
                if self._CoreOrderAllowed(delta_notional):
                    self._StageOrExecute({"type": "setholdings", "symbol": self.spy, "weight": self.CORE_WEIGHT, "tag": "CORE_REBAL"})

        macro_ivp = self.IVPercentile()
        iv_for_logic = macro_ivp if macro_ivp is not None else self.HEDGE_MID_IV_PCT
        self.UpdateCrisisState(iv_for_logic)

        if self.ENABLE_TAIL_HEDGE:
            if self.tail_contract is None:
                self.EstablishTail()
            else:
                self.MaybeRollTail()

        if self.ENABLE_TAIL_HEDGE and self.in_crisis:
            self.MaybeCrisisPlateauMonetize(iv_for_logic)

        if self.ENABLE_TAIL_HEDGE:
            self.MaybeRehedge(iv_for_logic)

        if self.ENABLE_KICKER:
            self.MaybeBuyKickerOnce()

    def OnEndOfAlgorithm(self):
        self.Debug("done hedge_cash=$%s tail=%s crisis=%s" % (format(self.hedge_cash, ",.0f"), str(self.tail_contract), str(self.in_crisis)))