# CandleRepository

캔들 데이터 테이블 동적 생성, UPSERT, 조회.

## CandleRepository

Symbol의 is_unified()에 따라 통합/개별 테이블 자동 관리. 가격은 int64로 저장 (x10^8).

### Properties
PRICE_SCALE: int = 100_000_000  # 가격 변환 스케일

### Methods

to_storage(price: float) -> int  # staticmethod
    float 가격을 int64로 변환 (x 10^8).

from_storage(value: int) -> float  # staticmethod
    int64를 float 가격으로 복원 (/ 10^8).

get_or_create_table(conn: Connection, symbol) -> Table
    symbol.get_table_name()으로 테이블 조회/생성.
    통합 테이블: symbol_id 컬럼 포함, (symbol_id, timestamp) 복합 PK.
    개별 테이블: timestamp PK.

upsert(conn: Connection, symbol, data: Union[dict, list[dict]]) -> None
    raise NotImplementedError
    MySQL INSERT ON DUPLICATE KEY UPDATE.
    MySQL 외 DB는 NotImplementedError.

query_to_dataframe(conn: Connection, symbol, symbol_id: int = None, start_ts: int = None, end_ts: int = None) -> pd.DataFrame
    raise ValueError
    통합 테이블에서 symbol_id 없으면 ValueError.
    가격 컬럼 자동 from_storage 변환.

table_exists(conn: Connection, symbol) -> bool
    테이블 존재 여부 확인.

get_last_timestamp(conn: Connection, symbol, symbol_id: int = None) -> int
    raise ValueError
    마지막 timestamp 조회. 통합 테이블에서 symbol_id 필수.

get_first_timestamp(conn: Connection, symbol, symbol_id: int = None) -> int
    raise ValueError
    첫 timestamp 조회. 통합 테이블에서 symbol_id 필수.

count(conn: Connection, symbol, symbol_id: int = None) -> int
    raise ValueError
    레코드 수 조회. 통합 테이블에서 symbol_id 필수.

has_data(conn: Connection, symbol, symbol_id: int = None) -> bool
    데이터 존재 여부. count() > 0.
