Skip to content

feat: ib-pmcc-bot — operational PMCC bot (scan, open, manage)#76

Open
tradam-m wants to merge 2 commits into
staskh:mainfrom
tradam-m:feat/pmcc-bot-operational
Open

feat: ib-pmcc-bot — operational PMCC bot (scan, open, manage)#76
tradam-m wants to merge 2 commits into
staskh:mainfrom
tradam-m:feat/pmcc-bot-operational

Conversation

@tradam-m

@tradam-m tradam-m commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds ib-pmcc-bot, an operational PMCC bot that turns the existing PMCC scanner into an operator: it scans an equity universe for diagonal-call opportunities, opens the top-N that fit available funds as combo BAG orders, and actively manages its own shorts (buy-to-close + reroll once the premium has decayed past a threshold).

Behaviour

  • Options only — the long leg is always a long call (LEAPS-style), never a future.
  • Margin-gated entry against AvailableFunds (fallback ExcessLiquidity); candidates that don't fit are skipped with an explicit reason.
  • Dedup — symbols already held or with a working bot order are never re-opened (safe for repeated/autonomous runs).
  • Tagged orders (BOT_PMCC_* / BOT_CLOSE_*); exit management touches only equity diagonal-call spreads, so manual futures/stock positions are excluded by construction.
  • Dry-run by default; --execute places orders. Market-hours guard (is_trading_now) blocks off-hours fills on stale quotes.
  • Confirms order status before disconnect — orders placed then dropped on immediate disconnect otherwise.

Files

  • src/trading_skills/broker/pmcc_bot.py — bot logic (pure/testable core + IBKR I/O)
  • .claude/skills/ib-pmcc-bot/ — skill + CLI wrapper (dry-run default, --execute)
  • tests/test_broker_pmcc_bot.py — 16 unit tests (margin gate, exit trigger, sizing, tagging)

Testing

  • 16 new unit tests pass; ruff check/format clean.
  • Verified live on paper (7497): NVDA and MSFT diagonals opened and filled; dedup correctly skips held/pending symbols; off-hours guard respected.
  • Note: the 5 test_mcp_server.py::*_handles_no_connection tests fail only when an IB Gateway is running locally during pytest (known environmental artifact); they pass in CI with no IB.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 8, 2026 17:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds an operational PMCC (Poor Man’s Covered Call) bot and extends the IB option-chain tooling to support futures options (FOP) with model Greeks, plus accompanying CLI/docs/tests.

Changes:

  • Introduce pmcc_bot orchestration (scan → select via margin gate → place combo orders; manage shorts via decay trigger).
  • Add futures/FOP helpers and enhance option-chain extraction (asset-type autodetect, greeks, multiplier).
  • Add unit tests and CLI skill wrappers; bump package version.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/trading_skills/broker/pmcc_bot.py New operational PMCC bot with pure selection/plan logic + IBKR order/position I/O
src/trading_skills/broker/options.py Add futures/FOP support, asset-type resolution, Greeks extraction, and unified quote-row builder
src/trading_skills/broker/futures.py New helpers to detect futures exchange and resolve FOP contracts via contract details
tests/test_broker_pmcc_bot.py Unit tests for PMCC bot pure functions (selection, tagging, decay trigger, plan builder)
tests/test_broker_futures.py Unit tests for futures exchange selection and options greeks/quote extraction helpers
.claude/skills/ib-pmcc-bot/scripts/bot.py CLI wrapper for running the PMCC bot (dry-run default)
.claude/skills/ib-pmcc-bot/SKILL.md Skill documentation for PMCC bot operation and safety model
.claude/skills/ib-option-chain/scripts/options.py Add --sec-type flag passthrough to force stock vs future resolution
.claude/skills/ib-option-chain/SKILL.md Update docs to reflect futures/FOP support + greeks/multiplier fields
pyproject.toml Bump project version to 0.10.0

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

acct = account or (managed[0] if managed else None)

funds = await _available_funds(ib, acct) if acct else {}
available = funds.get("available_funds") or funds.get("excess_liquidity") or 0.0

quote = await _fetch_single_option_quote(ib, symbol, short["strike"], short["expiry"], "C")
current_price = get_option_price(quote or {}, price_mode)
decay = short_decay_pct(premium_received, current_price or 0)
Comment on lines +368 to +372
"premium_received": round(premium_received, 2),
"current_short_price": round(current_price, 2) if current_price else None,
"decay_pct": round(decay * 100, 1),
"action": "close_and_reroll" if close else "hold",
"limit_price": round(current_price, 2) if current_price else None,
"""
try:
async with ib_connection(port, CLIENT_IDS["pmcc_advisor"]) as ib:
ib.reqMarketDataType(4)

return {
"generated_at": generated_at_str(),
"data_delay": "real-time",
Comment thread src/trading_skills/broker/options.py Outdated
Comment on lines +205 to +208
bid = t.bid if t.bid and t.bid > 0 else None
ask = t.ask if t.ask and t.ask > 0 else None
last = t.last if t.last and t.last > 0 else None
volume = int(t.volume) if t.volume and t.volume >= 0 else None
Comment thread src/trading_skills/broker/options.py Outdated
Comment on lines +216 to +220
"impliedVolatility": (
round(t.modelGreeks.impliedVol * 100, 2)
if t.modelGreeks and t.modelGreeks.impliedVol
else None
),
Comment thread src/trading_skills/broker/options.py Outdated
Comment on lines +74 to +80
ib_logger = logging.getLogger("ib_async")
prev_level = ib_logger.level
ib_logger.setLevel(logging.CRITICAL)
try:
qualified = await ib.qualifyContractsAsync(stock)
finally:
ib_logger.setLevel(prev_level)
Comment thread src/trading_skills/broker/futures.py Outdated
Comment on lines +62 to +68
resolved = []
for strike in strikes:
base = FuturesOption(sym, expiry, strike, right, exchange=exchange)
try:
details = await ib.reqContractDetailsAsync(base)
except Exception:
details = []
Comment thread src/trading_skills/broker/options.py Outdated
return greeks


async def _resolve_underlying(ib: IB, symbol: str, sec_type: str | None) -> tuple:
tradam-m and others added 2 commits June 12, 2026 11:35
Scans an equity universe for diagonal-call (PMCC) opportunities, opens the
top-N that fit available funds as combo BAG orders, and actively manages its
own shorts (buy-to-close + reroll once premium has decayed past a threshold).

- Options only: long leg is always a long call, never a future.
- Margin-gated entry against AvailableFunds; dedup skips held/pending symbols.
- Orders tagged BOT_PMCC_* / BOT_CLOSE_*; manages only equity diagonals, so
  manual futures/stock positions are excluded by construction.
- Dry-run by default; --execute places orders. Market-hours guard blocks
  off-hours fills on stale quotes.
- Confirms order status before disconnect (orders placed then dropped on
  immediate disconnect otherwise).
- 16 unit tests for margin gate, exit trigger, sizing, tagging.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tradam-m
tradam-m force-pushed the feat/pmcc-bot-operational branch from d7c8cd3 to 7561534 Compare June 12, 2026 09:36
@tradam-m

Copy link
Copy Markdown
Contributor Author

Ready for review / merge.

  • Rebased onto latest main; the diff is now bot-only (5 files): src/trading_skills/broker/pmcc_bot.py, the ib-pmcc-bot skill + CLI, tests/test_broker_pmcc_bot.py, and the version bump to 0.9.0.
  • No dependency on the unmerged FOP option-chain work — the bot only imports from pmcc_advisor, scanner_pmcc, account, and connection, all already on main.
  • 16 new unit tests pass; ruff check/format clean. The only suite failures are the known test_mcp_server.py::*_handles_no_connection artifact that triggers when an IB Gateway happens to be running locally during pytest — green in CI with no IB.
  • Verified live on paper (7497): NVDA and MSFT diagonals opened and filled, dedup correctly skips held/pending symbols, and the market-hours guard blocks off-hours fills.

Unrelated to #62 (that was time-dependent test rot in test_pmcc_advisor.py, already fixed in c3499d7). Mergeable, no conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants