using System.ComponentModel.DataAnnotations; using Domain.Entities.Stocks.ValueObject; namespace Domain.Entities.Stocks; /// /// 지수(시장) 일별 마감 시세 (KRX OpenAPI idx 엔드포인트) — (Series, IndexName, TradeDate) UNIQUE. /// 한 계열(KOSPI/KOSDAQ/KRX) 안에 여러 지수(코스피/코스피200/… )가 존재하므로 IndexName 까지 UQ 에 포함한다. /// 등락률은 정수 보관을 위해 %×100 basis point(Bp)로 저장 (예: -0.70% → -70, 1.45% → 145). /// public class IndexDailyPrice { [Key] public long ID { get; private set; } /// 계열 구분 (1=KOSPI, 2=KOSDAQ, 3=KRX) public MarketIndexSeries Series { get; private set; } /// 지수명 (IDX_NM, 예: "코스피", "코스닥", "KRX 100") public string IndexName { get; private set; } = default!; /// 거래일 (BAS_DD) public DateOnly TradeDate { get; private set; } /// 종가 (CLSPRC_IDX) public decimal Close { get; private set; } /// 전일 대비 (CMPPREVDD_IDX) public decimal ChangeVal { get; private set; } /// 등락률 basis point = %×100 (FLUC_RT) public int FlucRateBp { get; private set; } /// 시가 (OPNPRC_IDX) public decimal Open { get; private set; } /// 고가 (HGPRC_IDX) public decimal High { get; private set; } /// 저가 (LWPRC_IDX) public decimal Low { get; private set; } /// 거래량 (ACC_TRDVOL) public long Volume { get; private set; } /// 거래대금 (ACC_TRDVAL, 원) public long Value { get; private set; } /// 상장시가총액 (MKTCAP, 원) — 미제공 시 null public long? MarketCap { get; private set; } public DateTime CreatedAt { get; private set; } = DateTime.UtcNow; private IndexDailyPrice() { } public static IndexDailyPrice Create( MarketIndexSeries series, string indexName, DateOnly tradeDate, decimal close, decimal changeVal, int flucRateBp, decimal open, decimal high, decimal low, long volume, long value, long? marketCap = null ) { if (!Enum.IsDefined(series)) { throw new ArgumentOutOfRangeException(nameof(series)); } if (string.IsNullOrWhiteSpace(indexName)) { throw new ArgumentException("indexName required", nameof(indexName)); } return new IndexDailyPrice { Series = series, IndexName = indexName.Trim(), TradeDate = tradeDate, Close = close, ChangeVal = changeVal, FlucRateBp = flucRateBp, Open = open, High = high, Low = low, Volume = volume, Value = value, MarketCap = marketCap }; } /// 동일 (Series, IndexName, TradeDate) 재수집 시 값 갱신 (upsert) public void Update( decimal close, decimal changeVal, int flucRateBp, decimal open, decimal high, decimal low, long volume, long value, long? marketCap = null ) { Close = close; ChangeVal = changeVal; FlucRateBp = flucRateBp; Open = open; High = high; Low = low; Volume = volume; Value = value; MarketCap = marketCap; } }