Files
portfolio-hub/docs/issues/20260524_portfolio-hub-ticket-symbol-in-portfolios.md
T

5.2 KiB

[REQ] GET /v1/portfolios 응답에 종목 코드(symbol) 포함

요약

GET /v1/portfolios 응답의 PortfolioItem 에 종목 코드(symbol) 필드를 추가해주세요. 현재는 asset_id (UUID) 만 반환되어, 종목 코드가 필요한 클라이언트가 별도 카탈로그 조회로 매핑해야 합니다.

배경

trex-orbit 자동매매 데몬은 매 사이클마다 GET /v1/portfolios 로 daemon-scoped portfolio 리스트를 받아 운용 대상 종목을 결정합니다. 이후 외부 데이터 서비스 (kis-data-hub) 에 시세 / 분봉을 요청하려면 종목 코드 (예: "005930") 가 필요한데, 현재 PortfolioItem 에는 asset_id (UUID) 만 있고 symbol 이 빠져 있어 다음 우회가 필요합니다.

  1. trex-orbit 부팅 시 asset 카탈로그를 별도로 조회해 asset_id → symbol 캐시 구성
  2. 사이클 중 asset_id 마다 캐시 lookup
  3. 캐시 미스 시 portfolio-hub 에 추가 조회

이 과정에서 캐시 stale / 신규 asset 등록 후 동기화 지연 / 클라이언트마다 캐시 로직 중복 같은 운영 부담이 발생합니다.

현재 상태

Endpoint: GET /v1/portfolios (app/api/v1_portfolios.py:224)

응답 스키마: PortfolioItem

class PortfolioItem(BaseModel):
    portfolio_id: str
    asset_id: str | None = None    # UUID
    owner_user_id: str | None = None
    broker: str
    status: str
    name: str
    cash_balance: float = 0.0
    asset_quantity: float = 0.0
    price: float = 0.0
    profit_buffer: float = 0.0
    tag_ids: list[str] = Field(default_factory=list)
    managed_by_daemon_id: str | None = None
    created_at: datetime | None = None
    updated_at: datetime | None = None
    # symbol 없음

종목 코드는 별도 AssetItem 에만 존재 (app/schemas/v1.py:55):

class AssetItem(BaseModel):
    asset_id: str
    symbol: str       # ← 여기 있음
    status: str
    ...

요청 변경

1. 스키마

PortfolioItem 에 symbol 필드 추가:

class PortfolioItem(BaseModel):
    portfolio_id: str
    asset_id: str | None = None
    symbol: str | None = None   # ← 추가 요청
    owner_user_id: str | None = None
    ...

2. 응답 채움 로직

GET /v1/portfolios 의 _portfolio_to_item 빌더가 portfolios.asset_id → assets.symbol join 결과를 활용해 symbol 을 채워주세요. 이미 repository 단계에서 join 되어 있다면 변환 로직만 추가하면 됩니다.

3. 단건 / 관련 엔드포인트도 동일 적용

다음 엔드포인트의 응답에도 symbol 포함:

  • POST /v1/portfolios (생성 후 반환)
  • PATCH /v1/portfolios/{portfolio_id}
  • DELETE /v1/portfolios/{portfolio_id} (soft delete 응답)
  • 기타 PortfolioItem 을 반환하는 모든 경로

정당성

  1. 클라이언트 단순화: daemon 클라이언트 (trex-orbit 등) 가 portfolio 정보만 받으면 즉시 외부 시세 API 호출 가능. 추가 카탈로그 조회 / 캐시 관리 불필요.
  2. 일관성: cash_balance, asset_quantity, price 등 자산 관련 필드는 이미 PortfolioItem 에 포함됨. symbol 도 자산 식별의 핵심이므로 같이 포함되는 것이 자연스러움.
  3. stale cache 위험 제거: 클라이언트 캐시 + miss fallback 패턴은 카탈로그 변경 시 일시적 불일치 가능. server 측 join 으로 항상 최신 매핑 제공.
  4. 운영 부담 감소: 캐시 무효화 / 갱신 / 재로드 로직이 클라이언트마다 중복 구현되는 것을 회피.

호환성

symbol 은 신규 필드이며 Optional[str] 로 추가하면 기존 클라이언트에 영향 없음 (additive change).

영향 범위

검수 기준

  1. GET /v1/portfolios 호출 시 각 item 에 symbol 필드가 포함됨
  2. symbol 값은 해당 asset_id 의 AssetItem.symbol 과 일치 (server side join)
  3. 단건 조회 / 생성 / 수정 / 삭제 응답도 동일하게 symbol 포함
  4. interface-contract.md 의 GET /v1/portfolios 응답 예시에 symbol 명시
  5. 기존 테스트 회귀 없음 + 신규 케이스 추가

우선순위

Medium — trex-orbit 사이드에서 캐시 기반 우회가 가능해 즉시 차단 이슈는 아니지만, 운영 본격 시작 전 정리하면 lifecycle 비용을 크게 줄임.

관련 문서

  • trex-orbit temp/plan.md 8.4.1 step 3 (asset_id → symbol resolve) — 본 이슈의 우회 구현 단계
  • trex-orbit temp/plan.md 8.6.4.1 전제 시점 — universe 결정 과정에서 symbol resolve 가 필요한 이유

작성자 / 일자