Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 71 additions & 4 deletions .claude/scripts/sprint-metrics.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,62 @@
# bash .claude/scripts/sprint-metrics.sh item-complete <item-id>
# bash .claude/scripts/sprint-metrics.sh cycle <item-id>
# bash .claude/scripts/sprint-metrics.sh rework <item-id>
# bash .claude/scripts/sprint-metrics.sh phase <phase-name>
# bash .claude/scripts/sprint-metrics.sh status <item-id> <value>
# bash .claude/scripts/sprint-metrics.sh finalize
#
# `phase` and `status` auto-initialize the metrics file when it is absent
# (sprint id parsed from SPRINT.md's "**Sprint:**" line, fallback "unknown")
# so best-effort callers (sprint-update.sh) never need a prior explicit init.

METRICS_FILE=".sprint-metrics.json"
SPRINT_FILE="SPRINT.md"
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -Iseconds)

die() { echo "Error: $1" >&2; exit 1; }

[ $# -ge 1 ] || die "Usage: sprint-metrics.sh <init|item-start|item-complete|cycle|rework|finalize> [args]"
# Write a fresh metrics file (existing init shape + phases array), parsing the
# sprint id from SPRINT.md when available. Used by phase/status auto-init.
auto_init() {
sprint_id="unknown"
if [ -f "$SPRINT_FILE" ]; then
parsed=$(grep -m1 '^\*\*Sprint:\*\*' "$SPRINT_FILE" | sed 's/^\*\*Sprint:\*\*[[:space:]]*//' | awk '{print $1}' | sed 's/[:,]$//')
[ -n "$parsed" ] && sprint_id="$parsed"
fi
cat > "$METRICS_FILE" <<ENDJSON
{
"sprintId": "${sprint_id}",
"startedAt": "${NOW}",
"completedAt": null,
"phases": [],
"items": [],
"totals": {
"planned": 0,
"completed": 0,
"rework": 0,
"blocked": 0,
"scopeChanges": 0,
"contextCycles": 0
}
}
ENDJSON
}

[ $# -ge 1 ] || die "Usage: sprint-metrics.sh <init|item-start|item-complete|cycle|rework|phase|status|finalize> [args]"

subcmd="$1"
shift

# All commands except init require jq and the metrics file
# All commands except init require jq and the metrics file.
# phase/status auto-init the file when absent (best-effort invocation path).
if [ "$subcmd" != "init" ]; then
command -v jq >/dev/null 2>&1 || die "jq is required for sprint-metrics.sh"
[ -f "$METRICS_FILE" ] || die ".sprint-metrics.json not found — run 'sprint-metrics.sh init <sprint-id>' first"
if [ ! -f "$METRICS_FILE" ]; then
case "$subcmd" in
phase|status) auto_init ;;
*) die ".sprint-metrics.json not found — run 'sprint-metrics.sh init <sprint-id>' first" ;;
esac
fi
fi

case "$subcmd" in
Expand All @@ -35,6 +75,7 @@ case "$subcmd" in
"sprintId": "${sprint_id}",
"startedAt": "${NOW}",
"completedAt": null,
"phases": [],
"items": [],
"totals": {
"planned": 0,
Expand All @@ -61,7 +102,7 @@ ENDJSON
fi
# Add new item and increment planned count
jq --arg id "$item_id" --arg ts "$NOW" '
.items += [{"id": $id, "startedAt": $ts, "completedAt": null, "contextCycles": 0, "reviewFindings": 0, "reworkCount": 0}]
.items += [{"id": $id, "startedAt": $ts, "completedAt": null, "contextCycles": 0, "reviewFindings": 0, "reworkCount": 0, "transitions": []}]
| .totals.planned += 1
' "$METRICS_FILE" > "${METRICS_FILE}.tmp" && mv "${METRICS_FILE}.tmp" "$METRICS_FILE"
else
Expand Down Expand Up @@ -105,6 +146,32 @@ ENDJSON
' "$METRICS_FILE" > "${METRICS_FILE}.tmp" && mv "${METRICS_FILE}.tmp" "$METRICS_FILE"
;;

phase)
[ $# -eq 1 ] || die "Usage: sprint-metrics.sh phase <phase-name>"
phase_name="$1"

jq --arg p "$phase_name" --arg ts "$NOW" '
.phases = ((.phases // []) + [{"phase": $p, "at": $ts}])
' "$METRICS_FILE" > "${METRICS_FILE}.tmp" && mv "${METRICS_FILE}.tmp" "$METRICS_FILE"
;;

status)
[ $# -eq 2 ] || die "Usage: sprint-metrics.sh status <item-id> <value>"
item_id="$1"
status_value="$2"

# Auto-create the item entry (same shape as item-start) on first status,
# then append the transition. totals.planned increments only on creation.
jq --arg id "$item_id" --arg val "$status_value" --arg ts "$NOW" '
(if (.items | any(.id == $id)) then .
else
.items += [{"id": $id, "startedAt": $ts, "completedAt": null, "contextCycles": 0, "reviewFindings": 0, "reworkCount": 0, "transitions": []}]
| .totals.planned += 1
end)
| .items = [.items[] | if .id == $id then .transitions = ((.transitions // []) + [{"status": $val, "at": $ts}]) else . end]
' "$METRICS_FILE" > "${METRICS_FILE}.tmp" && mv "${METRICS_FILE}.tmp" "$METRICS_FILE"
;;

finalize)
jq --arg ts "$NOW" '
.completedAt = $ts
Expand Down
23 changes: 22 additions & 1 deletion .claude/scripts/sprint-update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,24 @@
# bash .claude/scripts/sprint-update.sh sprint-status in-progress

SPRINT_FILE="SPRINT.md"
METRICS_SCRIPT="$(dirname "$0")/sprint-metrics.sh"

die() { echo "Error: $1" >&2; exit 1; }

# Best-effort sprint-metrics emission (observability only). Guarded by jq
# availability and suffixed `|| true` — a metrics failure must NEVER fail the
# SPRINT.md update (the update path is sprint-critical, metrics are not).
emit_metrics() {
if ! command -v jq >/dev/null 2>&1; then
echo "note: jq not found — sprint metrics not recorded" >&2
return 0
fi
[ -f "$METRICS_SCRIPT" ] || return 0
bash "$METRICS_SCRIPT" "$@" >/dev/null 2>&1 || true
}

if [ $# -lt 1 ]; then
die "Usage: sprint-update.sh <status|postmerge|sprint-status> [issue-id] <value>"
die "Usage: sprint-update.sh <status|postmerge|sprint-status|phase> [issue-id] <value>"
fi

subcmd="$1"
Expand Down Expand Up @@ -50,6 +63,8 @@ case "$subcmd" in
print
}
' "$SPRINT_FILE" > "${SPRINT_FILE}.tmp" && mv "${SPRINT_FILE}.tmp" "$SPRINT_FILE"

emit_metrics status "$issue_id" "$new_value"
;;

postmerge)
Expand Down Expand Up @@ -89,6 +104,10 @@ case "$subcmd" in
/^\*\*Status:\*\*/ { print "**Status:** " val; next }
{ print }
' "$SPRINT_FILE" > "${SPRINT_FILE}.tmp" && mv "${SPRINT_FILE}.tmp" "$SPRINT_FILE"

# Recorded in the phases timeline (the metrics script has no sprint-level
# status concept; prefixing keeps it distinguishable from phase names).
emit_metrics phase "sprint-status:$new_value"
;;

phase)
Expand All @@ -107,6 +126,8 @@ case "$subcmd" in
{ print }
' "$SPRINT_FILE" > "${SPRINT_FILE}.tmp" && mv "${SPRINT_FILE}.tmp" "$SPRINT_FILE"
fi

emit_metrics phase "$new_value"
;;

*)
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ config.local.*

# IDE and Editor
.idea/
.vscode/

*.swp
*.swo
Expand Down Expand Up @@ -137,6 +138,7 @@ nul
.sprint-tool-count
.correction-state
.context-usage
.sprint-metrics.json
.quality-gate-pass
.quality-review-result.json
.claude/worktrees/
Expand Down
152 changes: 152 additions & 0 deletions docs/archive/unified-roadmap-2026-04-07.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Unified Trading System Roadmap (Revised 2026-04-07)

## Context

OptiTrade consolidated into TradingSystem. Iron condor backtesting proved the strategy barely breaks even on SPY (+0.07% CAGR) and QC can't reliably simulate SPX (market order fills on illiquid index options). Research spike (April 2026) identified validated patterns, tools, and approaches from the AI trading community that should be incorporated.

## Completed (this session)
- [x] OptiTrade archived (tagged v1.0-archive)
- [x] Backtest pipeline migrated to TradingSystem tools/backtest/
- [x] 3 ADRs recorded (consolidation, dual-mode, iron condor findings)
- [x] Claude regime detection wired with rule-based fallback
- [x] SPX backtest completed and analyzed (QC unsuitable for index options)
- [x] Research spike on AI trading strategies 2026

---

## Phase 1: Foundation Completion (Sprint 1 — 1 week)

**Goal:** Close out Week 10, merge consolidation branch, wire gateway integration.

| Item | Status |
|------|--------|
| PR and merge `feature/consolidate-optitrade` (4 commits) | Ready |
| Route AI calls through Claude Gateway (localhost:3131), fall back to direct API | To do |
| Add Claude API key from Bitwarden to TradingSystem local config | To do |
| Set up Discord server/channel, configure webhook URL | **User action needed** |
| End-to-end orchestrator smoke test in paper mode | To do |
| Gate: build clean, 418+ tests pass, orchestrator runs E2E | |

---

## Phase 2A: Strategy Backtests on SPY (Sprint 2 — 1 week)

**Goal:** Establish per-strategy baselines on QC for strategies that work with SPY options data.

SPX is off the table for QC backtesting (proven unreliable). SPY options are liquid and QC data is good. Run 2-3 targeted backtests:

| Backtest | Rationale |
|----------|-----------|
| Bull put spreads on SPY | Higher frequency than iron condors (bullish/neutral regime only) |
| Covered calls on SPY | Tests premium capture on underlying holdings |
| CSPs on SPY | Tests put-selling expectancy, willing to take assignment |

Each ~60-90 min automated. Any strategy with CAGR > 0% and IS/OOS <= 3pp gets enabled. Failures get disabled.

**Gate:** Per-strategy pass/fail recorded. Enabled strategy list locked for paper validation.

---

## Phase 2B: AI Integration + Research Patterns (Sprint 3 — 1-2 weeks)

**Goal:** Incorporate validated 2026 AI patterns into the system before paper validation.

### Must-do (validated by research)

| Item | Source | What |
|------|--------|------|
| Install QuantConnect MCP server | taylorwilsdon/quantconnect-mcp | Claude iterates backtests via natural language — productivity multiplier |
| Add GEX/gamma exposure as regime signal | aiflowtrader.com pattern | Positive gamma → premium selling safe. Negative gamma → sit out. More actionable than VIX alone for options |
| Wire Claude as conviction filter | Community consensus pattern | Traditional strategy generates signal → Claude scores conviction 0-1.0 → suppress below 0.3. Not a signal generator |
| Install IBKR MCP server (read-only) | Hellek1/ib-mcp or equivalent | Gives Claude visibility into positions/P&L for analysis, not execution |

### Evaluate (promising but lower priority)

| Item | Source | What |
|------|--------|------|
| claude-trading-skills library | tradermonty/claude-trading-skills | 50 skills including Options Advisor, Regime Detector, Position Sizer. Evaluate which are useful |
| Self-improving prompts | Karpathy/ATLAS pattern | Treat regime prompts as optimizable parameters, evolve winners. Evaluate during paper validation |
| Multi-agent debate | TradingAgents pattern | Bull/bear agents argue before final decision. Evaluate for weekly frequency |

### Architecture decisions

| Decision | Choice | Rationale |
|----------|--------|-----------|
| AI call routing | Gateway first (CLI/subscription), fall back to direct API | Cost efficiency, centralized model config |
| AI role | Conviction filter + regime detection | Community consensus: don't predict direction, filter and score |
| Model flexibility | Configurable model, abstract interface | Next-gen frontier model expected ~2-3 months |
| Options regime signal | GEX + VIX combined | GEX is more actionable for options than VIX alone |

**Gate:** Gateway integration tested. GEX signal wired into regime detection. Conviction filter implemented. MCP servers installed and verified.

---

## Phase 3: Paper Validation (12+ weeks, runs in background)

**Goal:** Full system running autonomously in IBKR paper mode.

- Both sleeves active, all enabled strategies running simultaneously
- Regime detection (Claude via gateway + GEX + VIX rules) drives strategy selection
- Conviction filter scores every entry signal
- Risk engine enforces all limits
- Discord alerts for stops, regime changes, daily summaries
- Self-improving prompt evaluation (compare prompt variants for regime detection)

**Configuration for Mode A (alpha-seeking):**
- Sleeve allocation: 50/50 or configurable
- Options sleeve: all strategies that passed QC baseline
- Income sleeve: total return focus (growth + yield), not pure yield
- Position sizing: aggressive within risk limits

**Gate:** 12+ weeks continuous operation, zero hard risk-limit violations, risk telemetry complete, sleeve-level readiness scorecards.

---

## Phase 4: Live Transition (4+ weeks staged)

- Pre-live: runbook, emergency close-all tested, monitoring verified
- Week 1: minimal positions. Weeks 2-4: staged scaling.
- Human approval at each step.

---

## Phase 5: Stabilization (3+ months)

- Monthly performance vs SPY benchmark
- AI ablation study (regime detection on vs off)
- Prompt optimization based on live outcomes
- Revisit model when next-gen frontier model available (~June-July 2026)

---

## Dual-Mode Strategy

### Mode A: Alpha-Seeking (build first, next ~5 years)
- Beat SPY on total return
- Options sleeve is primary alpha engine
- Higher allocation to options (50/50 or 30/70 income/options)
- Aggressive within risk limits

### Mode B: Income + Protection (retirement, 5+ years out)
- 5-8% consistent yield, drawdown protection
- Income sleeve primary, options sleeve conservative
- 70/30 income/options

Both use the same infrastructure, different configuration profiles.

---

## Sprint-Ready Items

**Sprint 1 (next):** Phase 1 Foundation Completion
- Merge consolidation PR
- Gateway integration (ClaudeService → try gateway, fall back to API)
- Claude API key in local config
- Discord setup (user action)
- Smoke test

**Sprint 2:** Phase 2A SPY backtests (bull puts, covered calls, CSPs)

**Sprint 3:** Phase 2B AI integration (QC MCP, GEX regime signal, conviction filter, IBKR MCP)

**Sprint 4+:** Phase 3 paper validation launch and monitoring
Loading