Roll 操作 — Theta 没收满 / ITM 处理决策树
Roll 的本质、三种 Roll 的取舍、何时 Roll 何时不 Roll、Roll 的数学约束(net credit 法则)、被 assigned 后的处理、CC 端 Roll 与 CSP 端 Roll 的差异、Roll 死循环陷阱
日期: 2026-06-21 方向: Phase 2 / Roll 阶段: Phase 2: 策略实战 + AI 信号 标签: #RollOut #RollDown #ITM #NetCredit #Wheel #Assignment #Avoidance
今日目标
| 类型 | 内容 |
|---|---|
| 学习 | Roll 的本质、三种 Roll 的取舍、何时 Roll 何时不 Roll、Roll 的数学约束(net credit 法则)、被 assigned 后的处理、CC 端 Roll 与 CSP 端 Roll 的差异、Roll 死循环陷阱 |
| 实操 | 写 should_roll() 决策函数 + execute_roll() 二段操作函数(先 BTC 再 STO),含 dry-run;用本周 paper trade 的 F / BAC / SOFI 三仓位模拟决策树 |
| 产出 | TR-DAY43 笔记 + wheel/roll.py 模块 + 三个仓位的实际决策记录(Roll vs 让过期 vs 主动 close) |
一、Roll 到底是什么:一笔交易还是两笔?
Roll 的中文常译成「展期」「滚动」「续约」,这三个词都对,但没一个把核心点说出来。
Roll = 在同一个标的上,平掉当前 expiry 的 position,开一个更远 expiry 的 position;两笔操作在心理上是一个动作,但在 broker 那里是两笔独立的成交。
拆开看:
原始 position: Short Put F 06/20 $10 @ $0.18 收取
当前状态: 06/18,F 报价 $9.40,put 已经 ITM $0.60
Roll 操作 = 两笔 trade:
Step 1: Buy to Close (BTC) F 06/20 $10 Put @ $0.65 (付出)
Step 2: Sell to Open (STO) F 07/18 $10 Put @ $0.95 (收取)
Net 现金流: -0.65 + 0.95 = +$0.30 / share = +$30 / contract
注意三点:
- strike 可以不变,也可以改——这是 Roll out / Roll down / Roll up 的分类依据
- expiry 必须更远(往近期 Roll 在某些 broker 叫 "Roll in",意义不大,几乎不用)
- 必须是 net credit 才有意义——这是后面要专门讲的核心法则
很多 broker(包括 IBKR 和 tastytrade)提供「Roll」按钮,会自动把两笔打包成一个 combo order。combo order 有 net debit / net credit 的 mid-price 撮合机制,比手动两笔分别下单成交质量好。但本质还是两笔交易,两份佣金。
二、三种 Roll:Out / Down / Up
2.1 Roll Out(同 strike,远 expiry)
最常见的一种。
原: Short Put F 06/20 $10 收 $0.18
Roll Out → Short Put F 07/18 $10 收 $0.50
Net credit: +$0.50 - $0.65 (close cost) = -$0.15 ? ← 注意:当 put ITM 时 close cost 上升
用途:F 价格跌到 strike 附近或刚 ITM,你还相信 F 长期值得拿货,但不想 6/20 就被 assigned。Roll 一个月,给市场更多时间反弹。
Trade-off:
- ✅ 延长时间收 Theta
- ✅ 远期 IV term structure 通常更高,premium 大
- ❌ 锁住资金一个月不能用
- ❌ 如果继续跌,下个月还是会 ITM,进入 Roll 死循环
2.2 Roll Down(低 strike,远 expiry)
Strike 降低,避免被 assigned。
原: Short Put F 06/20 $10 深 ITM(F=$8.80)
Roll Down → Short Put F 07/18 $9.5
Net premium 通常较小,因为同时降 strike 又延 expiry,两个动作部分抵消
用途:F 跌得比预期深,$10 接货你不舒服了,想把成本基础往下压一点。Roll Down 等同于「我宁可少收 premium,也不要 $10 接货」。
重要:Roll Down 经常是 net debit(你要倒贴钱)。这不一定是坏事——你是在花钱换更好的 strike。但必须算清楚账。
2.3 Roll Up(高 strike)
很少用在 CSP 端,主要用在 Covered Call (CC) 端。
场景:你拥有 100 股 F @ $10 成本,卖出 CC F 06/20 $11
F 涨到 $11.50,CC 已经 ITM,再不动就被 called away
原: Short Call F 06/20 $11
Roll Up → Short Call F 07/18 $12
意图:保留股票上行空间,避免在 $11 被 called away
Trade-off:
- ✅ 保留更多上行空间
- ✅ 如果继续涨,下月还能在 $12 卖 CC
- ❌ Net credit 通常很小,甚至 net debit
- ❌ 如果 F 涨到 $12 以上,你又要面对同样问题(涨太快 = CC 端永远在追)
三、何时该 Roll:决策树
我把 Day 1-42 的所有期权基础知识收敛到这一棵树。遇到 ITM 仓位,从顶端走到底,每个分叉问自己一个问题。
┌───────────────────────────────────┐
│ 当前 position 距离 expiry 多少天? │
└───────────────────┬───────────────┘
│
┌───────────────────────┼──────────────────────────┐
▼ ▼ ▼
DTE > 21 天 DTE 7-21 天 DTE < 7 天
│ │ │
┌─────┴─────┐ ┌───────┴───────┐ ┌───────┴────────┐
▼ ▼ ▼ ▼ ▼ ▼
profit ≥50% 其他状态 仍深 OTM ATM 或 ITM 深 OTM ITM
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
主动 BTC hold 让它过期 考虑 Roll 让它过期 Scenario C
兑现利润 等 Theta (零费用) out (零费用) (核心决策)
(50% rule)
Scenario C(DTE < 7 天且 ITM)展开:
Scenario C: DTE<7d 且 ITM
│
┌───────────┴───────────┐
▼ ▼
能 Roll 出 net credit 不能 Roll 出 net credit
│ │
┌──────┴──────┐ ▼
▼ ▼ 接受 assignment
还想 hold? 不想了 (走 Stage 2→3:
│ │ 拿货 → 立刻挂 CC)
▼ ▼
Roll Out 接 assignment
或 Roll Down
几个关键判断点:
- DTE > 21 + 仍深 OTM + 利润 ≥ 50% premium → 主动 BTC(这是 tastytrade 著名的「manage winners at 50%」法则)。原因:剩余 50% premium 要用一倍以上的时间才能收完,时间风险/Gamma 风险不值。
- DTE 7-21 天 + ITM → 这是 Roll 的黄金窗口。再不动 Theta 加速会变成 Gamma 加速。
- DTE < 7 + 深 OTM → 不要瞎动,让它过期。任何 BTC 都是付费给市场(spread + 佣金)。
四、Roll 的数学:Net Credit 法则
第一法则:必须 net credit 才 Roll。Net debit 的 Roll 等同于「为了延后亏损而再付一笔钱」。
公式:
Net Credit = (New Premium Received)
- (Old Position Close Cost)
- 2 × Commission
- 2 × Bid-Ask Spread Cost
if Net Credit > 0: → Roll
else: → 接 assignment(或主动 close)
把这条规则展开,注意几个陷阱:
4.1 Close cost 不是当初 STO 的 premium
新手常犯的错误:以为「我当初收了 $0.18,现在 BTC 花 $0.65,亏 $0.47」。这个亏损是 sunk cost,已经发生了,决策只看「现在 Roll 出去能不能 net credit」。
错误思路:「我开仓收 $0.18,新仓收 $0.50,净 $0.50 + $0.18 = $0.68 ✓」 ← 错
正确思路:「Close 要 $0.65,开新仓收 $0.50,net = $0.50 - $0.65 = -$0.15 ✗ 不 Roll」
4.2 ITM 越深,Roll 越难做出 net credit
当 put 深度 ITM(如 F 跌到 $8.5,put strike $10),intrinsic value 是 $1.50,close 至少要花 $1.50+,而你能收到的下月同 strike premium 可能只有 $1.55——extrinsic 只有 $0.05。一旦 spread 和佣金吃进去,net credit 是负的。
经验数据:
| ITM 深度(占 strike %) | 同 strike Roll out 一月 | 能否 net credit |
|---|---|---|
| 0-2%(刚刚 ITM) | 通常 +$0.20 ~ +$0.50 | ✅ 容易 |
| 2-5% | 通常 +$0.05 ~ +$0.20 | ⚠️ 勉强 |
| 5-10% | 通常 -$0.10 ~ +$0.05 | ❌ 很难 |
| >10%(深度 ITM) | 通常 net debit | ❌ 几乎不可能 |
结论:深度 ITM 时,Roll 已经不是好选择。这种情况就该接 assignment,把它转成 Wheel 的 Stage 2。
4.3 IV 高时 Roll 容易,IV 低时 Roll 难
Roll 的本质是「用时间换 extrinsic premium」。IV 高 → 远期合约 extrinsic 大 → 容易 net credit。 IV 低 → 远期合约 extrinsic 也小 → 难 net credit。
F earnings 前一周(IV ≈ 60%) → Roll out 一月通常 +$0.40 ~ +$0.80
F earnings 后第二周(IV ≈ 28%) → Roll out 一月可能 +$0.10 ~ +$0.20
这就是为什么 Day 49 起我会讲「财报前 IV crush 套利」——同一个机制反过来用。
五、代码实现:should_roll + execute_roll
5.1 should_roll() 决策函数
把决策树编码成一个函数。返回 (should_roll: bool, reason: str) 便于日志审计。
# wheel/roll.py
from dataclasses import dataclass
from datetime import date
from typing import Literal, Tuple
@dataclass
class ShortPutPosition:
symbol: str
strike: float
expiry: date
premium_received: float # 当初 STO 时收的 premium
current_underlying: float # 当前股价
current_option_mid: float # 当前 put 的 mid price(BTC 成本估计)
contracts: int = 1
roll_count: int = 0 # 历史 Roll 次数,用于死循环防护
def dte(p: ShortPutPosition, today: date) -> int:
return (p.expiry - today).days
def is_itm(p: ShortPutPosition) -> bool:
return p.current_underlying < p.strike
def profit_pct(p: ShortPutPosition) -> float:
"""已实现利润占初始 premium 的百分比(未平仓估算)"""
unrealized = p.premium_received - p.current_option_mid
return unrealized / p.premium_received if p.premium_received > 0 else 0.0
def should_roll(
p: ShortPutPosition,
today: date,
new_expiry_mid: float, # 候选远月合约 mid price
commission_per_leg: float = 0.65,
spread_slippage: float = 0.02,
) -> Tuple[bool, Literal["roll_out", "close_win", "let_expire", "accept_assignment", "hold"], str]:
"""
返回 (should_act, action, reason)。
action ∈ {"roll_out", "close_win", "let_expire", "accept_assignment", "hold"}
"""
days = dte(p, today)
# --- avoidance pattern: 限制 Roll 死循环 ---
if p.roll_count >= 2:
if is_itm(p):
return True, "accept_assignment", f"already rolled {p.roll_count}x; force accept to break spiral"
# --- DTE > 21 ---
if days > 21:
if profit_pct(p) >= 0.5:
return True, "close_win", f"profit {profit_pct(p):.0%} ≥ 50% rule"
return False, "hold", f"DTE={days}, theta still working"
# --- DTE 7-21 ---
if 7 <= days <= 21:
if not is_itm(p):
return False, "hold", f"OTM, let theta accelerate"
# ITM, 评估 Roll
net_credit = (
new_expiry_mid
- p.current_option_mid
- 2 * commission_per_leg / 100 # 转成 per share
- spread_slippage
)
if net_credit > 0:
return True, "roll_out", f"ITM, net credit ${net_credit:.2f} > 0"
return False, "hold", f"ITM but Roll net debit ${net_credit:.2f}; wait"
# --- DTE < 7 ---
if days < 7:
if not is_itm(p):
return False, "let_expire", f"deep OTM with {days}d left, let expire"
# ITM 且即将到期
net_credit = (
new_expiry_mid
- p.current_option_mid
- 2 * commission_per_leg / 100
- spread_slippage
)
if net_credit > 0:
return True, "roll_out", f"ITM, last week, Roll out net credit ${net_credit:.2f}"
return True, "accept_assignment", f"ITM, no net credit on Roll, take assignment per plan"
return False, "hold", "unreached"
注意两个安全设计:
- roll_count 上限 = 2:超过 2 次强制接货。后面单独讲。
- commission 和 spread 显式入参:不要把成本藏在「应该差不多」里——金融决策的成本必须显式建模。
5.2 execute_roll() 操作函数(先 BTC 再 STO)
# wheel/roll.py (续)
from ib_insync import IB, Option, ComboLeg, Contract, Order
def execute_roll(
ib: IB,
symbol: str,
old_expiry: str, # 'YYYYMMDD'
old_strike: float,
new_expiry: str,
new_strike: float,
contracts: int = 1,
right: Literal["P", "C"] = "P",
dry_run: bool = True,
limit_net_credit: float = 0.05, # 最低可接受 net credit
) -> dict:
"""
Roll a short put (or call) via a combo order.
Step 1: Buy to Close old leg
Step 2: Sell to Open new leg
Combined as one combo to capture mid-price.
"""
# 限定合约
old_opt = Option(symbol, old_expiry, old_strike, right, "SMART", "100", "USD")
new_opt = Option(symbol, new_expiry, new_strike, right, "SMART", "100", "USD")
ib.qualifyContracts(old_opt, new_opt)
# 取最新报价用于 dry-run 估算
old_ticker = ib.reqMktData(old_opt, '', snapshot=True)
new_ticker = ib.reqMktData(new_opt, '', snapshot=True)
ib.sleep(1.5)
old_mid = (old_ticker.bid + old_ticker.ask) / 2
new_mid = (new_ticker.bid + new_ticker.ask) / 2
net_credit_est = new_mid - old_mid
plan = {
"symbol": symbol,
"old": f"{old_expiry}/{old_strike}{right}",
"new": f"{new_expiry}/{new_strike}{right}",
"old_mid": round(old_mid, 4),
"new_mid": round(new_mid, 4),
"net_credit_est": round(net_credit_est, 4),
"contracts": contracts,
}
if net_credit_est < limit_net_credit:
plan["status"] = "REJECTED"
plan["reason"] = f"net_credit {net_credit_est:.4f} < limit {limit_net_credit}"
return plan
if dry_run:
plan["status"] = "DRY_RUN_OK"
return plan
# ---- 真实下单(combo)----
combo = Contract(
symbol=symbol, secType="BAG", exchange="SMART", currency="USD",
comboLegs=[
ComboLeg(conId=old_opt.conId, ratio=1, action="BUY", exchange="SMART"),
ComboLeg(conId=new_opt.conId, ratio=1, action="SELL", exchange="SMART"),
],
)
# combo limit price 用 net credit 表示(正数 = 收钱)
order = Order(
action="BUY", # IBKR combo 约定:BUY combo at -credit
orderType="LMT",
totalQuantity=contracts,
lmtPrice=round(-limit_net_credit, 2), # 负数表示 net credit
tif="DAY",
)
trade = ib.placeOrder(combo, order)
plan["status"] = "SUBMITTED"
plan["order_id"] = trade.order.orderId
return plan
dry-run 是必须的——任何会动钱的代码,第一版都要先支持 dry_run=True,跑通逻辑+验证报价合理,才打开实盘开关。这是 Day 1 笔记里提到的 Read-Only safety pattern 的延伸。
5.3 一个完整的本周决策跑批
# 本周三仓位(来自 Day 41 paper trade 开仓)
positions = [
ShortPutPosition("F", 10.0, date(2026, 6, 20), 0.18, 9.40, 0.65, roll_count=0),
ShortPutPosition("BAC", 38.0, date(2026, 6, 20), 0.42, 38.6, 0.18, roll_count=0),
ShortPutPosition("SOFI", 8.5, date(2026, 6, 20), 0.22, 9.10, 0.04, roll_count=0),
]
today = date(2026, 6, 19) # 周五前一天
candidate_new_mids = {"F": 0.95, "BAC": 0.55, "SOFI": 0.18}
for p in positions:
act, kind, reason = should_roll(p, today, candidate_new_mids[p.symbol])
print(f"{p.symbol:6s} | act={act} | kind={kind:20s} | {reason}")
预期输出:
F | act=True | kind=roll_out | ITM, net credit $0.28 > 0
BAC | act=False | kind=hold | OTM, let theta accelerate
SOFI | act=True | kind=close_win | profit 82% ≥ 50% rule
六、被 assigned 怎么办:从 Stage 1 走到 Stage 2
冷静比正确更重要。被 assigned 不是失败,是 Wheel 策略计划内的状态切换。
6.1 Assignment 当天发生什么
周五 16:00 EST option 到期,ITM 触发 assignment
周五夜 / 周六 OCC 处理,broker 收到通知
周一开盘前 你的账户里:
- 现金 -= strike × 100 × contracts
- 股票 += 100 × contracts 股
- short put position 消失
- 这单 P&L 锁定: (premium_received - intrinsic_at_assign) × 100
心理上需要重置:你不再是「卖方期权 trader」,你是「股票持有者」。仓位逻辑、风险来源、Greeks 全部变了。
6.2 Greeks 的突变
这是新手最容易被打懵的点。
| 状态 | Delta | Gamma | Theta | Vega |
|---|---|---|---|---|
| Short Put(assignment 前) | +0.25 | -0.05 | +0.03 (收) | -0.10 |
| 100 股股票(assignment 后) | +1.00 | 0 | 0 | 0 |
Delta 从 +0.25 跳到 +1.00 = 4 倍敞口放大。如果 F 再跌 $1:
- Assignment 前:put 损失约 $0.25 × 100 = $25
- Assignment 后:股票损失约 $1.00 × 100 = $100
所以 Wheel 策略书里反复强调一句话——只对你愿意以 strike 价拿货的股票卖 CSP。这条规则的全部含义就在这个 Greeks 突变里。
6.3 Stage 2 立刻挂 CC
被 assigned 后不要 hold 等反弹,按计划立刻挂 CC:
# pseudo-code
def on_assignment(symbol, assignment_price, shares=100):
# Stage 2: 我们现在持有股票
# Stage 3: 立刻挂 Covered Call
target_cc_strike = round(assignment_price * 1.05, 1) # +5%
target_expiry = next_monthly_expiry(today, days=30) # 30d out
target_delta = 0.20 # 20Δ CC,被 called away 概率约 20%
cc_contract = find_option_by_delta(
symbol, target_expiry, right="C", target_delta=target_delta
)
place_order(
action="SELL",
contract=cc_contract,
order_type="LMT",
limit=cc_contract.mid * 0.98, # 略低于 mid 提高成交率
)
挂 CC 的两个考虑点:
- Strike ≥ assignment_price:永远不要在亏损价位 cap upside。这是 Wheel 策略的纪律——CC strike 必须 ≥ 你的 cost basis(即被 assigned 的 strike 减去原始收到的 premium)
- Delta 0.15-0.25:太高被 called away 概率高,太低 premium 太薄。20Δ 是 sweet spot
七、Avoidance Pattern:Roll 死循环
最多 Roll 2 次。第 3 次强制接货。
为什么?因为 Roll 在心理上是甜的——「我没亏,只是推迟」。但推迟亏损不等于不亏损,而且持续的 Roll 会绑死资金、累积手续费、且每次都假设「下个月会反弹」。这种假设连续做 3 次错的概率不低。
7.1 死循环长什么样
Month 1: 卖 F $10 Put 收 $0.18
Month 1 到期前: F = $9.40,Roll Out 到 Month 2,net +$0.28
Month 2 到期前: F = $9.10,Roll Out 到 Month 3,net +$0.15
Month 3 到期前: F = $8.80,Roll Down 到 Month 4 $9 strike,net -$0.05
Month 4 到期前: F = $8.20,深 ITM,Roll 已经做不出 net credit
↑
这时被迫接货 = 在更差的位置被迫接货
VS
如果 Month 2 就接货:
以 $10 接货,cost basis = $10 - $0.18 - $0.28 = $9.54
立刻挂 CC,开始 Stage 3 收 CC premium
4 个月下来即使 F 在 $8.80 也有 CC premium 缓冲
结构性洞察:Roll 死循环和企业里的「展期保命」是同一个 anti-pattern——把不良债务一次次展期,最后变成更深的坏账。金融 PM 应该天然对「无限延期」敏感。
7.2 实操规则
| 条件 | 强制动作 |
|---|---|
| 同一 underlying 累计 Roll ≥ 2 次 | 不论 net credit 多少,下次到期 ITM → 强制接货 |
| 累计 Roll 1 次但 ITM 深度 > 5% strike | 同上 |
| Roll 时被迫 net debit | 不 Roll,立刻接货 |
这三条对应到代码就是 should_roll() 顶部那段 avoidance check。写代码的时候把这些纪律编码进逻辑层,比靠人执行可靠 10 倍。
八、CC 端的 Roll:和 CSP 端不一样
Wheel 的下半段是 Covered Call。CC 端的 Roll 决策逻辑相反但结构相同。
| 维度 | CSP 端 | CC 端 |
|---|---|---|
| 触发 Roll 的方向 | 股票跌了,put ITM | 股票涨了,call ITM |
| Roll 的恐惧 | 不想接货(cash 转股票) | 不想被 called away(股票转 cash) |
| 偏好的 Roll 类型 | Roll Out / Roll Down | Roll Out / Roll Up |
| 死循环风险 | 越 Roll 越深套 | 越 Roll 越追不上股价 |
8.1 CC ITM 的两种结局
CC F 06/20 $11,F 涨到 $11.50
选择 A: 让它被 called away
→ 卖出 100 股 @ $11
→ 收到 $1100 现金 + 已收的 CC premium
→ 重新进 Wheel Stage 1: 卖新 CSP
选择 B: Roll Up + Roll Out
→ BTC F 06/20 $11,STO F 07/18 $12
→ 保留股票,多收一点 net credit(可能很小)
→ 但如果 F 继续涨到 $12.50,下月又要做同样决策
我的纪律:CC ITM 默认走 A——让它被 called away。理由:Wheel 的设计就是「Stage 3 末端兑现盈利,回到 Stage 1」。如果你不舍得让 CC 被 called away,那当初就不应该卖 CC。
唯一的例外:股票有 ex-dividend 临近,被 called away 会损失股息。这时 Roll Out 跨越除息日有意义。
8.2 CC OTM 临近 expiry
CC F 06/20 $11,F 还在 $10.20,CC 深 OTM
→ 让它过期(零费用、最大 premium 收入)
→ 周一开盘卖下个月的 CC
这种状态就是 Wheel 的「理想轨道」——CC 持续过期,股票不变,每个月稳定收 premium。
九、本周 Paper Trade 三仓位的实际决策
Day 41 paper trade 开了三个 CSP(基于 Day 28-32 因子合成挑出的低 IV rank、低估值仓位)。今天是 6/21,距离 6/20 周五到期只有一天,正好走一遍决策树。
9.1 F 仓位:CSP ITM → Roll Out
仓位: Short Put F 06/20 $10 收 $0.18 (Day 41 开仓)
当前: F = $9.40,put mid = $0.65 (ITM $0.60 + extrinsic $0.05)
DTE: 1 天
Roll 候选: F 07/18 $10 mid = $0.95
Net credit = 0.95 - 0.65 - 0.013 commission - 0.02 spread = +$0.247
roll_count = 0
→ should_roll() = True, action="roll_out"
→ 决策: Roll Out 到 07/18 $10,预期 net credit ≈ $24.70
→ 更新 roll_count = 1
PM 视角的反思:F 跌 8% 是因为整体周期股回调,不是 F 公司基本面变化。基本面没崩 → Roll 一个月给市场时间消化是合理的。如果是 earnings miss 后跌 8%,决策应该不一样——基本面恶化时不要 Roll,直接接货然后用 CC 慢慢摊低成本。
9.2 BAC 仓位:CSP OTM → 让它过期
仓位: Short Put BAC 06/20 $38 收 $0.42 (Day 41 开仓)
当前: BAC = $38.60,put mid = $0.18
DTE: 1 天
利润比例: (0.42 - 0.18) / 0.42 = 57%
但 DTE < 7 且 OTM → action="let_expire"
(DTE 太短,BTC 成本 > 剩余 extrinsic 收益)
→ 决策: 让它周五过期,0 费用收尾,premium $42 全数到手
经验沉淀:Day 41 当初选 BAC 的理由是「IV rank 38%(适中)+ 大型银行下行有限」。一周后回看,这个判断对了。记下这个 setup → 下次再现时复制。
9.3 SOFI 仓位:CSP 深 OTM → 50% rule?
仓位: Short Put SOFI 06/20 $8.5 收 $0.22 (Day 41 开仓)
当前: SOFI = $9.10,put mid = $0.04
DTE: 1 天
利润比例: (0.22 - 0.04) / 0.22 = 82%
DTE < 7 + 深 OTM → action="let_expire"
50% rule 是 DTE > 21 时的逻辑,此时 close 多此一举
注意一个微妙点:50% rule 的本意是「在 DTE 还长时,提前锁利、释放资金」。DTE 只剩 1 天时,让它过期更优——剩余 $0.04 几乎稳定流入,BTC 反而要付 spread。
十、和 PM 工作的迁移性思考
写完今天这棵决策树,反推到 10 年 PM 的几个隐性经验:
| 场景 | 量化语境 | PM 语境(同构问题) |
|---|---|---|
| 该不该 Roll | 接受亏损 vs 延后兑现 | 该不该展期合同 / 续约低毛利客户 |
| Net Credit 法则 | Roll 必须收钱 | 续约必须让单位经济模型变好(CAC/LTV 改善),否则就是续约亏损 |
| Roll 死循环 | 最多 Roll 2 次 | 不良客户最多让步 2 次,否则结构性亏损 |
| 被 assigned 立刻挂 CC | 接受现状 + 立刻启动下一阶段 | 项目失败后立即开始 retrospective + next-step plan,而不是停滞 |
| 50% rule | 提前兑现部分利润 | 大合同分阶段交付而非全 hold 到验收 |
最深的一条:「兑现损失」是金融人最难做的动作之一,因为它把账面亏损变成已实现亏损,心理代价大。但所有 Roll 的最坏路径都是「延期被迫兑现,且兑现得更深」。早接受 = 早脱困。这不是量化独有,是所有损失认知问题的共性。
十一、Day 1-42 的整合视角
到 Day 43,Wheel 策略所需的零件都齐了:
| Day | 提供的能力 |
|---|---|
| Day 1-10 | IBKR / Paper / Python / ib_insync |
| Day 11-20 | Greeks / IV / 期权链查询 / 风险敞口 |
| Day 21-27 | CSP / CC 单独操作 / Wheel Stage 1-3 |
| Day 28-32 | 因子合成挑选标的 |
| Day 33-40 | IV rank 过滤 / 仓位 sizing / 组合层 Greeks |
| Day 41 | 三仓位 paper trade 开仓 |
| Day 43(今天) | Roll 决策树 + ITM 处理 |
明天 Day 44 是 Wheel 第一周复盘,把今天的决策结果记录下来,开始累积「我自己的 setup 表现库」——这才是个人量化最值钱的资产。
十二、明日预告
Day 44: Wheel 第一周复盘 — Setup 库初版
- 三仓位实际成交回顾(F Roll 成本 / BAC 过期 / SOFI 过期)
- P&L 拆解:premium 收入 / Greek pnl / 滑点 / 佣金
- IV rank vs 实际 IV 路径:开仓时的 IV 假设有没有兑现
- 第一版 setup 库表设计:标的、IV rank 区间、Δ、DTE、净 premium、结局
- 失败 setup 的迭代规则:什么样的开仓条件下周不复制
- 对应代码:
wheel/journal.py把 IBKR 成交流水转换成 setup 评估表
实际执行记录
启动一项填一项,时间戳 + 卡点。
- [hh:mm] should_roll() 函数写完 + 三仓位跑过 dry-run
- [hh:mm] execute_roll() combo order 在 paper 上跑通(F 仓位)
- [hh:mm] Roll combo 实际成交价 vs mid 估算偏差记录
- [hh:mm] BAC / SOFI 周五过期确认(0 佣金收尾)
- [hh:mm] 更新
wheel/positions.csv—— F 仓位 roll_count = 1 - 卡点 / 学到的:
总字数:约 6,200 字 今日完成度:理论 ✓ / 代码(dry-run) ✓ / 实操(Roll 成交结果待 paper trade 周五前) / 笔记 ✓