- git mv stock-lab/ → stock/ - docker-compose.yml: 서비스 키 + container_name + build.context + frontend.depends_on + agent-office STOCK_LAB_URL → STOCK_URL - agent-office/app: config.py, service_proxy.py, agents/stock.py, tests/ STOCK_LAB_URL → STOCK_URL - nginx/default.conf: proxy_pass http://stock-lab → http://stock (3 lines) - CLAUDE.md / README.md / STATUS.md / scripts/ 문구 갱신 - stock/ 내부 자기 참조 갱신 lab 네이밍 정책 (feedback_lab_naming.md) graduation. API URL / Python import / DB 파일명 변경 없음.
241 lines
5.5 KiB
Markdown
241 lines
5.5 KiB
Markdown
# 📈 Stock Lab API Specification
|
||
프론트엔드 연동을 위한 주식 서비스 API 명세서입니다.
|
||
|
||
**Base URL**: `/api`
|
||
|
||
---
|
||
|
||
## 1. 💰 계좌 잔고 조회
|
||
현재 연결된 한국투자증권 계좌의 잔고와 보유 종목을 조회합니다.
|
||
|
||
- **URL**: `/trade/balance`
|
||
- **Method**: `GET`
|
||
- **Description**: Windows AI Server를 통해 실시간 잔고를 가져옵니다.
|
||
|
||
### Response Example
|
||
```json
|
||
{
|
||
"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 파싱 완료)
|
||
```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`를 화면에 그대로 보여주는 것을 권장합니다.
|
||
```json
|
||
{
|
||
"status": "failed_parse",
|
||
"raw_response": "잔고 현황을 분석해 보겠습니다...\n결정:\n```\n{\n ... \n}\n```"
|
||
}
|
||
```
|
||
**Frontend 처리 권장사항**: `status`가 `failed_parse`라면 `raw_response` 텍스트를 `pre` 태그 등으로 그대로 노출하거나, 정규식으로 JSON 부분만 추출하여 보여주세요.
|
||
|
||
---
|
||
|
||
## 3. 📰 뉴스 조회
|
||
DB에 저장된 최신 뉴스를 조회합니다.
|
||
|
||
- **URL**: `/stock/news`
|
||
- **Method**: `GET`
|
||
- **Params**:
|
||
- `limit`: 개수 (기본 20)
|
||
- `category`: `domestic` (국내) | `overseas` (해외)
|
||
|
||
### Response Example
|
||
```json
|
||
[
|
||
{
|
||
"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
|
||
```json
|
||
{
|
||
"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
|
||
```json
|
||
{
|
||
"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_rate` 가 `null`로 반환됩니다.
|
||
> 프론트에서 `null` 체크 후 `"조회 실패"` 등으로 표시해 주세요.
|
||
|
||
> **현재가 출처(`price_session`)**: 정규장 마감 후 NXT 시간외 거래가 진행 중이면 NXT 가격으로 자동 전환됩니다.
|
||
> - `REGULAR` — KRX 정규장 진행중(09:00–15:30) 실시간 가격
|
||
> - `NXT_PRE` — NXT 프리마켓(08:00–08:50) 거래가
|
||
> - `NXT_AFTER` — NXT 애프터마켓(15:30–20:00) 거래가
|
||
> - `CLOSED` — 모든 세션 마감, 정규장 종가 노출
|
||
>
|
||
> `price_as_of`는 가격이 마지막으로 형성된 시각(ISO 8601, KST). HTML 폴백 경로에서는 `null`일 수 있음.
|
||
|
||
---
|
||
|
||
### 5-2. 종목 추가
|
||
|
||
- **URL**: `POST /portfolio`
|
||
- **Status**: `201 Created`
|
||
|
||
#### Request Body
|
||
```json
|
||
{
|
||
"broker": "KB증권",
|
||
"ticker": "005930",
|
||
"name": "삼성전자",
|
||
"quantity": 100,
|
||
"avg_price": 72000
|
||
}
|
||
```
|
||
|
||
| 필드 | 타입 | 설명 |
|
||
|------|------|------|
|
||
| `broker` | string | 증권사명 (자유 입력) |
|
||
| `ticker` | string | 종목 코드 6자리 |
|
||
| `name` | string | 종목명 |
|
||
| `quantity` | integer | 보유 수량 |
|
||
| `avg_price` | integer | 평균 매입가 (원) |
|
||
|
||
#### Response
|
||
```json
|
||
{ "id": 1, "ok": true }
|
||
```
|
||
|
||
---
|
||
|
||
### 5-3. 종목 수정
|
||
|
||
- **URL**: `PUT /portfolio/{id}`
|
||
- **Description**: 변경할 필드만 포함하면 됩니다 (부분 수정).
|
||
|
||
#### Request Body (모든 필드 Optional)
|
||
```json
|
||
{ "quantity": 150 }
|
||
```
|
||
|
||
#### Response
|
||
```json
|
||
{ "ok": true }
|
||
```
|
||
|
||
#### Error (존재하지 않는 id)
|
||
```json
|
||
{ "error": "Item not found" } // HTTP 404
|
||
```
|
||
|
||
---
|
||
|
||
### 5-4. 종목 삭제
|
||
|
||
- **URL**: `DELETE /portfolio/{id}`
|
||
|
||
#### Response
|
||
```json
|
||
{ "ok": true }
|
||
```
|
||
|
||
#### Error (존재하지 않는 id)
|
||
```json
|
||
{ "error": "Item not found" } // HTTP 404
|
||
```
|