Files
olsch01 b7d4e900cc 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>
2026-04-09 14:38:25 -04:00

47 lines
1.5 KiB
Python

from fastapi import APIRouter, Depends, Header, HTTPException, Query
from sqlalchemy.orm import Session
from app.database import get_db
from app.models.db_models import Device, Alert
from app.models.schemas import AlertResponse
router = APIRouter(prefix="/alerts", tags=["alerts"])
def _get_device(x_device_token: str = Header(...), db: Session = Depends(get_db)) -> Device:
device = db.query(Device).filter(Device.apns_token == x_device_token).first()
if not device:
raise HTTPException(status_code=404, detail="Device not registered.")
return device
@router.get("", response_model=list[AlertResponse])
def get_alerts(
unread_only: bool = Query(False),
device: Device = Depends(_get_device),
db: Session = Depends(get_db),
):
query = db.query(Alert).filter(Alert.device_id == device.id)
if unread_only:
query = query.filter(Alert.acknowledged == False) # noqa: E712
return query.order_by(Alert.sent_at.desc()).limit(100).all()
@router.patch("/{alert_id}/acknowledge", response_model=AlertResponse)
def acknowledge_alert(
alert_id: int,
device: Device = Depends(_get_device),
db: Session = Depends(get_db),
):
alert = (
db.query(Alert)
.filter(Alert.id == alert_id, Alert.device_id == device.id)
.first()
)
if not alert:
raise HTTPException(status_code=404, detail="Alert not found.")
alert.acknowledged = True
db.commit()
db.refresh(alert)
return alert