Initial implementation of Options Sidekick

Full-stack iOS options trading assistant:
- Python FastAPI backend with SQLite, APScheduler (15-min position monitor),
  APNs push notifications, and yfinance market data integration
- Signal engine: IV Rank (rolling HV proxy), SMA-50/200, swing-based
  support/resistance, earnings detection, signal strength scoring and
  noise-resistant SHA hash for change detection
- Recommendation engine: covered call and cash-secured put strike/expiry
  selection across 0DTE, 1DTE, weekly, and monthly horizons
- REST API: /devices, /portfolio, /recommendations, /positions, /signals, /alerts
- iOS SwiftUI app (iOS 17+): dashboard, recommendations, trades, portfolio,
  and alerts tabs with push notification deep-linking
- Unit + integration tests for signal engine and API layer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 14:38:25 -04:00
commit b7d4e900cc
61 changed files with 4953 additions and 0 deletions

38
backend/app/scheduler.py Normal file
View File

@@ -0,0 +1,38 @@
"""
scheduler.py — APScheduler configuration.
The scheduler is started in main.py's lifespan event.
"""
import asyncio
import logging
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.interval import IntervalTrigger
from app.config import settings
logger = logging.getLogger(__name__)
scheduler = AsyncIOScheduler()
def start_scheduler():
from app.services.position_monitor import monitor_all_positions
scheduler.add_job(
monitor_all_positions,
trigger=IntervalTrigger(seconds=settings.monitor_interval_seconds),
id="position_monitor",
name="Position Monitor",
replace_existing=True,
misfire_grace_time=60,
)
scheduler.start()
logger.info(f"Scheduler started — monitor interval: {settings.monitor_interval_seconds}s")
def stop_scheduler():
if scheduler.running:
scheduler.shutdown(wait=False)
logger.info("Scheduler stopped")