返回交易笔记
TR Day 42

IBKR Paper — 第一组 Wheel 实战

Staggered expiry 设计、thesis-first 下单纪律、保证金 buffer、限价滑点观测

2026-06-20
Phase 2: 策略实战 + AI 信号
WheelPaperTradeFirstTradeCSPStaggeredExpiryGreyscaleIBKR

日期: 2026-06-20 方向: Phase 2 / Wheel 实战 阶段: Phase 2: 策略实战 + AI 信号 标签: #Wheel #PaperTrade #FirstTrade #CSP #StaggeredExpiry #Greyscale #IBKR


今日目标

类型内容
学习Staggered expiry 设计、thesis-first 下单纪律、保证金 buffer、限价滑点观测
实操IBKR Paper 真实开 3 张 CSP(F / BAC / SOFI),形成第一个完整 wheel portfolio
产出TR-DAY42 笔记 + setup_wheel.py + 3 张 thesis 卡 + 监控阈值表 + 当日复盘

关键纪律:今天不是「试一下能不能下单」,是正式上线第一组真实 wheel 仓位——只是钱是 Paper 的。流程、风控、文档全部按实盘要求执行。


一、为什么是「3 张 + Stagger」:灰度发布的产品思维

我做 PM 10 年的本能:不要一次性把所有用户切到新版本

把这个本能搬到交易上:

一次开 10 张 CSP一次开 3 张 CSP(stagger)
一个市场事件全员中枪至少 2/3 还在 OTM 缓冲区
同一天大批 assigned,现金占用暴增expiry 错开,assignment 分摊
操作流程没经过验证就上量第一周专注流程正确性
心理压力 3×心理压力可控
出错回滚成本高出错只动一张

核心认知:第一周的目标不是「赚最多 premium」,是验证我设计的下单→监控→roll→close 的全流程在 Paper 上不会断。把这 7 天当成「灰度发布期」,week 4 才考虑扩到 6-8 张。

1.1 Stagger Expiry 的具体设计

标的当前价DTEStrikeDeltaPremium 估现金占用
F (Ford)~$10.0030$9.00-0.30~$0.18$900
BAC (Bank of America)~$35.0035$33.00-0.25~$0.50$3,300
SOFI~$12.0040$11.00-0.30~$0.32$1,100
合计Net Δ +45~$100~$5,300

Net Delta 计算:short 1 张 put 的 delta = -(-0.30) × 100 = +30;同理 BAC = +25,SOFI = +30;考虑 contract multiplier 后 delta 单位是「等价股数」,故 Net Δ ≈ +85 等价股。简化为「+45 directional units」是把 100 multiplier 拆开来感知方向暴露的口径,下文统一用 directional units。

Stagger 的本质:3 张 expiry 分别在 T+30 / T+35 / T+40,意味着任意一天最多一张需要 roll/close/接货决策——决策分散 = 错误风险分散。如果 3 张都 T+30 同一天,遇到周五大跌就要同时处理 3 个 ITM put,操作压力会让人乱来。

1.2 标的选择的逻辑

维度FBACSOFI
行业周期/汽车大型银行Fintech
流动性极高极高
期权链周度 + 月度周度 + 月度周度 + 月度
接货后是否愿持✓ 股息 5%+✓ 大盘金融✓ 增长但波动大
与已有持仓相关性与 BAC 中性与 F 0.4与 BAC 0.6

承认问题:BAC 和 SOFI 同属金融板块,相关性偏高,真实组合应该选一个非金融来分散(如 CSCO / KO / T)。但作为 Day 42 的第一组——复杂度优先于完美度,先跑通三张 stagger 流程,下周再优化标的篮子。


二、Thesis-First:每张单子都必须先写下「为什么愿意接货」

这是这个交易体系最重要的一条纪律:任何 CSP 下单前,先用一句话写下「我愿意以 strike 价持有这只股票 N 天的理由」

为什么?因为没有 thesis 的开仓,事后必然 rationalize

  • 跌了 → 「啊我本来就是想接货」(其实没想过)
  • 涨了 → 「啊我看准了」(其实是运气)
  • 横盘 → 「啊我赚 theta」(如果真这么想为什么不直接做 IC)

写下 thesis 后,复盘时可以做事前 vs 事后对比,这是唯一能积累 alpha 的机制。

2.1 三张 Thesis 卡

┌──────────────────────────────────────────────────────────────┐
│ TRADE #1: F 30DTE 9P @ $0.18                                 │
│                                                              │
│ Thesis:                                                      │
│   "I am willing to own F at $9 for the next 30 days because  │
│    (1) F trades at 0.7× book value at $9, near 10-yr low    │
│    (2) 6%+ dividend yield at $9 entry, covers theta decay   │
│    (3) EV transition narrative已 priced-in,downside有限    │
│    (4) Q3 earnings 已过,无重大事件窗口"                     │
│                                                              │
│ Invalidation:                                                │
│   - 油价跌破 $60(消费者下行风险传导)                       │
│   - 美国汽车贷款违约率 >7%                                   │
│   - 联储意外加息 50bps                                       │
│                                                              │
│ Plan if assigned: 转 CC,strike $10,覆盖成本基础            │
└──────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────┐
│ TRADE #2: BAC 35DTE 33P @ $0.50                              │
│                                                              │
│ Thesis:                                                      │
│   "I am willing to own BAC at $33 for 35 days because        │
│    (1) BAC P/B 0.95×,大型银行历史均值 1.1×                  │
│    (2) Q3 财报已确认 NIM 企稳,前向 PE 9×                   │
│    (3) $33 = 200日均线 + 主要支撑位                          │
│    (4) 期权链流动性好,IV rank 35%(不算贵但有 premium)    │
│                                                              │
│ Invalidation:                                                │
│   - 区域银行再爆雷(SVB 2.0)                                │
│   - 联储意外鸽派砸 yield curve(NIM 压力)                   │
│   - 商业地产违约率超预期                                     │
│                                                              │
│ Plan if assigned: 持有等股息,CC 卖 $35                      │
└──────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────┐
│ TRADE #3: SOFI 40DTE 11P @ $0.32                             │
│                                                              │
│ Thesis:                                                      │
│   "I am willing to own SOFI at $11 for 40 days because       │
│    (1) Q3 首次 GAAP 盈利已确认,预期 Q4 延续                 │
│    (2) $11 = IPO 后第二根支撑趋势线                          │
│    (3) 学生贷款业务因联邦政策利好                            │
│    (4) IV rank 60%(高),premium 收益相对厚                 │
│                                                              │
│ Invalidation:                                                │
│   - Q4 财报指引下修                                          │
│   - Tech sell-off > 10%                                      │
│   - 利率重新预期上调(fintech 估值压力)                     │
│                                                              │
│ Plan if assigned: 持有,CC 卖 $12,平均权益基础 $10.68       │
└──────────────────────────────────────────────────────────────┘

Thesis 卡的设计要点

  1. 正向 thesis(为什么 OK)+ Invalidation 条件(什么时候认错)+ 接货后计划——三段缺一不可
  2. Invalidation 必须是可观测的市场信号,不能是「感觉不对」这种主观词
  3. 接货后计划写出来防止 assigned 时手忙脚乱

三、ib_insync 下单流程:从 dry-run 到真实成交

3.1 流程图

[1] connect Paper (port 7497, assert)
       ↓
[2] qualify contracts (3 个 option contract)
       ↓
[3] 取 live quote → 计算 mid price
       ↓
[4] 检查保证金 buffer < 95%
       ↓
[5] dry-run 打印订单详情 → 人工确认
       ↓
[6] sell to open (LMT @ mid)
       ↓
[7] 监听 orderStatus / execDetails event
       ↓
[8] 5 分钟未 fill → 退一档 mid+0.01 重挂
       ↓
[9] 全部 fill → 写入本地 trade journal

3.2 完整代码:setup_wheel.py

# setup_wheel.py
"""
Day 42 — Open first wheel basket on IBKR Paper.

3 staggered CSPs: F 30DTE 9P / BAC 35DTE 33P / SOFI 40DTE 11P
"""

from ib_insync import IB, Stock, Option, LimitOrder, util
from dataclasses import dataclass, field
from datetime import datetime, date
from typing import Optional
import json
import sys
from pathlib import Path

# ─────────────────────────────────────────────────────────────
# 配置
# ─────────────────────────────────────────────────────────────

PAPER_PORT = 7497         # TWS Paper port — NEVER use 7496 (live)
CLIENT_ID  = 42           # 用 Day 编号当 clientId,方便排查
MARGIN_BUFFER = 0.95      # 保证金占用不超过 95%
JOURNAL_PATH = Path("./trade_journal.jsonl")


@dataclass
class WheelCandidate:
    symbol: str
    target_strike: float
    target_dte: int
    target_delta: float
    thesis: str

    # 运行时填充
    underlying_price: Optional[float] = None
    chosen_expiry: Optional[str] = None
    contract: Optional[Option] = None
    mid_price: Optional[float] = None
    margin_required: Optional[float] = None
    order: Optional[LimitOrder] = None


CANDIDATES = [
    WheelCandidate(
        symbol="F",
        target_strike=9.0,
        target_dte=30,
        target_delta=0.30,
        thesis="F at $9 = 0.7× book, 6%+ div yield, EV narrative priced-in",
    ),
    WheelCandidate(
        symbol="BAC",
        target_strike=33.0,
        target_dte=35,
        target_delta=0.25,
        thesis="BAC at $33 = 0.95× P/B, 200DMA support, NIM stabilized",
    ),
    WheelCandidate(
        symbol="SOFI",
        target_strike=11.0,
        target_dte=40,
        target_delta=0.30,
        thesis="SOFI at $11 = post-IPO trendline, first GAAP profit Q3",
    ),
]


# ─────────────────────────────────────────────────────────────
# 步骤 1: 安全连接
# ─────────────────────────────────────────────────────────────

def connect_paper() -> IB:
    ib = IB()
    ib.connect("127.0.0.1", PAPER_PORT, clientId=CLIENT_ID)

    # 护栏 1: 必须是 Paper port
    assert ib.client.port == PAPER_PORT, f"WRONG PORT {ib.client.port} — PAPER ONLY"

    # 护栏 2: account ID 应以 DU 开头(Paper account 约定)
    accounts = ib.managedAccounts()
    assert all(a.startswith("DU") for a in accounts), \
        f"REFUSED: non-paper account detected: {accounts}"

    print(f"[OK] Connected to Paper {accounts} on port {PAPER_PORT}")
    return ib


# ─────────────────────────────────────────────────────────────
# 步骤 2: 寻找最接近 target delta 的 strike
# ─────────────────────────────────────────────────────────────

def find_target_option(ib: IB, cand: WheelCandidate) -> Option:
    """从期权链里挑最接近 target_delta 且最接近 target_dte 的 put。"""

    # 取 underlying 现价
    stk = Stock(cand.symbol, "SMART", "USD")
    ib.qualifyContracts(stk)
    ticker = ib.reqMktData(stk, "", snapshot=True)
    ib.sleep(2)
    cand.underlying_price = ticker.marketPrice() or ticker.last
    print(f"[{cand.symbol}] spot = ${cand.underlying_price:.2f}")

    # 取期权链
    chains = ib.reqSecDefOptParams(stk.symbol, "", stk.secType, stk.conId)
    smart_chain = next(c for c in chains if c.exchange == "SMART")

    # 选最接近 target_dte 的 expiry
    today = date.today()
    def dte(exp_str):
        return (datetime.strptime(exp_str, "%Y%m%d").date() - today).days

    valid_expiries = [e for e in smart_chain.expirations if dte(e) > 7]
    chosen = min(valid_expiries, key=lambda e: abs(dte(e) - cand.target_dte))
    cand.chosen_expiry = chosen
    print(f"[{cand.symbol}] chose expiry {chosen} (DTE={dte(chosen)})")

    # 在 target_strike 附近选 strike(简化:直接用 target_strike)
    # 实盘版本应该 reqMktData 多个 strike 拿 greeks,找 delta 最接近 -0.30
    opt = Option(
        symbol=cand.symbol,
        lastTradeDateOrContractMonth=chosen,
        strike=cand.target_strike,
        right="P",
        exchange="SMART",
        currency="USD",
    )
    ib.qualifyContracts(opt)

    # 拿 quote
    opt_ticker = ib.reqMktData(opt, "", snapshot=True)
    ib.sleep(2)
    bid, ask = opt_ticker.bid, opt_ticker.ask
    if bid is None or ask is None or bid <= 0 or ask <= 0:
        raise ValueError(f"[{cand.symbol}] no valid quote: bid={bid} ask={ask}")
    mid = round((bid + ask) / 2, 2)
    cand.mid_price = mid
    cand.contract = opt

    print(f"[{cand.symbol}] {cand.target_strike}P @ bid={bid} ask={ask} mid={mid}")
    return opt


# ─────────────────────────────────────────────────────────────
# 步骤 3: 保证金 / cash secured 检查
# ─────────────────────────────────────────────────────────────

def check_margin(ib: IB, cands: list[WheelCandidate]) -> bool:
    """Cash-secured put: 保证金 = strike × 100 - premium received。
    检查总占用 < 95% 账户净值。"""
    summary = ib.accountSummary()
    net_liq = float(next(s.value for s in summary if s.tag == "NetLiquidation"))

    total_required = sum(
        (c.target_strike * 100 - c.mid_price * 100) for c in cands
    )
    for c in cands:
        c.margin_required = c.target_strike * 100 - c.mid_price * 100

    pct = total_required / net_liq
    print(f"\n[MARGIN] required ${total_required:,.0f} / net liq ${net_liq:,.0f} = {pct:.1%}")

    if pct > MARGIN_BUFFER:
        print(f"[FAIL] exceeds {MARGIN_BUFFER:.0%} buffer — REFUSED")
        return False
    print(f"[OK] within {MARGIN_BUFFER:.0%} buffer")
    return True


# ─────────────────────────────────────────────────────────────
# 步骤 4: Dry-run + 确认
# ─────────────────────────────────────────────────────────────

def dry_run(cands: list[WheelCandidate]) -> bool:
    print("\n" + "=" * 60)
    print("DRY RUN — Review before submitting")
    print("=" * 60)
    for c in cands:
        print(f"\n  SELL TO OPEN  {c.symbol}  {c.chosen_expiry} {c.target_strike}P")
        print(f"  Limit:        ${c.mid_price}  (mid)")
        print(f"  Premium:      ${c.mid_price * 100:,.0f}")
        print(f"  Cash needed:  ${c.margin_required:,.0f}")
        print(f"  Thesis:       {c.thesis}")
    print("\n" + "=" * 60)
    resp = input("Submit all 3 orders? [y/N]: ").strip().lower()
    return resp == "y"


# ─────────────────────────────────────────────────────────────
# 步骤 5: 提交 + 监听 fill
# ─────────────────────────────────────────────────────────────

def submit_orders(ib: IB, cands: list[WheelCandidate]):
    trades = []
    for c in cands:
        order = LimitOrder("SELL", 1, c.mid_price, tif="DAY")
        c.order = order
        trade = ib.placeOrder(c.contract, order)
        trades.append((c, trade))
        print(f"[SUBMIT] {c.symbol} {c.target_strike}P @ ${c.mid_price}")

    # 等待 60 秒,看 fill 情况
    print("\nWaiting up to 60s for fills...")
    for _ in range(60):
        ib.sleep(1)
        if all(t.orderStatus.status == "Filled" for _, t in trades):
            break

    # 报告
    print("\n" + "=" * 60)
    print("FILL REPORT")
    print("=" * 60)
    for c, t in trades:
        st = t.orderStatus
        fill_px = st.avgFillPrice if st.avgFillPrice else "—"
        print(f"  {c.symbol}: status={st.status}  filled@{fill_px}  remaining={st.remaining}")

        # 写 journal
        record = {
            "ts": datetime.now().isoformat(),
            "symbol": c.symbol,
            "strike": c.target_strike,
            "expiry": c.chosen_expiry,
            "right": "P",
            "action": "SELL_TO_OPEN",
            "limit_price": c.mid_price,
            "fill_price": st.avgFillPrice,
            "status": st.status,
            "thesis": c.thesis,
        }
        with JOURNAL_PATH.open("a") as f:
            f.write(json.dumps(record) + "\n")

    return trades


# ─────────────────────────────────────────────────────────────
# Main
# ─────────────────────────────────────────────────────────────

def main():
    ib = connect_paper()
    try:
        for cand in CANDIDATES:
            find_target_option(ib, cand)

        if not check_margin(ib, CANDIDATES):
            sys.exit("Margin check failed")

        if not dry_run(CANDIDATES):
            print("Aborted by user.")
            return

        submit_orders(ib, CANDIDATES)
    finally:
        ib.disconnect()


if __name__ == "__main__":
    main()

3.3 代码里的几个产品级 pattern

Pattern体现位置为什么重要
多层 assertionconnect_paper() 双重护栏误连实盘是最严重的事故,要 fail-fast
Dry-run 默认开dry_run() 必须人工 y 才继续防止脚本被误触发自动下单
预算护栏check_margin() 总仓位 < 95%留 5% buffer 给意外
结构化 journal写 jsonl,便于后续 SQL/pandas 分析没有 journal 等于没复盘
明确单一职责函数connect / find / check / dry_run / submit 分离调试时可单步

四、Portfolio State:第一天结束时该长什么样

下单全部成交后,组合的 Greeks snapshot:

维度数值含义
持仓-1 F 9P / -1 BAC 33P / -1 SOFI 11P3 张 short put
Net Delta+85 directional units轻度 long bias,相当于持 85 股一篮子
Net Theta~+$15/day每天「应该」收到约 $15 时间衰减(含周末)
Net Vega~-$40/% IVIV 上升 1 个百分点会 mark-to-market 亏 $40
Net Gamma-2.5delta 反向变化敏感度,跌得越多 long bias 越强
现金占用~$5,300接近上限(建议账户调到 $5,500 给点 buffer)
未实现 P&L~$0(开仓即 -spread/2)实际开盘瞬间因 bid-ask spread 略亏

4.1 Greeks 的解读和心理预期

+85 Delta:
  → SPY +1% 时组合 mark-to-market ≈ +$85
  → 这是个 "微微看多" 的姿态,符合 CSP 卖方本质

+$15 Theta/day:
  → 30 天满吃 = $450 premium
  → 实际能到 50-70%(提前 close 或部分 assigned)
  → 真实预期净收入 ~$225-$315 / 月

-$40 Vega:
  → IV 暴涨 10% 会 mark-to-market 亏 $400
  → 但这是「未实现」损失,到期前是浮动的
  → 重要:这就是 CSP 的核心痛点——你赚 theta 但卖空 vol

心态校准:开仓第一周 mark-to-market 大概率是负的(bid-ask spread + IV 波动),不要看一天浮亏就慌。CSP 是要持有到接近 expiry 才能确认 theta 收益的策略。


五、监控阈值表:什么时候做什么

把规则写出来,远比脑子里想着「我会注意的」靠谱 1000 倍。

触发条件阈值动作决策依据
单一标的暴跌spot < -10%重新读 thesis 卡看 invalidation 条件是否触发
Thesis invalidatedinvalidation 命中Close to close(即使亏损)纪律高于侥幸
Premium 缩到 50%premium ≤ 0.5 × 开仓价Close to take profit50% rule:风险收益比恶化
Premium 缩到 80%premium ≤ 0.2 × 开仓价必须 close留着的下行风险大于上行
DTE ≤ 7 + OTMdistance > 5% OTMLet expire收尽 final theta
DTE ≤ 7 + ATM/ITMstrike 附近 ±2%决定 roll vs accept看 thesis 是否还成立
DTE ≤ 2 + ITM深度 ITMAccept assignment接货转 CC,进 wheel 后半段
IV 暴涨 > 30%IV rank +30 in 1 day检查是否 close + 等 IV 回落再开卖方在 vol spike 中开仓更值
账户 drawdown> -10% MTD暂停开新仓强制冷静期

5.1 50% Rule 的数学直觉

为什么 premium 缩到 50% 就该 close?

开仓:  收 $0.50 premium, 当时风险 = ~$2.50 (max loss assumption)
       风险报酬比 = 0.50 / 2.50 = 20%

3 周后: premium 缩到 $0.25
       剩余可赚 = $0.25
       剩余风险 ≈ 仍然接近 $2.50(gamma 增加,DTE 减少)
       新的风险报酬比 = 0.25 / 2.50 = 10%

→ 同等风险下能赚的钱减半,应该 close 再去开新一张更厚 premium 的

这是「Theta Harvest 论」的核心——总是持有最厚 premium / 最低剩余风险的合约


六、常见首日坑(提前列出)

6.1 限价挂错位

错误做法:直接挂 bid(永远不成交)
错误做法:直接挂 ask(被 MM 立刻 take,相当于 market order)
正确做法:mid,5 分钟未成交 → mid - 0.01(卖方 perspective: 降一档让步)
         再不成 → mid - 0.02,最多让 3-4 档
         若让到 bid 附近还不成 → 当天放弃,明天再来

6.2 保证金 buffer 被吃光

IBKR 的 maintenance margin 是动态的——你晚上下单时账户 $5,000,盘前 SOFI 跌 5%,第二天保证金需求飙升,IBKR 直接拒下一单(甚至 force close)。

对策

  • 永远保留 5-10% buffer
  • 不要在临近收盘前下满仓单(隔夜 gap 风险)
  • 大事件(FOMC / CPI)前一天不要把仓位开满

6.3 clientId 冲突

ConnectionRefusedError / "clientId already in use"

原因:之前的脚本没正常 disconnect,TWS 还认为这个 clientId 被占用。

对策

  • 始终用 try: ... finally: ib.disconnect() 包裹
  • 关键脚本固定 clientId(如 setup_wheel.py 用 42),告警类脚本用 200+
  • 实在不行重启 TWS(最后大招)

6.4 期权链没数据

如果你订了 OPRA 但报价仍然 bid=-1.0,几种可能:

  • 市场未开盘(盘前盘后期权链多数没报价)
  • 这个 strike 没成交,IBKR 不给虚拟 quote
  • 期权快到期(< 1 DTE,多数券商收紧报价)

对策:选 流动性最好的 monthly expiry(第 3 个周五),不要碰冷门 weekly。

6.5 同时下 3 张,第 2 张被拒

如果第一张 fill 后保证金占用提升,第 2 张的 pre-trade margin check 可能失败。

对策:在 check_margin() 时把所有 3 张当一个整体算保证金,而不是顺序下单顺序检查。


七、第一天复盘 Prompt(晚上写)

每天结束前用这套模板自问,写在 journal 里,不写就没复盘。

## TR-Day42 复盘

### 1. 流程是否跑通?
- [ ] connect_paper 成功(assertion 全部通过)
- [ ] 3 张报价都拿到了
- [ ] 保证金 check 通过
- [ ] dry-run 看着合理
- [ ] 3 张全 fill 了吗?滑点多少?

### 2. 滑点观测(基础项)
| Symbol | Mid | Fill Px | Slip (bps) |
|--------|-----|---------|------------|
| F 9P   | 0.18 | ?      | ?          |
| BAC 33P| 0.50 | ?      | ?          |
| SOFI 11P| 0.32 | ?      | ?          |

期权 mid 滑点正常 5-10%(vs bid-ask spread),> 20% 要怀疑挂单时机。

### 3. Greeks 实际 vs 预期
- 预期 Net Delta ≈ +85,实际 ?
- 预期 Net Theta ≈ +$15/day,实际 ?
- 偏差大说明 strike 选错了或 delta 估算偏差

### 4. Thesis 是否还成立?
- F: 收盘后看油价、利率、汽车行业新闻 — 任何 invalidation 触发?
- BAC: 区域银行有无新雷?
- SOFI: 利率预期变化?

### 5. 明天的 watch list
- 哪张 P&L 异常?
- 哪张接近某个 invalidation 边缘?
- 周五是否有大事件(FOMC / CPI / earnings)?

### 6. 我今天做错了什么?(强制写一条)
(哪怕是「太晚下单了,最后 15 分钟流动性差」也要写)

### 7. 我明天会改什么?
(具体到一行代码或一个步骤)

八、PM 视角:今天学到的迁移性思考

  1. 灰度发布 = 风险即时反馈:先开 3 张,问题在小规模暴露。这跟做产品上线先放 5% 流量是同一个道理——没有可观测的小规模运行,不要直接全量
  2. Thesis 卡 = 决策审计:把开仓理由 + invalidation 写下来,等于给自己留了一份 ADR(Architecture Decision Record)。事后复盘有原始判断可对比,不会被 hindsight bias 污染——对应产品工作里的「假设记录文档」
  3. Dry-run + 人工确认:自动化不等于无人值守。自动化好的系统反而保留更多 explicit 人工 checkpoint,因为它知道 critical path 需要人。
  4. Journal 是 alpha 的真实来源:单笔交易盈亏不重要,能不能从 100 笔交易里识别出「我系统性地在 X 情况下做错」才是。这是「Observability 优先级 > 性能」在交易场景的体现
  5. 保证金 buffer 是产品的「容量水位线」:把 95% 当上限不是物理限制,是给「未知未知」留 headroom。做支付系统设计「不让账户余额跑到 0」是同一逻辑

九、明日预告

Day 43: Roll 操作 — 当 CSP 进入 challenge 区域时怎么办

  • Roll down / roll out / roll down-and-out 三种基本动作
  • 怎么算 roll 的「净 credit」是不是值得
  • 什么时候应该 roll,什么时候应该 accept assignment
  • 写一个 roll_csp.py 工具:输入现有头寸 → 推荐 roll target 期权
  • 案例:模拟 F 跌到 $8.80,9P 进入 ITM,演示完整 roll 决策
  • 心理纪律:roll 不是「治疗亏损」,是「重新表达 thesis」

实际执行记录

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

  • [hh:mm] 启动 TWS Paper,确认端口 7497
  • [hh:mm] 跑 python setup_wheel.py — connect_paper 通过
  • [hh:mm] F 报价 spot=? mid=? 滑点=?
  • [hh:mm] BAC 报价 spot=? mid=? 滑点=?
  • [hh:mm] SOFI 报价 spot=? mid=? 滑点=?
  • [hh:mm] 保证金 check:required=$? net_liq=$? pct=?
  • [hh:mm] Dry-run 确认 — 是否调整
  • [hh:mm] 3 张全部 fill / 部分 fill / 未 fill
  • [hh:mm] trade_journal.jsonl 写入成功
  • [hh:mm] 拉取实际 Greeks vs 预期对比
  • [hh:mm] 复盘 prompt 7 条全部写完
  • 卡点 / 学到的:

总字数:约 7,200 字 今日完成度:理论 ✓ / 实操(执行 setup_wheel.py + 3 张 fill)/ 笔记 ✓