# ======================================================
# Full Premium Selling Scanner + Volatility Dashboard
# With GARCH Volatility Forecast Integration
# antwerks 12/01/2025
# ======================================================
input ivLength = 30; # IV lookback (for context, not used directly)
input hvLength = 20; # HV lookback
input trendLength = 50; # Trend filter (SMA)
input emLength = 5; # Expected Move days
input liquidityMin = 1000000;
input priceMin = 5;
# GARCH parameters
input garchAlpha = 0.10; # reaction to last shock
input garchBeta = 0.85; # persistence of past variance
input edgeMode = {default HVandGARCH, HVonly, GARCHonly};
# -----------------------------
# PRICE / LIQUIDITY FILTERS
# -----------------------------
def liquid = volume > liquidityMin;
def validPrice = close > priceMin;
# -----------------------------
# IMPLIED VOLATILITY (SAFE)
# -----------------------------
def IV_raw = if !IsNaN(imp_volatility()) then imp_volatility() else 0;
def IV = IV_raw * 100;
# -----------------------------
# HISTORICAL VOLATILITY (SAFE)
# -----------------------------
def HV =
if hvLength > 1 then
StDev(Log(close / close[1]), hvLength) * Sqrt(252) * 100
else 0;
# -----------------------------
# GARCH(1,1) VOLATILITY FORECAST
# -----------------------------
# log returns
def ret = Log(close / close[1]);
# sample standard deviation and variance of returns
def sampleStd = if hvLength > 1 then StDev(ret, hvLength) else 0;
def sampleVar = Sqr(sampleStd);
# omega chosen so that unconditional variance matches sample variance
def garchOmega = sampleVar * (1 - garchAlpha - garchBeta);
# recursive GARCH variance
rec garchVar =
if IsNaN(garchVar[1]) or garchVar[1] <= 0 then sampleVar
else garchOmega + garchAlpha * Sqr(ret[1]) + garchBeta * garchVar[1];
# annualized GARCH volatility (%)
def GARCHVol = Sqrt(garchVar * 252) * 100;
# -----------------------------
# IV RANK (1-year)
# -----------------------------
def IV_history = IV;
def belowCount =
fold i = 1 to 252
with total = 0
do total + (if IV_history >= GetValue(IV_history, i) then 1 else 0);
def IVR = (belowCount / 252) * 100;
# -----------------------------
# IV PERCENTILE (1-year)
# -----------------------------
def IVmax = Highest(IV_history, 252);
def IVmin = Lowest(IV_history, 252);
def IVP = if IVmax != IVmin then
((IV_history - IVmin) / (IVmax - IVmin)) * 100
else 0;
# -----------------------------
# EXPECTED MOVE (IV-based)
# -----------------------------
def EM = close * IV_raw * Sqrt(emLength / 365);
# -----------------------------
# TREND FILTER
# -----------------------------
def sma = Average(close, trendLength);
def upTrend = close > sma;
def downTrend = close < sma;
# -----------------------------
# VOLATILITY EDGE CONDITIONS
# -----------------------------
def volEdgeHV = IV > (HV + 5);
def volEdgeGARCH = IV > (GARCHVol + 5);
def volEdge =
if edgeMode == edgeMode.HVandGARCH then volEdgeHV and volEdgeGARCH
else if edgeMode == edgeMode.HVonly then volEdgeHV
else volEdgeGARCH;
# -----------------------------
# STRATEGY LOGIC
# -----------------------------
# 1 = Sell Puts
# -1 = Sell Calls
# 0 = Sell Both
def strategyFlag =
if upTrend then 1
else if downTrend then -1
else 0;
# -----------------------------
# SCAN OUTPUT
# -----------------------------
plot scan =
volEdge and
liquid and
validPrice;
# -----------------------------
# LABELS
# -----------------------------
AddLabel(yes,
"IV: " + AsText(IV, "0.0") +
" | HV: " + AsText(HV, "0.0") +
" | GARCH: " + AsText(GARCHVol, "0.0") +
" | IVR: " + AsText(IVR, "0.0") +
" | IVP: " + AsText(IVP, "0.0") +
" | EM: ±" + AsDollars(EM),
Color.WHITE
);
AddLabel(yes,
"Edge: " +
(if edgeMode == edgeMode.HVandGARCH then "IV > HV & GARCH"
else if edgeMode == edgeMode.HVonly then "IV > HV"
else "IV > GARCH") +
(if volEdge then " (ACTIVE)" else " (inactive)"),
if volEdge then Color.GREEN else Color.GRAY
);
AddLabel(yes,
if strategyFlag == 1 then "STRATEGY: Sell Puts (Bullish)"
else if strategyFlag == -1 then "STRATEGY: Sell Calls (Bearish)"
else "STRATEGY: Sell Both Sides (Neutral)",
if strategyFlag == 1 then Color.GREEN
else if strategyFlag == -1 then Color.RED
else Color.YELLOW
);