Files
web-page-backend/stock-lab/API_SPEC.md
gahusb a826e00399 feat(stock): NXT 시간외 거래가를 정규장 마감 후 자동 연결
네이버 모바일 주식 API의 overMarketPriceInfo를 인식해 NXT 프리/애프터마켓
운영 중이면 overPrice를 current_price로 자동 전환. 포트폴리오 응답에
price_session(REGULAR/NXT_PRE/NXT_AFTER/CLOSED)과 price_as_of 메타 동봉.

이전엔 closePrice만 사용해 15:30 이후 NXT 거래가 진행 중이어도 평가금액이
동결됐음. 이제 가격이 자연스럽게 이어짐. _select_price_from_response는
순수 함수로 분리, unittest 8케이스로 회귀 방지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 19:32:10 +09:00

5.5 KiB
Raw Permalink Blame History

📈 Stock Lab API Specification

프론트엔드 연동을 위한 주식 서비스 API 명세서입니다.

Base URL: /api


1. 💰 계좌 잔고 조회

현재 연결된 한국투자증권 계좌의 잔고와 보유 종목을 조회합니다.

  • URL: /trade/balance
  • Method: GET
  • Description: Windows AI Server를 통해 실시간 잔고를 가져옵니다.

Response Example

{
  "holdings": [
    {
      "code": "005930",
      "name": "삼성전자",
      "qty": 10,
      "buy_price": 72000.0,
      "current_price": 74500.0,
      "profit_rate": 3.47
    }
  ],
  "summary": {
    "total_eval": 15400000,
    "deposit": 5000000,
    "note": "정상 조회됨"
  }
}

2. 🤖 AI 자동 매매 (분석/주문)

AI에게 현재 잔고와 뉴스를 기반으로 매매 판단을 요청합니다.

  • URL: /trade/auto
  • Method: POST
  • Description: 분석에는 수 초~수십 초가 소요될 수 있습니다. (타임아웃 주의)

Response Example (성공 - JSON 파싱 완료)

{
  "status": "success",
  "decision": {
    "action": "BUY",
    "ticker": "000660",
    "quantity": 10,
    "reason": "반도체 업황 개선 뉴스 다수 포착 및 현금 비중 과다"
  },
  "trade_result": {
    "success": true,
    "order_no": "1234567"
  }
}

Response Example (실패 - AI가 JSON을 안 줬을 때)

AI가 말로 설명하느라 JSON 포맷을 어긴 경우입니다. raw_response를 화면에 그대로 보여주는 것을 권장합니다.

{
  "status": "failed_parse",
  "raw_response": "잔고 현황을 분석해 보겠습니다...\n결정:\n```\n{\n ... \n}\n```"
}

Frontend 처리 권장사항: statusfailed_parse라면 raw_response 텍스트를 pre 태그 등으로 그대로 노출하거나, 정규식으로 JSON 부분만 추출하여 보여주세요.


3. 📰 뉴스 조회

DB에 저장된 최신 뉴스를 조회합니다.

  • URL: /stock/news
  • Method: GET
  • Params:
    • limit: 개수 (기본 20)
    • category: domestic (국내) | overseas (해외)

Response Example

[
  {
    "id": 105,
    "title": "삼성전자, 3분기 영업익 2.4조... 전년비 77% 감소",
    "link": "https://n.news.naver.com/...",
    "published_at": "2024-09-25T09:00:00",
    "sentiment": "negative"
  }
]

4. 📊 지수 조회

KOSPI, KOSDAQ 등 주요 지수를 조회합니다.

  • URL: /stock/indices
  • Method: GET

Response Example

{
  "KOSPI": {
    "value": "2450.55",
    "change": "-10.23",
    "percent": "-0.42%"
  },
  "USD/KRW": {
    "value": "1340.50",
    "change": "5.00",
    "percent": "0.37%"
  }
}

5. 📂 포트폴리오 (수동 입력)

KB증권·삼성증권 등 Open API 미제공 증권사용. 보유 종목을 수동 등록하면 현재가는 네이버 금융에서 자동 조회 (3분 캐시)하여 손익을 계산해 반환합니다.


5-1. 전체 조회

  • URL: GET /portfolio
  • Description: 등록된 모든 종목의 현재가·평가금액·손익을 포함하여 반환합니다.

Response

{
  "holdings": [
    {
      "id": 1,
      "broker": "KB증권",
      "ticker": "005930",
      "name": "삼성전자",
      "quantity": 100,
      "avg_price": 72000,
      "current_price": 74500,
      "price_session": "NXT_AFTER",
      "price_as_of": "2026-05-11T19:21:40+09:00",
      "eval_amount": 7450000,
      "profit_amount": 250000,
      "profit_rate": 3.47
    }
  ],
  "summary": {
    "total_buy": 7200000,
    "total_eval": 7450000,
    "total_profit": 250000,
    "total_profit_rate": 3.47
  }
}

주의: 현재가 조회에 실패한 종목은 current_price, eval_amount, profit_amount, profit_ratenull로 반환됩니다. 프론트에서 null 체크 후 "조회 실패" 등으로 표시해 주세요.

현재가 출처(price_session): 정규장 마감 후 NXT 시간외 거래가 진행 중이면 NXT 가격으로 자동 전환됩니다.

  • REGULAR — KRX 정규장 진행중(09:0015:30) 실시간 가격
  • NXT_PRE — NXT 프리마켓(08:0008:50) 거래가
  • NXT_AFTER — NXT 애프터마켓(15:3020:00) 거래가
  • CLOSED — 모든 세션 마감, 정규장 종가 노출

price_as_of는 가격이 마지막으로 형성된 시각(ISO 8601, KST). HTML 폴백 경로에서는 null일 수 있음.


5-2. 종목 추가

  • URL: POST /portfolio
  • Status: 201 Created

Request Body

{
  "broker": "KB증권",
  "ticker": "005930",
  "name": "삼성전자",
  "quantity": 100,
  "avg_price": 72000
}
필드 타입 설명
broker string 증권사명 (자유 입력)
ticker string 종목 코드 6자리
name string 종목명
quantity integer 보유 수량
avg_price integer 평균 매입가 (원)

Response

{ "id": 1, "ok": true }

5-3. 종목 수정

  • URL: PUT /portfolio/{id}
  • Description: 변경할 필드만 포함하면 됩니다 (부분 수정).

Request Body (모든 필드 Optional)

{ "quantity": 150 }

Response

{ "ok": true }

Error (존재하지 않는 id)

{ "error": "Item not found" }   // HTTP 404

5-4. 종목 삭제

  • URL: DELETE /portfolio/{id}

Response

{ "ok": true }

Error (존재하지 않는 id)

{ "error": "Item not found" }   // HTTP 404