penti/backend/app/api/v1/portfolios.py

180 lines
4.5 KiB
Python

"""Portfolio API endpoints."""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import Optional
from uuid import UUID
from app.database import get_db
from app.schemas.portfolio import (
PortfolioCreate,
PortfolioUpdate,
PortfolioResponse,
PortfolioListResponse
)
from app.services.rebalancing_service import PortfolioService
router = APIRouter()
@router.post("/", response_model=PortfolioResponse, status_code=status.HTTP_201_CREATED)
async def create_portfolio(
portfolio: PortfolioCreate,
user_id: Optional[str] = None,
db: Session = Depends(get_db)
):
"""
포트폴리오 생성.
Args:
portfolio: 포트폴리오 생성 요청
user_id: 사용자 ID (선택)
db: 데이터베이스 세션
Returns:
생성된 포트폴리오
"""
try:
assets_data = [
{'ticker': asset.ticker, 'target_ratio': asset.target_ratio}
for asset in portfolio.assets
]
created_portfolio = PortfolioService.create_portfolio(
name=portfolio.name,
description=portfolio.description,
assets=assets_data,
user_id=user_id,
db_session=db
)
return created_portfolio
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"포트폴리오 생성 오류: {str(e)}"
)
@router.get("/{portfolio_id}", response_model=PortfolioResponse)
async def get_portfolio(
portfolio_id: UUID,
db: Session = Depends(get_db)
):
"""
포트폴리오 조회.
Args:
portfolio_id: 포트폴리오 ID
db: 데이터베이스 세션
Returns:
포트폴리오
"""
portfolio = PortfolioService.get_portfolio(portfolio_id, db)
if not portfolio:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="포트폴리오를 찾을 수 없습니다"
)
return portfolio
@router.get("/", response_model=PortfolioListResponse)
async def list_portfolios(
user_id: Optional[str] = None,
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db)
):
"""
포트폴리오 목록 조회.
Args:
user_id: 사용자 ID (필터)
skip: 건너뛸 레코드 수
limit: 최대 레코드 수
db: 데이터베이스 세션
Returns:
포트폴리오 목록
"""
result = PortfolioService.list_portfolios(db, user_id, skip, limit)
return result
@router.put("/{portfolio_id}", response_model=PortfolioResponse)
async def update_portfolio(
portfolio_id: UUID,
portfolio: PortfolioUpdate,
db: Session = Depends(get_db)
):
"""
포트폴리오 수정.
Args:
portfolio_id: 포트폴리오 ID
portfolio: 포트폴리오 수정 요청
db: 데이터베이스 세션
Returns:
수정된 포트폴리오
"""
try:
assets_data = None
if portfolio.assets:
assets_data = [
{'ticker': asset.ticker, 'target_ratio': asset.target_ratio}
for asset in portfolio.assets
]
updated_portfolio = PortfolioService.update_portfolio(
portfolio_id=portfolio_id,
name=portfolio.name,
description=portfolio.description,
assets=assets_data,
db_session=db
)
if not updated_portfolio:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="포트폴리오를 찾을 수 없습니다"
)
return updated_portfolio
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(e)
)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"포트폴리오 수정 오류: {str(e)}"
)
@router.delete("/{portfolio_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_portfolio(
portfolio_id: UUID,
db: Session = Depends(get_db)
):
"""
포트폴리오 삭제.
Args:
portfolio_id: 포트폴리오 ID
db: 데이터베이스 세션
"""
success = PortfolioService.delete_portfolio(portfolio_id, db)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="포트폴리오를 찾을 수 없습니다"
)