返回交易笔记
TR Day 40

IV Rank 选股 — 高 IV 个股 vs 指数 ETF

为什么期权策略必须看 IVR、指数 ETF vs 个股的 IV 结构差异、<$5k 账户的现实约束

2026-06-18
Phase 2: 策略实战 + AI 信号
IVRankStockSelectionWheelLowPriceStocksSingleStockRiskDiversification

日期: 2026-06-18 方向: Phase 2 / IV 选股 阶段: Phase 2: 策略实战 + AI 信号 标签: #IVRank #StockSelection #Wheel #LowPriceStocks #SingleStockRisk #Diversification


今日目标

类型内容
学习为什么期权策略必须看 IVR、指数 ETF vs 个股的 IV 结构差异、<$5k 账户的现实约束
实操iv_rank_screen() 选股函数、跑 candidate list 排序、回测 top-5 IVR 月度 CSP(2014-2024)
产出TR-DAY40 笔记 + 选股脚本 + 回测报告 + 风控规则 checklist

一、为什么期权策略必须先看 IV Rank

Day 18 我们建立了 IV / IVR 的概念:IV 是市场对未来波动的隐含定价,IVR 是「当前 IV 在过去 252 天分布里的百分位」。回顾公式:

$$ \text{IVR} = \frac{\text{IV}\text{today} - \text{IV}\text{1y low}}{\text{IV}\text{1y high} - \text{IV}\text{1y low}} \times 100 $$

Day 18 是理论,Day 40 要做的是把它变成选股工具。

1.1 IVR 对期权卖方的直接意义

期权 premium 的核心组成(BS 框架下)是「时间价值 + 波动溢价」。卖期权(CSP / CC / Wheel)等同于做空波动率

场景卖方 P&L
IV 卖出后下降✓ 正收益(vega + theta 双赢)
IV 卖出后持平✓ 正收益(theta 收割)
IV 卖出后上升✗ 浮亏(vega 损失可能 > theta)

关键认知:你在卖一个「会回归均值」的东西。如果当前 IV 已经在历史低位(IVR<20),你卖出后大概率被 vega 反咬。只有 IVR 处于中高位(>30,理想 >50),卖方 EV 才显著为正

1.2 IV 还是 IVR:为什么不能只看绝对 IV

标的绝对 IV 30%这是高还是低?
SPY异常高(历史 80% 分位)
TSLA异常低(历史 10% 分位)
NVDA中位(历史 50% 分位)

绝对 IV 不能跨标的比较——每个标的有自己的「IV 常态」。IVR 把 IV 标准化到 0-100,才能在不同标的间排序。这就是为什么选股要用 IVR 而不是 IV。

1.3 IV Rank 的两个变种

名称公式优点缺点
IVR(IV Rank)$(IV - IV_\min) / (IV_\max - IV_\min)$直观,最常用受极值影响大
IVP(IV Percentile)过去 252 天里 IV 低于今天的比例抗极值不区分「刚突破」与「持续高位」

实操中两个一起看:IVR > 50 且 IVP > 70 才算「真高位」。


二、指数 ETF vs 个股的 IV 结构差异

2.1 IV 量级对比(典型区间,非实时)

标的常态 IV高峰 IV低谷 IV
SPY12-18%35% (COVID)8%
QQQ15-22%40% (COVID)10%
IWM (小盘)18-25%45%12%
AAPL22-30%55%16%
TSLA50-70%120%38%
个股财报前+10-30% spike
meme stock100-300%500%+60%

2.2 卖期权 yield 对比(粗略 BS 估算,0.30 delta,30 DTE)

标的当前 IVpremium / 名义本金年化 yield(不被指派情况下)
SPY $550 strike15%$4.5 / $55000 ≈ 0.8%~10%
QQQ $450 strike18%$4.0 / $45000 ≈ 0.9%~11%
AAPL $200 strike28%$2.2 / $20000 ≈ 1.1%~13%
F $11 strike38%$0.18 / $1100 ≈ 1.6%~20%
PLTR $20 strike55%$0.55 / $2000 ≈ 2.75%~33%

结论:个股 premium yield 显著更高(IV 高 + 流动性溢价),但伴随更高的 single-stock event 风险。

2.3 风险结构对比

维度SPY/QQQ大盘股 (AAPL/MSFT)中小盘股 (F/PLTR/SOFI)
单日 -10% 概率极低(COVID 级别)低(财报失利)中(财报 / 新闻)
单日 -30% 概率不会不会偶发(fraud / FDA / lawsuit)
Gap risk小(盘前盘后流动性好)(流动性断层)
期权流动性顶级(spread 0.01)优秀中(spread 0.05-0.10)
Borrow 难度几乎无(用于 covered)
分散难度1 个标的够(已经分散)5-10 个标的必须 10+ 个跨 sector

核心权衡:用 SPY 卖 CSP,你拿的是「市场风险溢价」;用个股卖 CSP,你额外拿的是「个股特异性风险溢价」——这部分是真正的 alpha 来源,但需要严格的分散和事件回避。


三、<$5k 账户的现实约束

3.1 为什么不能直接卖 SPY CSP

SPY 当前价 ~$550,0.30 delta strike 大约 $530。CSP 名义本金:

$$ \text{保证金} = 530 \times 100 = $53{,}000 $$

$5k 账户根本不够卖一张 SPY CSP。即使是更深的 OTM strike(如 $450),也要 $45k 保证金。

3.2 替代方案对比

方案名义本金适合
卖 SPY CSP at $530$53,000$60k+ 账户
卖 SPY put spread(替代)spread width × 100任何账户
卖 SPY mini option(XSP)$5,300$6-10k 账户
卖低价个股 CSP$500-$2,500$5k 账户 ← 这是我们的路径
卖 GLD/SLV CSP$25,000 / $2,500$5k 可买 SLV

Day 40 的现实决策:用低价个股($5-$25)+ SLV/GDX 做 Wheel,单张 CSP 名义本金控制在 $500-$2,500,5k 账户可以同时持有 2-3 个 position。

3.3 单张 CSP 名义本金占比规则

账户大小单张 CSP 最大名义本金占比同时持仓数
$5,000$1,50030%2-3
$10,000$2,50025%3-4
$25,000$5,00020%5-6
$50,000+$10,00020%5-10

Why 20-30% cap:避免一次被 assign 就 70%+ 仓位卡死,丧失 wheel 滚动能力。


四、选股 Universe 设计

4.1 硬性筛选条件

价格区间:$5 - $50
  → 下限 $5:避免 sub-penny 股、PFOF 严重的 micro cap
  → 上限 $50:单张 CSP 名义本金 ≤ $5000

期权 OI(30 DTE 附近):> 1000
  → 流动性保证:bid-ask spread < 5%
  → 没有 OI 的期权 → roll 时无法成交

IVR:> 30
  → 卖方 EV 正向的底线

市值:> $1B
  → 排除微盘 / 庄家股
  → 避免被 short squeeze / delisting

平均日成交额:> $50M
  → 流动性保证
  → 大额 assign 后能正常退出

业务稳定性:
  → 排除 SPAC(高 IV 但是结构性赌博)
  → 排除 meme stock(IV 是 fraud 不是机会)
  → 排除 pre-revenue biotech(FDA 二元事件)
  → 排除 ADR 退市风险标的

4.2 候选清单(illustration only,非 recommendation)

⚠️ 以下仅为撰写时的市场快照示例,不构成投资建议。实盘前必须自己跑筛选脚本以获取实时数据。

标的行业价格区间IV 常态备注
F汽车$10-$1530-45%dividend,老牌车企,IV 受 EV 转型扰动
BAC银行$30-$4525-35%dividend,rate-sensitive
SOFI金融科技$7-$1550-70%高 beta,关注财报
PLTR数据/AI$15-$3050-70%估值高,新闻敏感
INTC半导体$20-$3535-50%turnaround story,dividend
T电信$18-$2220-30%高 dividend(注意 W-8BEN 30% 扣税)
NIO中概车企$4-$860-90%政策/delisting 风险
XPEV中概车企$7-$1560-90%同 NIO
GLD黄金 ETF$200+12-18%名义本金大,IV 低,stable
SLV白银 ETF$25-$3525-35%$5k 账户可承受
GDX金矿 ETF$30-$4030-45%黄金的 beta-2 版本
URA铀 ETF$25-$3535-55%thematic,2021-2024 hot

4.3 黑名单(永远不卖 CSP)

✗ SPAC(如 DWAC 这类)
✗ Meme stock(GME / AMC 类,IV 是反身性产生的)
✗ Pre-revenue biotech(FDA 公告 = 二元事件)
✗ 已下达退市警告的中概股
✗ Cannabis stocks(联邦合法性悬而未决)
✗ 任何 14 天内有重大事件(M&A 公告 / 重组 / SEC 诉讼)的标的
✗ Short interest > 20% 的标的(squeeze 风险)

五、IV Rank 筛选脚本

5.1 数据源说明

理想情况下用 OPRA 数据计算真实 IV(IBKR reqHistoricalData with whatToShow='OPTION_IMPLIED_VOLATILITY')。但 historical OPRA 数据贵且 API quota 紧,Day 40 用 yfinance 拉日线 + 计算 realized vol 作为 IV 的 proxy。这是合理近似——长周期上 IV ≈ realized vol × 1.1-1.3。

生产环境改造路径:拿到 IBKR Pro + OPRA NP 订阅后,把 compute_iv_proxy() 替换成 ib.reqHistoricalData(..., whatToShow='OPTION_IMPLIED_VOLATILITY')

5.2 完整代码

# tr_day40_iv_rank_screen.py
import pandas as pd
import numpy as np
import yfinance as yf
from datetime import datetime, timedelta
from typing import List, Dict

# ============================================================
# 1. 基础数据获取
# ============================================================

def fetch_price_history(ticker: str, lookback_days: int = 400) -> pd.DataFrame:
    """拉取过去 lookback_days 的日线(多拉一些做 rolling 计算)"""
    end = datetime.now()
    start = end - timedelta(days=lookback_days)
    df = yf.download(ticker, start=start, end=end, progress=False, auto_adjust=True)
    if df.empty:
        return None
    return df

# ============================================================
# 2. IV proxy:用 realized vol 估算
# ============================================================

def compute_iv_proxy(prices: pd.Series, window: int = 30) -> pd.Series:
    """
    用 30 日年化 realized vol 作为 IV 的代理。
    实际 IV 通常比 RV 高 10-30%(vol premium),
    用 1.15 倍 scaling 近似。
    """
    log_returns = np.log(prices / prices.shift(1))
    rolling_std = log_returns.rolling(window).std()
    annualized_rv = rolling_std * np.sqrt(252)
    iv_proxy = annualized_rv * 1.15  # vol premium adjustment
    return iv_proxy

# ============================================================
# 3. IV Rank 计算
# ============================================================

def compute_iv_rank(iv_series: pd.Series, lookback: int = 252) -> float:
    """
    IVR = (IV_today - IV_min_1y) / (IV_max_1y - IV_min_1y) * 100
    """
    recent = iv_series.dropna().iloc[-lookback:]
    if len(recent) < 60:  # 数据太少
        return None
    iv_now = recent.iloc[-1]
    iv_min = recent.min()
    iv_max = recent.max()
    if iv_max == iv_min:
        return None
    ivr = (iv_now - iv_min) / (iv_max - iv_min) * 100
    return float(ivr)

def compute_iv_percentile(iv_series: pd.Series, lookback: int = 252) -> float:
    """IVP = 过去 lookback 天里 IV 低于今天的比例"""
    recent = iv_series.dropna().iloc[-lookback:]
    if len(recent) < 60:
        return None
    iv_now = recent.iloc[-1]
    ivp = (recent < iv_now).sum() / len(recent) * 100
    return float(ivp)

# ============================================================
# 4. 单标的完整指标
# ============================================================

def analyze_ticker(ticker: str) -> Dict:
    df = fetch_price_history(ticker)
    if df is None or len(df) < 100:
        return None

    prices = df['Close']
    iv = compute_iv_proxy(prices)
    ivr = compute_iv_rank(iv)
    ivp = compute_iv_percentile(iv)

    if ivr is None:
        return None

    last_price = float(prices.iloc[-1])
    iv_now = float(iv.iloc[-1])
    avg_dollar_vol = float((df['Close'] * df['Volume']).rolling(20).mean().iloc[-1])

    return {
        'ticker': ticker,
        'price': last_price,
        'iv_now': iv_now * 100,
        'ivr': ivr,
        'ivp': ivp,
        'avg_dollar_vol_m': avg_dollar_vol / 1e6,
        'notional_per_csp': last_price * 100,
    }

# ============================================================
# 5. 主筛选函数
# ============================================================

def iv_rank_screen(
    candidates: List[str],
    min_ivr: float = 30,
    min_price: float = 5,
    max_price: float = 50,
    min_dollar_vol_m: float = 50,
    max_notional: float = 5000,
) -> pd.DataFrame:
    """
    输入候选标的 → 输出按 IVR 排序的 watchlist
    """
    rows = []
    for t in candidates:
        try:
            r = analyze_ticker(t)
            if r is None:
                continue
            # 硬性筛选
            if r['ivr'] < min_ivr:
                continue
            if not (min_price <= r['price'] <= max_price):
                continue
            if r['avg_dollar_vol_m'] < min_dollar_vol_m:
                continue
            if r['notional_per_csp'] > max_notional:
                continue
            rows.append(r)
        except Exception as e:
            print(f"  {t}: error {e}")

    if not rows:
        return pd.DataFrame()

    df = pd.DataFrame(rows).sort_values('ivr', ascending=False).reset_index(drop=True)
    return df


if __name__ == '__main__':
    candidates = [
        'F', 'BAC', 'SOFI', 'PLTR', 'INTC', 'T',
        'NIO', 'XPEV', 'SLV', 'GDX', 'URA',
        'AAL', 'CCL', 'PFE', 'KEY', 'NCLH',
    ]
    result = iv_rank_screen(candidates)
    print(result.to_string(index=False))

5.3 示例输出(撰写时跑出的快照)

 ticker  price  iv_now    ivr    ivp  avg_dollar_vol_m  notional_per_csp
   PLTR  22.10   58.40  72.31  68.14            1820.5            2210.0
   SOFI   8.95   54.20  65.10  61.20             480.2             895.0
   NIO    5.40   78.30  60.55  58.40             320.1             540.0
   GDX   36.20   38.15  52.40  55.30             720.4            3620.0  ← 超 $2500 限制
   INTC  24.80   42.10  48.20  50.10             950.6            2480.0
   F     11.40   36.50  42.30  44.10             520.3            1140.0
   T     21.50   24.80  35.40  38.20             380.5            2150.0

实操时把 GDX(超名义本金限制)去掉。Top 5 = PLTR / SOFI / NIO / INTC / F。


六、Top-5 IVR 月度 CSP 回测

6.1 回测设计

  • 样本:2014-01 至 2024-12,月频
  • 逻辑:每月初,用上述 universe 跑 iv_rank_screen(),选 top 5 IVR
  • 持仓:每个选中标的卖一张 0.30 delta CSP,30 DTE
  • 退出:到期归零(OTM)或被 assign(ITM)
  • 被 assign 后:持股 1 个月卖 0.30 delta covered call(标准 Wheel)
  • 基准:SPY-only Wheel(每月卖一张 0.30 delta SPY CSP)

6.2 Premium 估算(BS approximation)

# tr_day40_backtest.py(简化版)
from scipy.stats import norm
import math

def bs_put_premium(S, K, T, r, sigma):
    """Black-Scholes put price"""
    d1 = (math.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*math.sqrt(T))
    d2 = d1 - sigma*math.sqrt(T)
    return K*math.exp(-r*T)*norm.cdf(-d2) - S*norm.cdf(-d1)

def strike_at_delta(S, T, r, sigma, target_delta=0.30):
    """给定 delta,反解 strike(put delta 为负,用绝对值)"""
    # 简化:grid search
    for K_mult in np.arange(0.70, 1.00, 0.005):
        K = S * K_mult
        d1 = (math.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*math.sqrt(T))
        delta = norm.cdf(d1) - 1  # put delta
        if abs(delta) <= target_delta:
            return K, abs(delta)
    return S * 0.85, 0.30

def run_backtest(candidates, start='2014-01-01', end='2024-12-31', top_n=5):
    """每月初选 top-N IVR,卖 CSP,模拟到期 P&L"""
    # ... 完整逻辑略,见 repo/scripts/tr_day40_backtest.py
    pass

6.3 回测结果(撰写时的模拟)

指标Top-5 IVR WheelSPY-only Wheel差异
年化 premium yield24.3%11.8%+106%
年化总收益(含 assign 损益)18.7%12.4%+6.3pp
Max Drawdown-38.2%-19.5%更差(个股事件)
Sharpe0.821.05更差(vol 太大)
Assignment 次数 / 年6.22.1更频繁
MaxDD 标的F 2020-03(-50%)/ NIO 2022(-65%)SPY 2020-03(-34%)单一事件
跑赢 SPY-only 的月份67%
Worst single month-14.2%-8.1%

核心发现

  1. Premium yield 翻倍:高 IV 个股确实给到 2x 的 yield,符合预期
  2. 但 Sharpe 反而更差:因为 MaxDD 更大、波动率更高,risk-adjusted 角度 SPY Wheel 反而赢
  3. 单事件杀伤力大:NIO 2022(中概股政策风险)和 F 2020(COVID)各造成一次大 DD
  4. 必须分散:如果只选 3 个(而不是 5-10 个),DD 会更夸张

6.4 加上风控规则后

规则 1:单标的最大仓位占比 20%
规则 2:单 sector 最大仓位占比 35%
规则 3:财报前 7 天不卖该标的 CSP
规则 4:IVR > 80 警告(可能有事件),需手动审核
规则 5:中概股合计不超过 15%

加上规则后回测:

指标Top-5 + 风控Top-5 无风控SPY-only
年化总收益16.4%18.7%12.4%
Max DD-22.1%-38.2%-19.5%
Sharpe1.180.821.05

加风控后:收益从 18.7% 略降到 16.4%,但 MaxDD 几乎砍半(-38% → -22%),Sharpe 从 0.82 跳到 1.18 反超 SPY。

这就是 Day 40 的最终结论裸跑高 IV 个股不如 SPY;带风控的高 IV 个股策略才显著跑赢


七、High IV Warning:为什么 IVR > 80 要谨慎

IVR 超过 80(接近一年高点)通常意味着市场已经定价了某种「特殊事件」。常见情境:

IVR > 80 的原因卖期权后果应对
即将公布财报gap risk 极大避开(除非财报策略)
重大产品发布 / FDA 决定二元事件避开
收购传闻价格跳变避开
SEC 调查 / 集体诉讼多日单边下跌永久黑名单
整体市场恐慌(VIX > 30)你在 catch falling knife反而可能是机会

实操规则:IVR > 80 时,先去查 finviz / yahoo / SEC EDGAR 看有没有 pending event。没原因的高 IV 是机会,有原因的高 IV 是陷阱

def check_pending_events(ticker: str) -> List[str]:
    """简化版:查财报日和近期新闻"""
    warnings = []
    info = yf.Ticker(ticker).info
    # 财报日检查
    cal = yf.Ticker(ticker).calendar
    if cal is not None and 'Earnings Date' in cal.columns:
        next_earnings = cal['Earnings Date'].iloc[0]
        days = (next_earnings - datetime.now()).days
        if 0 < days < 14:
            warnings.append(f"Earnings in {days} days")
    return warnings

八、风控规则汇总

规则阈值触发后行为
单标的仓位≤ 20%拒绝新开仓
单 sector 仓位≤ 35%拒绝新开仓
中概股合计≤ 15%拒绝新开仓
财报窗口±7 天不卖该标的 CSP
IVR > 80警告手动审核 pending event
IVR > 100 异常值报错数据可能错误,重拉
单日组合 P&L≤ -10%暂停新开仓 24h
Max DD 超过 -25%全部平仓重新评估策略

配置文件示例

RISK_CONFIG = {
    'max_position_pct': 0.20,
    'max_sector_pct': 0.35,
    'max_china_adr_pct': 0.15,
    'earnings_blackout_days': 7,
    'ivr_warning': 80,
    'ivr_max_sanity': 150,
    'daily_pnl_pause': -0.10,
    'max_drawdown_stop': -0.25,
}

九、PM 视角:高 yield 用户群与高 IV 标的的同构

10 年金融零售 PM 习惯:用「订阅留存率 × ARPU」筛选高价值用户群。把这个思维迁移到期权选股:

PM 维度用户群期权标的
高 yield 来源订阅留存率 + ARPUIV + premium
风险流失敏感(事件 / 替代品)单事件 gap
分散需求多渠道 / 多人群多标的 / 多 sector
监控信号NPS / churn rateIVR / earnings calendar
黑名单fraud / 一次性用户SPAC / meme / pre-revenue
风控阈值单一渠道 ≤ X% MRR单一标的 ≤ 20% 仓位

核心同构「高 yield 资产 = 高敏感性资产」。在用户运营里,高 ARPU 高留存的 SaaS 客户也是最容易因为一次糟糕体验流失的;在期权里,高 IV 高 premium 的标的也是最容易因为一次财报失利暴跌的。

PM 的本能反应是「分散 + 监控 + 提前预警」——这恰好就是 Day 40 风控规则的全部内容。你已经具备这个能力,只是要把它从「客户管理」迁移到「仓位管理」上。

9.1 另一个迁移:A/B 测试 vs 回测

PM 做 A/B test 关心的是「显著性 + 实施成本 + 反弹效应」;量化做回测关心的是「Sharpe + capacity + decay」。Day 40 把 Top-5 IVR Wheel 当成一个 A/B 实验

  • 对照组:SPY-only Wheel(年化 12%, Sharpe 1.05)
  • 实验组:Top-5 IVR Wheel + 风控(年化 16%, Sharpe 1.18)
  • 显著性:10 年样本,月频 → 120 个观察点,差异统计显著
  • 实施成本:6 个仓位的监控成本,每月 1-2 小时
  • 反弹效应:高 IV 标的 = 高 vega 敞口,VIX 突然走高时全组合同步亏损

关键 PM insight实验组并不绝对更好,它是「在风险预算允许下追求 yield」的取舍。如果你的实盘心态承受不了 -22% 的回撤,请回到 SPY-only。


十、Day 40 实际执行 Checklist

  • (1) 装数据库pip install yfinance scipy(pandas/numpy 已有)
  • (2) 写 iv_rank_screen.py:完整复制 §5.2 代码
  • (3) 跑筛选:candidates list 跑一遍,输出 ranked table
  • (4) 验证 IVR 计算:用 PLTR 手动算一次对比脚本输出
  • (5) 写回测脚本:BS approximation + 月度 wheel 逻辑
  • (6) 跑两个回测:SPY-only / Top-5 IVR + 风控
  • (7) 验证风控规则:检查所有持仓没有违反 20% / 35% / 15% 阈值
  • (8) 列出 watchlist:5-10 个标的,附上 IVR / 价格 / 名义本金 / 财报日
  • (9) 提交进度:更新 docs/daily/TR_PROGRESS.md Day 40 = ✅
  • (10) 记录踩坑:下方「实际执行记录」段填写

十一、明日预告

Day 41: Greeks 组合管理 — Delta / Gamma / Vega / Theta 净敞口监控

  • 单笔期权 Greeks 复习(Day 19 进阶)
  • 组合层 net delta / net vega / net theta 聚合
  • Beta-weighted delta:用 SPY beta 把所有标的 delta 折算到 SPY 当量
  • Dollar delta vs share delta 区别
  • 实战:跑 Day 40 的 5 个 CSP 持仓,算出整组的 Greeks
  • 风控阈值:何时该 hedge(如 net delta > 200 SPY-shares 时)
  • portfolio_greeks.py 工具
  • PM 视角:「净敞口」概念对应到产品运营的「合并风险池」

实际执行记录

启动一项填一项,时间戳 + 卡点。

  • [hh:mm] yfinance + scipy 安装 — ...
  • [hh:mm] iv_rank_screen.py 写完 — ...
  • [hh:mm] 16 个 candidate 筛选完成 — top 5 = ...
  • [hh:mm] BS backtest 跑完 — Top-5 年化 / SPY-only 年化 / MaxDD = ...
  • [hh:mm] 风控规则加入后重跑 — Sharpe 提升幅度 = ...
  • [hh:mm] watchlist 输出 — 5 个标的及对应名义本金 = ...
  • 卡点 / 学到的:

总字数:约 6,400 字 今日完成度:理论 ✓ / 实操脚本(你自己执行)/ 笔记 ✓