CommodityDailyTrade.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using System.ComponentModel.DataAnnotations;
  2. using Domain.Entities.Stocks.ValueObject;
  3. namespace Domain.Entities.Stocks;
  4. /// <summary>
  5. /// 일반상품(석유·금·배출권) 일별매매 시세 (KRX OpenAPI gen 엔드포인트) — (CommodityMarket, Code, TradeDate) UNIQUE.
  6. /// 세 시장을 한 테이블에 담고 CommodityMarket 으로 구분한다. 시장별 응답 shape 이 다르다:
  7. /// - 금(Gold)/배출권(Emission): ISU_CD/ISU_NM + 주식형 OHLC(TDD_CLSPRC/OPNPRC/HGPRC/LWPRC) + 전일대비(CMPPREVDD_PRC)·등락률(FLUC_RT).
  8. /// - 석유(Oil): ISU_CD 없음 → OIL_NM(유종구분)을 Code·Name 으로 사용. OHLC 미제공(Open/High/Low=0), 전일대비·등락률 없음 → null.
  9. /// 가격은 가중평균가격_경쟁(WT_AVG_PRC)을 Close 로, 가중평균가격_협의(WT_DIS_AVG_PRC)를 WeightedDiscussionPrice(석유 전용 nullable)로 담는다.
  10. /// 공통 필드: Code/Name, TradeDate, Close/Open/High/Low(decimal 18,2), Volume/TradeValue(long). 등락은 금/배출권만, 협의가격은 석유만.
  11. /// </summary>
  12. public class CommodityDailyTrade
  13. {
  14. [Key]
  15. public long ID { get; private set; }
  16. /// <summary>일반상품 시장 구분 (1=석유, 2=금, 3=배출권)</summary>
  17. public CommodityMarket CommodityMarket { get; private set; }
  18. /// <summary>단축코드 (ISU_CD) — 금/배출권. 석유는 OIL_NM(유종구분)을 코드로 사용</summary>
  19. public string Code { get; private set; } = default!;
  20. /// <summary>종목명 (ISU_NM) — 석유는 OIL_NM(유종구분)</summary>
  21. public string Name { get; private set; } = default!;
  22. /// <summary>거래일 (BAS_DD)</summary>
  23. public DateOnly TradeDate { get; private set; }
  24. /// <summary>종가 (TDD_CLSPRC) — 석유는 가중평균가격_경쟁 (WT_AVG_PRC)</summary>
  25. public decimal Close { get; private set; }
  26. /// <summary>시가 (TDD_OPNPRC) — 석유 미제공 시 0</summary>
  27. public decimal Open { get; private set; }
  28. /// <summary>고가 (TDD_HGPRC) — 석유 미제공 시 0</summary>
  29. public decimal High { get; private set; }
  30. /// <summary>저가 (TDD_LWPRC) — 석유 미제공 시 0</summary>
  31. public decimal Low { get; private set; }
  32. /// <summary>전일 대비 (CMPPREVDD_PRC) — 금/배출권만. 석유는 미제공 → null</summary>
  33. public decimal? ChangeAmount { get; private set; }
  34. /// <summary>등락률 % (FLUC_RT) — 금/배출권만. 석유는 미제공 → null</summary>
  35. public decimal? ChangeRate { get; private set; }
  36. /// <summary>가중평균가격_협의 (WT_DIS_AVG_PRC) — 석유만. 금/배출권은 null</summary>
  37. public decimal? WeightedDiscussionPrice { get; private set; }
  38. /// <summary>거래량 (ACC_TRDVOL)</summary>
  39. public long Volume { get; private set; }
  40. /// <summary>거래대금 (ACC_TRDVAL, 원)</summary>
  41. public long TradeValue { get; private set; }
  42. public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
  43. private CommodityDailyTrade() { }
  44. public static CommodityDailyTrade Create(
  45. CommodityMarket commodityMarket,
  46. string code,
  47. string name,
  48. DateOnly tradeDate,
  49. decimal close,
  50. decimal open,
  51. decimal high,
  52. decimal low,
  53. decimal? changeAmount,
  54. decimal? changeRate,
  55. decimal? weightedDiscussionPrice,
  56. long volume,
  57. long tradeValue
  58. ) {
  59. if (!Enum.IsDefined(commodityMarket))
  60. {
  61. throw new ArgumentOutOfRangeException(nameof(commodityMarket));
  62. }
  63. if (string.IsNullOrWhiteSpace(code))
  64. {
  65. throw new ArgumentException("code required", nameof(code));
  66. }
  67. if (string.IsNullOrWhiteSpace(name))
  68. {
  69. throw new ArgumentException("name required", nameof(name));
  70. }
  71. return new CommodityDailyTrade
  72. {
  73. CommodityMarket = commodityMarket,
  74. Code = code.Trim(),
  75. Name = name.Trim(),
  76. TradeDate = tradeDate,
  77. Close = close,
  78. Open = open,
  79. High = high,
  80. Low = low,
  81. ChangeAmount = changeAmount,
  82. ChangeRate = changeRate,
  83. WeightedDiscussionPrice = weightedDiscussionPrice,
  84. Volume = volume,
  85. TradeValue = tradeValue
  86. };
  87. }
  88. /// <summary>동일 (CommodityMarket, Code, TradeDate) 재수집 시 값 갱신 (upsert)</summary>
  89. public void Update(
  90. string name,
  91. decimal close,
  92. decimal open,
  93. decimal high,
  94. decimal low,
  95. decimal? changeAmount,
  96. decimal? changeRate,
  97. decimal? weightedDiscussionPrice,
  98. long volume,
  99. long tradeValue
  100. ) {
  101. Name = name.Trim();
  102. Close = close;
  103. Open = open;
  104. High = high;
  105. Low = low;
  106. ChangeAmount = changeAmount;
  107. ChangeRate = changeRate;
  108. WeightedDiscussionPrice = weightedDiscussionPrice;
  109. Volume = volume;
  110. TradeValue = tradeValue;
  111. }
  112. }