chore: 작업 중 발생한 부수적 변경 사항 및 누락된 파일 전체 커밋
- 프론트엔드 UI 업데이트 (backtest.html, backtest.js) 엔진 라디오 버튼 통합 관련 반영 - Rust 플러그인(kis_rust_core) 및 컴파일 소스코드 추가 - CLI 백테스트 스크립트 수정 및 최신화 - 기타 스크래치 테스트 스크립트, 로그 요약 마크다운(.md) 등 누락 파일 일괄 반영 - 추가적으로 아직 발견되지 않은 엣지 케이스나 렌더링 오류가 포함되어 있을 가능성이 있음
This commit is contained in:
89
kis_trader/utils/export_ticks_parquet.py
Normal file
89
kis_trader/utils/export_ticks_parquet.py
Normal file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
kis_trader/utils/export_ticks_parquet.py
|
||||
DB의 ws_ticks 데이터를 Parquet 파일로 변환하여 디스크에 저장합니다.
|
||||
주기적인 백그라운드 작업이나 On-demand 호출을 위해 설계되었습니다.
|
||||
"""
|
||||
import os
|
||||
import argparse
|
||||
import sys
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
|
||||
from datetime import datetime, timedelta
|
||||
import polars as pl
|
||||
|
||||
from kis_trader.utils.logger import get_logger
|
||||
logger = get_logger("export_ticks_parquet")
|
||||
from database import TradeDB, _DB_HOST, _DB_USER, _DB_PASS, _DB_NAME, _DB_PORT
|
||||
|
||||
# 저장 폴더 경로 설정
|
||||
TICKS_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "data", "ticks"))
|
||||
os.makedirs(os.path.join(TICKS_DIR, "KR"), exist_ok=True)
|
||||
os.makedirs(os.path.join(TICKS_DIR, "US"), exist_ok=True)
|
||||
|
||||
# Polars 용 URI 생성 (connectorx)
|
||||
DB_URI = f"mysql://{_DB_USER}:{_DB_PASS}@{_DB_HOST}:{_DB_PORT}/{_DB_NAME}"
|
||||
|
||||
def export_day(market: str, day: str) -> bool:
|
||||
"""특정 일자의 데이터를 Parquet으로 변환합니다 (day: YYYYMMDD)"""
|
||||
market = market.strip().upper()
|
||||
table = "ws_ticks_us" if market == "US" else "ws_ticks"
|
||||
|
||||
start_str = f"{day}000000"
|
||||
end_str = f"{day}235959"
|
||||
|
||||
# 쿼리 작성 (MariaDB에서 직접 Polars로 로드)
|
||||
query = f"""
|
||||
SELECT code, tick_time, price, volume, source, recv_ts, tick_time_raw
|
||||
FROM {table}
|
||||
WHERE market = '{market}'
|
||||
AND tick_time >= '{start_str}'
|
||||
AND tick_time <= '{end_str}'
|
||||
"""
|
||||
|
||||
out_file = os.path.join(TICKS_DIR, market, f"{day}.parquet")
|
||||
|
||||
try:
|
||||
logger.info(f"[{market}] {day} 틱 데이터 로딩 중... ({table})")
|
||||
# polars의 read_database 사용 (connectorx 백엔드 사용 시 매우 빠름, 기본 adbc)
|
||||
# pip install adbc-driver-mysql 를 권장하지만 일단 pandas 폴백 혹은 pyarrow 활용
|
||||
df = pl.read_database_uri(query, uri=DB_URI)
|
||||
|
||||
if df.height == 0:
|
||||
logger.warning(f"[{market}] {day} 데이터가 없습니다.")
|
||||
return False
|
||||
|
||||
logger.info(f"[{market}] {day} 로딩 완료 ({df.height} rows). Parquet 저장 시작...")
|
||||
df.write_parquet(out_file)
|
||||
logger.info(f"[{market}] {day} Parquet 저장 완료: {out_file}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"[{market}] {day} Parquet 저장 실패: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="틱 데이터 Parquet 익스포터")
|
||||
parser.add_argument("--market", type=str, default="KR", help="마켓 (KR/US)")
|
||||
parser.add_argument("--start", type=str, help="시작일 (YYYY-MM-DD)")
|
||||
parser.add_argument("--end", type=str, help="종료일 (YYYY-MM-DD)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.start or not args.end:
|
||||
logger.error("start 와 end 인자가 필요합니다.")
|
||||
return
|
||||
|
||||
try:
|
||||
start_dt = datetime.strptime(args.start, "%Y-%m-%d")
|
||||
end_dt = datetime.strptime(args.end, "%Y-%m-%d")
|
||||
except Exception as e:
|
||||
logger.error(f"날짜 형식 오류: {e}")
|
||||
return
|
||||
|
||||
cur_dt = start_dt
|
||||
while cur_dt <= end_dt:
|
||||
day_str = cur_dt.strftime("%Y%m%d")
|
||||
export_day(args.market, day_str)
|
||||
cur_dt += timedelta(days=1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user