EsgIndexDailyPrice.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. using System.ComponentModel.DataAnnotations;
  2. namespace Domain.Entities.Stocks;
  3. /// <summary>
  4. /// ESG 지수 일별시세 (KRX OpenAPI esg/esg_index_info) — (IndexName, TradeDate) UNIQUE.
  5. /// 응답 shape 이 시장/파생 지수(IndexDailyPrice)와 달라 재사용하지 않고 별도 테이블로 둔다 (채권지수 BondIndexDailyPrice 와 동일한 이유):
  6. /// - 종가(CLSPRC_IDX)만 제공하고 시가/고가/저가·시가총액이 없다. → IndexDailyPrice 재사용 시 OHLC 5컬럼이 0/null 로 낭비된다.
  7. /// - 대신 ESG 지수 고유의 구성종목수(TRD_ISU_CNT)를 제공한다. → IndexDailyPrice 에는 담을 곳이 없다.
  8. /// 등락률(UPDN_RATE)은 정수 보관을 위해 %×100 basis point(Bp)로 저장 (IndexDailyPrice.FlucRateBp 와 동일 규약).
  9. /// 거래량 단위는 천주, 거래대금 단위는 백만원(원문 그대로 보관 — 스케일 변환하지 않는다).
  10. /// </summary>
  11. public class EsgIndexDailyPrice
  12. {
  13. [Key]
  14. public long ID { get; private set; }
  15. /// <summary>지수명 (IDX_NM, 예: "KRX ESG Leaders 150")</summary>
  16. public string IndexName { get; private set; } = default!;
  17. /// <summary>거래일 (BAS_DD)</summary>
  18. public DateOnly TradeDate { get; private set; }
  19. /// <summary>현재가/종가 (CLSPRC_IDX)</summary>
  20. public decimal Close { get; private set; }
  21. /// <summary>전일비 (PRV_DD_CMPR)</summary>
  22. public decimal ChangeVal { get; private set; }
  23. /// <summary>등락률 basis point = %×100 (UPDN_RATE)</summary>
  24. public int FlucRateBp { get; private set; }
  25. /// <summary>구성종목수 (TRD_ISU_CNT)</summary>
  26. public int ConstituentCount { get; private set; }
  27. /// <summary>거래량 (ACC_TRDVOL, 천주)</summary>
  28. public long Volume { get; private set; }
  29. /// <summary>거래대금 (ACC_TRDVAL, 백만원)</summary>
  30. public long Value { get; private set; }
  31. public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
  32. private EsgIndexDailyPrice() { }
  33. public static EsgIndexDailyPrice Create(
  34. string indexName,
  35. DateOnly tradeDate,
  36. decimal close,
  37. decimal changeVal,
  38. int flucRateBp,
  39. int constituentCount,
  40. long volume,
  41. long value
  42. ) {
  43. if (string.IsNullOrWhiteSpace(indexName))
  44. {
  45. throw new ArgumentException("indexName required", nameof(indexName));
  46. }
  47. return new EsgIndexDailyPrice
  48. {
  49. IndexName = indexName.Trim(),
  50. TradeDate = tradeDate,
  51. Close = close,
  52. ChangeVal = changeVal,
  53. FlucRateBp = flucRateBp,
  54. ConstituentCount = constituentCount,
  55. Volume = volume,
  56. Value = value
  57. };
  58. }
  59. /// <summary>동일 (IndexName, TradeDate) 재수집 시 값 갱신 (upsert)</summary>
  60. public void Update(
  61. decimal close,
  62. decimal changeVal,
  63. int flucRateBp,
  64. int constituentCount,
  65. long volume,
  66. long value
  67. ) {
  68. Close = close;
  69. ChangeVal = changeVal;
  70. FlucRateBp = flucRateBp;
  71. ConstituentCount = constituentCount;
  72. Volume = volume;
  73. Value = value;
  74. }
  75. }