# Architecture - KRXProvider

## 개요

KRX OpenAPI (openapi.krx.co.kr) 기반 한국 주식 캔들 데이터 수집 Provider.
기존 KRXFallbackProvider(FinanceDataReader 기반)의 상위 대체.
API 키 유무에 따라 자동 전환.

## Provider 전환 흐름

```mermaid
graph TB
    Registry[ProviderRegistry]
    KRX[KRXProvider<br/>KRX OpenAPI]
    Fallback[KRXFallbackProvider<br/>FinanceDataReader]

    Registry -->|KRX_API_KEY 있음| KRX
    Registry -->|KRX_API_KEY 없음<br/>NoApiKeyError catch| Fallback
```

## KRX API 특성과 대응

```mermaid
graph LR
    subgraph "KRX API (date-centric)"
        API["GET /sto/stk_bydd_trd<br/>?basDd=20240115"]
        Response["전종목 시세<br/>(KOSPI 2000+ 종목)"]
        API --> Response
    end

    subgraph "IProvider (symbol-centric)"
        Fetch["fetch(삼성전자, start, end)"]
        Result["삼성전자 캔들 데이터"]
        Fetch --> Result
    end

    subgraph "KRXProvider 내부"
        DateLoop["영업일 반복"]
        Cache["_date_cache<br/>dict[YYYYMMDD, list]"]
        Filter["ISU_CD == 005930<br/>필터링"]

        DateLoop -->|캐시 미스| API
        DateLoop -->|캐시 히트| Cache
        Response --> Cache
        Cache --> Filter
        Filter --> Result
    end

    Fetch --> DateLoop
```

## 날짜별 캐시의 필요성

KRX API는 "한 날짜의 전 종목"을 반환하므로,
active_update에서 N개 종목을 처리할 때 캐시 유무가 결정적.

| 시나리오 | 캐시 없음 | 캐시 있음 |
|---------|----------|----------|
| 1종목 x 250일 | 500회 (KOSPI+KOSDAQ) | 500회 (최초) |
| 2000종목 x 250일 | 1,000,000회 (불가) | 500회 (캐시 히트) |

일 10,000회 제한에서 캐시는 필수.

## fetch() 시퀀스

```mermaid
sequenceDiagram
    participant Caller
    participant KRXProvider
    participant Cache as _date_cache
    participant API as KRX OpenAPI
    participant Norm as NormalizationService

    Caller->>KRXProvider: fetch(symbol, start_at, end_at)

    KRXProvider->>KRXProvider: _get_business_days(start_at, end_at)

    loop 각 영업일 (YYYYMMDD)
        KRXProvider->>Cache: date_str in cache?

        alt 캐시 미스
            KRXProvider->>API: GET sto/stk_bydd_trd?basDd={date}
            API-->>KRXProvider: KOSPI 전종목
            KRXProvider->>API: GET sto/ksq_bydd_trd?basDd={date}
            API-->>KRXProvider: KOSDAQ 전종목
            KRXProvider->>Cache: 병합 저장
        end

        KRXProvider->>Cache: ISU_CD == symbol.base 필터
    end

    KRXProvider->>Norm: normalize_krx(filtered_data)
    Norm-->>KRXProvider: list[dict]
    KRXProvider-->>Caller: list[dict]
```

## 수정 필요 컴포넌트

### 1. NormalizationService (l3) - normalize_krx 추가

KRX API 응답 필드를 표준 캔들 형식으로 변환:

| KRX 필드 | 표준 필드 | 변환 |
|---------|----------|------|
| BAS_DD | timestamp | YYYYMMDD -> Unix timestamp |
| TDD_OPNPRC | open | string -> float -> to_storage |
| TDD_HGPRC | high | string -> float -> to_storage |
| TDD_LWPRC | low | string -> float -> to_storage |
| TDD_CLSPRC | close | string -> float -> to_storage |
| ACC_TRDVOL | volume | string -> float -> to_storage |

주의: 콤마 포함 가능 ("12,345" -> 12345), 빈 문자열/"-" 처리 필요.

### 2. ApiValidationService (l1) - KRX 서버 URL 추가

```python
self.server_urls = {
    ...
    'KRX': 'https://data-dbg.krx.co.kr/svc/apis/sto/stk_bydd_trd',
}
```

### 3. ProviderRegistry (l5) - Fallback 로직 추가

```
_provider_class_mapping: KRXProvider를 primary로 등록
_fallback_mapping: KRXFallbackProvider를 fallback으로 등록
get_provider_by_key: NoApiKeyError catch -> fallback 전환
```

### 4. 문서 업데이트

- for-agent-layerinfo.md: krx_provider 항목 업데이트
- for-agent-layerinfo-l4.md: KRXProvider 시그니처 추가
- Architecture - CandleDataManager.md: Provider 목록 업데이트

## 환경 설정

```
# .env
KRX_API_KEY=your_krx_api_key_here
```

## 제약 사항

- 일봉(1d)만 지원 (KRX API가 일별 시세만 제공)
- 2010년 이후 데이터만 조회 가능
- 일 10,000회 API 호출 제한
- 비상업적 용도 제한 (KRX OpenAPI 이용약관)
- 당일 데이터 불가 (익일 08:00 업데이트)
