Model Card — Layered Covered Call Income Cycle
Strategy ID: lcc-income-cycle
Status: Ready for feature-dev handoff. OQ-1 through OQ-5 locked 2026-06-05.
Intended Consumer: feature-developer (Raptor/Antlers implementation), software-architect (service design)
Date: 2026-05-05
Last Updated: 2026-06-05
Tracking Issue: #3282
1. What This Strategy Does
The Layered Covered Call Income Cycle is a paper-trading strategy module that manages a share position paired with weekly covered calls distributed across multiple strike zones. The strategy tracks premium income, assignment events, tax-lot selection, and re-entry decisions as explicit, rule-based state transitions.
It is NOT a prediction engine. It does NOT recommend trades. It enforces a pre-committed rule set against a paper-trading position and records what happened.
2. Inputs Required
2.1 Per-Cycle Inputs (provided by the trader, pre-market)
{
"sentiment_label": "string (Neutral | Bullish | Bearish | HighUncertainty)",
"sentiment_committed_at": "string (ISO 8601 date — used for staleness check)",
"ticker": "string",
"options_chain": {
"expiration_date": "string (ISO 8601 date)",
"strikes": [
{
"strike": "number",
"bid": "number",
"ask": "number",
"delta": "number",
"extrinsic": "number"
}
]
},
"underlying_open_price": "number",
"underlying_prior_close": "number"
}
2.2 System State Inputs (maintained by paper-trading engine)
- Current position record (shares, lots, open calls, state)
- Earnings calendar for the next 5 trading days
- VIX daily close (prior day) for gap classification proxy
- Commission config from SimulationConfig
- Per-instance strategy config:
max_roll_debit_pct_of_original_credit,min_shares_threshold(OQ-1, OQ-3)
2.3 Historical Data (for backtest only)
- AMZN daily OHLCV from Alpaca Market Data
- Historical options chain: ORATS or Tradier (confirmed license required)
- CBOE VIX daily series (public)
3. Outputs
3.1 Per-Cycle Outputs
{
"cycle_id": "string (uuid4)",
"sentiment_was_fallback": "boolean (true if staleness fallback applied)",
"proposed_call_structure": [
{"zone": "string (ITM|ATM|OTM)", "contracts": "integer", "target_delta_range": "string"}
],
"opening_sell_timing": {
"market_condition": "string",
"recommended_delay_minutes": "integer",
"reason": "string"
},
"alerts": ["array of Alert objects"],
"re_entry_decision": "ReentryDecision object or null"
}
3.2 Ledger Records (written per event)
EquityLot— on every share acquisitionShortCall— on every call sell, update at closeAssignmentEvent— on every assignment (includesearly_assignment_flag,early_assignment_trigger,operator_early_assignment_selection)Cycle— one per income cycle, closed at expiration (includessentiment_was_fallback)ReentryDecision— one per re-entry evaluationAlert— every alert fired
3.3 Dashboard Metrics (computed on demand from ledger)
See metrics.py for implementations of all 14 metrics.
4. What Can Fail
| Failure | Impact | Detection | Resolution |
|---|---|---|---|
| Options chain data missing for target expiration | Cycle cannot start — no strikes to select | Null check on options_chain input | Surface "chain unavailable" alert; skip cycle |
| Sentiment label stale (>1 market day) | More conservative call structure applied (High-Uncertainty fallback) | STALE_SENTIMENT_LABEL alert |
Strategy continues; operator notified; provide fresh label to override |
| Shares drop below configured N | Cycle blocked; LCC auto-disabled | SHARES_BELOW_MIN_THRESHOLD alert; state=DISABLED |
Operator card: buy shares back + re-enable / reconfigure N / close strategy |
| Roll debit exceeds per-instance threshold | Roll refused; operator must decide | refuse_roll action returned; operator notified |
3-option card: take assignment / close-and-reopen / one-shot override |
| Early assignment (American-style) | State holds at EARLY_ASSIGNMENT_PENDING | early_assignment_flag=True in AssignmentEvent; full-screen card opens |
Operator selects from 4-option card; no autonomous action |
| State machine consistency violation | Naked call recorded, data corruption | NAKED_CALL_DETECTED + STATE_CONSISTENCY_ERROR alerts |
Block all actions; require manual reset |
| Options data vendor outage | Can't price open calls for exit evaluation | Circuit breaker: mark data as stale; surface warning | Hold state; do not auto-act on stale data |
| FIFO lot selection diverges from broker | P/L attribution wrong | Documented known limitation | CPA disclaimer; verify per broker before live |
5. What to Monitor in Production (Phase 3+)
| Metric | Alert Threshold | Frequency |
|---|---|---|
| Consecutive below-cost assignments | ≥3 in 30 days | Per-cycle |
| Consecutive all-ITM weeks | ≥3 | Per-cycle |
| NAKED_CALL_DETECTED alert | Any firing | Real-time |
| SHARES_BELOW_MIN_THRESHOLD alert | Any firing | Real-time |
| EARLY_ASSIGNMENT_PENDING cards unresolved | >4h without operator selection | Real-time |
| STALE_SENTIMENT_LABEL fallback rate | >3 cycles in a rolling 2-week window | Weekly |
| Assignment surprise rate | >20% of assignments were not flagged as "high assignment risk" 24h before | Weekly |
| Premium below minimum rate | >40% of cycles unable to meet minimum premium criterion | Weekly |
| State machine error rate | Any | Real-time |
6. Compute and Storage Budget
| Scale | Compute per Cycle | Storage per Year |
|---|---|---|
| 1 user, 1 ticker | < 10ms (pure Python, no ML) | ~500KB (JSON ledger) |
| 10 users, 1-3 tickers each | < 100ms aggregate | ~5MB |
| 100 users, 1-5 tickers each | < 1s aggregate | ~50MB |
| 1,000 users | Recommend async Celery task per user cycle | ~500MB |
Storage is append-only ledger records. Historical backtest artifacts are stored separately
under docs/data-science/backtests/lcc-income-cycle/ and not part of the per-user runtime storage.
7. Broker Agnosticism
This module is broker-agnostic. It operates on: - Share counts and lot records (internal state) - Options chain data (passed in from whatever data source the platform uses) - Fill confirmation (paper fills provided by the MBT paper-trading engine)
No brokerage vendor name appears in user-facing copy. The broker is plumbing. Raxx is the strategy layer.
For live trading (Phase 4, after paper validation): the paper-trading engine's fill confirmations are replaced by actual broker fill events. The strategy module itself does not change.
8. Regulatory Notes
- This module produces rule-based, pre-committed operational outputs (structured automation) — not personalized investment advice. See
feedback_deterministic_execution_ai_augments.md. - All AI-augmented surfaces (context on prior cycles, pattern flags) are retrospective descriptions of what happened on the user's own simulation data. They do not predict future outcomes. See
feedback_no_forward_looking_framing.md. - Tax-lot simulation is illustrative. The system does not calculate taxes owed. A CPA disclaimer must appear on any UI surface that shows lot-method selection or assignment P/L.
- Options trading involves risk of loss. Paper-trading results do not guarantee live-trading outcomes. This disclaimer must appear in the dashboard.
- Early assignment educational card copy must not be framed as an emergency or error. Per OQ-2 operator intent: "early assignment is sometimes favorable."
9. Implementation Scope for v1 (Phase 1 + 2)
Phase 1 — Manual Paper Sim (minimal Raptor work):
- Data schema (Postgres tables matching data-schema.md; includes OQ-1/OQ-3/OQ-5 schema changes)
- State machine service (Python, deterministic, no ML)
- Alert log table + basic alert surfacing in Antlers dashboard
- AMZN single-ticker support only
Phase 2 — Chain Ingestion + Delta Filters: - Options chain ingestion from Alpaca options API - Delta-based strike selection (pull nearest strike in each zone's delta range) - Earnings calendar check (Alpaca corporate events) - Dashboard metrics (all 14, computed from ledger) - Early assignment educational card (OQ-2 full-screen 4-option flow)
Phase 3 — Recommendations + Alerts + Backtest: - Automated opening bell rule (condition classification, delay logic) - Full alert routing (push notifications for WARNING+; email for CRITICAL) - Roll-refusal operator notification card (OQ-1) - Uncovered-shares operator card (OQ-3) - Backtest runner (Python script, not real-time) - Walk-forward validation report
Phase 4 — Live Broker Integration: - After Phase 3 walk-forward passes - Alpaca live options order submission (or BYOB equivalent) - This phase is out of scope for the current research handoff
10. Key Behavioral Decisions (all locked 2026-06-05)
| Decision | Value |
|---|---|
| Max roll debit | Per-instance config; default 50% of original credit (OQ-1) |
| Early assignment flow | 4-option operator card; no autonomous action; state=EARLY_ASSIGNMENT_PENDING (OQ-2) |
| Shares-below-N behavior | Auto-disable + push + email; 3-option operator card (OQ-3) |
| Sentiment staleness threshold | 1 market day; High-Uncertainty fallback; strategy continues (OQ-4) |
| Tax-lot default | FIFO; per-trade override at order ticket (OQ-5) |
11. Dependencies
| Dependency | Required By | Notes |
|---|---|---|
| Alpaca Market Data API | Phase 1+ | Daily OHLCV, corporate events |
| Alpaca Options API | Phase 2+ | Live options chain; verify options data tier |
| ORATS historical options | Backtest only | License required; do not use without confirmed subscription |
| MBT paper-trading engine | Phase 2+ | Fill simulation; see docs/architecture/mbt-paper-trading-engine.md |
| Postgres + TimescaleDB | Phase 1+ | Ledger storage; workflow UUID tracing per project_workflow_uuid_tracing_decisions.md |
| Push notification service | Phase 2+ | Required for EARLY_ASSIGNMENT_PENDING + SHARES_BELOW_MIN_THRESHOLD real-time alerts |
| Email delivery (Postmark) | Phase 2+ | Required for SHARES_BELOW_MIN_THRESHOLD email alert |
This model card is a research handoff document. It does not constitute investment advice. The strategy described is a paper-trading simulation. Real-world outcomes will differ.