using System.ComponentModel.DataAnnotations; namespace Domain.Entities.Stocks; /// /// ESG 지수 일별시세 (KRX OpenAPI esg/esg_index_info) — (IndexName, TradeDate) UNIQUE. /// 응답 shape 이 시장/파생 지수(IndexDailyPrice)와 달라 재사용하지 않고 별도 테이블로 둔다 (채권지수 BondIndexDailyPrice 와 동일한 이유): /// - 종가(CLSPRC_IDX)만 제공하고 시가/고가/저가·시가총액이 없다. → IndexDailyPrice 재사용 시 OHLC 5컬럼이 0/null 로 낭비된다. /// - 대신 ESG 지수 고유의 구성종목수(TRD_ISU_CNT)를 제공한다. → IndexDailyPrice 에는 담을 곳이 없다. /// 등락률(UPDN_RATE)은 정수 보관을 위해 %×100 basis point(Bp)로 저장 (IndexDailyPrice.FlucRateBp 와 동일 규약). /// 거래량 단위는 천주, 거래대금 단위는 백만원(원문 그대로 보관 — 스케일 변환하지 않는다). /// public class EsgIndexDailyPrice { [Key] public long ID { get; private set; } /// 지수명 (IDX_NM, 예: "KRX ESG Leaders 150") public string IndexName { get; private set; } = default!; /// 거래일 (BAS_DD) public DateOnly TradeDate { get; private set; } /// 현재가/종가 (CLSPRC_IDX) public decimal Close { get; private set; } /// 전일비 (PRV_DD_CMPR) public decimal ChangeVal { get; private set; } /// 등락률 basis point = %×100 (UPDN_RATE) public int FlucRateBp { get; private set; } /// 구성종목수 (TRD_ISU_CNT) public int ConstituentCount { get; private set; } /// 거래량 (ACC_TRDVOL, 천주) public long Volume { get; private set; } /// 거래대금 (ACC_TRDVAL, 백만원) public long Value { get; private set; } public DateTime CreatedAt { get; private set; } = DateTime.UtcNow; private EsgIndexDailyPrice() { } public static EsgIndexDailyPrice Create( string indexName, DateOnly tradeDate, decimal close, decimal changeVal, int flucRateBp, int constituentCount, long volume, long value ) { if (string.IsNullOrWhiteSpace(indexName)) { throw new ArgumentException("indexName required", nameof(indexName)); } return new EsgIndexDailyPrice { IndexName = indexName.Trim(), TradeDate = tradeDate, Close = close, ChangeVal = changeVal, FlucRateBp = flucRateBp, ConstituentCount = constituentCount, Volume = volume, Value = value }; } /// 동일 (IndexName, TradeDate) 재수집 시 값 갱신 (upsert) public void Update( decimal close, decimal changeVal, int flucRateBp, int constituentCount, long volume, long value ) { Close = close; ChangeVal = changeVal; FlucRateBp = flucRateBp; ConstituentCount = constituentCount; Volume = volume; Value = value; } }