feat(stock): watchlist CRUD + 알람 이력 API

This commit is contained in:
2026-07-02 15:45:14 +09:00
parent 01a8aee226
commit 89c52b1fb6
2 changed files with 58 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ from .db import (
upsert_broker_cash, get_all_broker_cash, delete_broker_cash,
upsert_asset_snapshot, get_asset_snapshots,
add_sell_history, get_sell_history, update_sell_history, delete_sell_history,
add_watchlist, remove_watchlist, get_watchlist, get_alert_history,
)
from .scraper import fetch_market_news, fetch_major_indices
from .price_fetcher import get_current_prices, get_current_prices_detail
@@ -653,6 +654,41 @@ def remove_sell_history(record_id: int):
return {"ok": True}
# --- Watchlist & Trade Alerts API (실시간 매매 알람) ---
class WatchlistItemRequest(BaseModel):
ticker: str
name: str | None = None
note: str | None = None
@app.get("/api/stock/watchlist")
def list_watchlist():
"""관심종목 목록 조회"""
return {"watchlist": get_watchlist()}
@app.post("/api/stock/watchlist", status_code=201)
def create_watchlist_item(req: WatchlistItemRequest):
"""관심종목 추가 (이미 존재하면 name/note 갱신, 멱등)"""
add_watchlist(req.ticker, req.name, req.note)
return {"ok": True}
@app.delete("/api/stock/watchlist/{ticker}")
def delete_watchlist_item(ticker: str):
"""관심종목 삭제"""
if not remove_watchlist(ticker):
raise HTTPException(status_code=404, detail="not in watchlist")
return {"ok": True}
@app.get("/api/stock/trade-alerts")
def list_trade_alerts(days: int = 7):
"""매매 알람 이력 조회 (최근 N일)"""
return {"alerts": get_alert_history(days)}
# --- Holdings Intelligence API ---
@app.get("/api/stock/holdings/intel")

View File

@@ -0,0 +1,22 @@
import pytest
from fastapi.testclient import TestClient
@pytest.fixture
def client(monkeypatch, tmp_path):
from app import db as _db
monkeypatch.setattr(_db, "DB_PATH", str(tmp_path / "stock.db"))
_db.init_db()
from app.main import app
return TestClient(app)
def test_watchlist_crud(client):
assert client.get("/api/stock/watchlist").json()["watchlist"] == []
r = client.post("/api/stock/watchlist", json={"ticker": "005930", "name": "삼성전자"})
assert r.status_code == 201
wl = client.get("/api/stock/watchlist").json()["watchlist"]
assert wl[0]["ticker"] == "005930"
assert client.delete("/api/stock/watchlist/005930").status_code == 200
assert client.delete("/api/stock/watchlist/005930").status_code == 404
def test_trade_alerts_history_empty(client):
assert client.get("/api/stock/trade-alerts?days=7").json()["alerts"] == []