using System.ComponentModel.DataAnnotations; namespace Domain.Entities.Stocks; /// /// 사회책임투자채권(SRI) 정보 스냅샷 (KRX OpenAPI esg/sri_bond_info) — (Code, TradeDate) UNIQUE. /// 채권 일별매매(BondDailyTrade)와 달리 가격/거래량이 아니라 발행 정보(발행기관·채권종류·발행일·상환일·표면이자율·발행금액 등) 레지스트리다. /// 응답이 basDd 파라미터로 그날 상장된 SRI 채권 전량을 반환하므로(스냅샷) 종목마다 여러 basDd 행이 생긴다 → (Code=표준코드, TradeDate=기준일자)로 UQ. /// 표준코드(ISU_CD)는 12자리 ISIN. 날짜(LIST_DD/ISU_DD/REDMPT_DD)는 yyyyMMdd 미제공/오류 시 null. 금액은 원 단위 long, 표면이자율은 decimal(9,5)%. /// public class SriBond { [Key] public long ID { get; private set; } /// 표준코드 (ISU_CD) — 12자리 ISIN. UQ 키의 일부 public string Code { get; private set; } = default!; /// 기준일자 (BAS_DD) — 스냅샷 일자. UQ 키의 일부 public DateOnly TradeDate { get; private set; } /// 발행기관 (ISUR_NM) public string IssuerName { get; private set; } = default!; /// 채권종류 (SRI_BND_TP_NM, 예: "녹색채권"/"사회적채권"/"지속가능채권") public string SriBondType { get; private set; } = default!; /// 종목명 (ISU_NM) public string Name { get; private set; } = default!; /// 상장일 (LIST_DD) — 미제공 시 null public DateOnly? ListDate { get; private set; } /// 발행일 (ISU_DD) — 미제공 시 null public DateOnly? IssueDate { get; private set; } /// 상환일 (REDMPT_DD) — 미제공 시 null public DateOnly? RedemptionDate { get; private set; } /// 표면이자율 % (ISU_RT) — 미제공 시 null public decimal? CouponRate { get; private set; } /// 발행금액 (ISU_AMT, 원) public long IssueAmount { get; private set; } /// 상장금액 (LIST_AMT, 원) public long ListAmount { get; private set; } /// 채권유형 (BND_TP_NM, 예: "회사채") — 미제공 시 null public string? BondType { get; private set; } public DateTime CreatedAt { get; private set; } = DateTime.UtcNow; private SriBond() { } public static SriBond Create( string code, DateOnly tradeDate, string issuerName, string sriBondType, string name, DateOnly? listDate, DateOnly? issueDate, DateOnly? redemptionDate, decimal? couponRate, long issueAmount, long listAmount, string? bondType ) { if (string.IsNullOrWhiteSpace(code)) { throw new ArgumentException("code required", nameof(code)); } if (string.IsNullOrWhiteSpace(issuerName)) { throw new ArgumentException("issuerName required", nameof(issuerName)); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException("name required", nameof(name)); } return new SriBond { Code = code.Trim(), TradeDate = tradeDate, IssuerName = issuerName.Trim(), SriBondType = sriBondType.Trim(), Name = name.Trim(), ListDate = listDate, IssueDate = issueDate, RedemptionDate = redemptionDate, CouponRate = couponRate, IssueAmount = issueAmount, ListAmount = listAmount, BondType = bondType }; } /// 동일 (Code, TradeDate) 재수집 시 값 갱신 (upsert) public void Update( string issuerName, string sriBondType, string name, DateOnly? listDate, DateOnly? issueDate, DateOnly? redemptionDate, decimal? couponRate, long issueAmount, long listAmount, string? bondType ) { IssuerName = issuerName.Trim(); SriBondType = sriBondType.Trim(); Name = name.Trim(); ListDate = listDate; IssueDate = issueDate; RedemptionDate = redemptionDate; CouponRate = couponRate; IssueAmount = issueAmount; ListAmount = listAmount; BondType = bondType; } }