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;
}
}