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