| Overall Statistics |
|
Total Orders 503 Average Win 0.87% Average Loss -0.53% Compounding Annual Return 15.773% Drawdown 24.600% Expectancy 0.445 Start Equity 1000000 End Equity 3306120.76 Net Profit 230.612% Sharpe Ratio 0.669 Sortino Ratio 0.763 Probabilistic Sharpe Ratio 31.936% Loss Rate 45% Win Rate 55% Profit-Loss Ratio 1.63 Alpha 0.028 Beta 0.718 Annual Standard Deviation 0.126 Annual Variance 0.016 Information Ratio 0.093 Tracking Error 0.069 Treynor Ratio 0.118 Total Fees $8800.59 Estimated Strategy Capacity $63000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 0.13% Drawdown Recovery 748 |
# 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 "0") == "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(2026, 2, 28)
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))
self.spx_opt_symbol = spxopt.Symbol
iwmopt = self.AddOption("IWM", Resolution.Minute)
iwmopt.SetFilter(lambda u: u.PutsOnly().Expiration(50, 130).Strikes(-28, -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):
return False
if not self._PassSpreadAndMid(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:
return
if not self.last_iwm_chain or not 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):
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)))