using System.ComponentModel.DataAnnotations;
namespace Domain.Entities.Stocks;
///
/// SEIBro 채권 조기상환 정보 (getBondOptionXrcInfo) — Call/Put 옵션 행사 조기상환 (Wave 4). 자연키 UNIQUE (Isin, ErlyRedDt).
/// 조기상환일(ERLY_RED_DT) 날짜 스윕으로 수집한다. 한 채권이 여러 조기상환일을 가질 수 있어 (Isin, ErlyRedDt) 로 구분.
///
public class BondEarlyRedemption
{
[Key]
public int ID { get; private set; }
/// 종목코드 (ISIN)
public string Isin { get; private set; } = default!;
/// 한글종목명 (KOR_SECN_NM)
public string? KorSecnNm { get; private set; }
/// 행사시작일 (XRC_BEGIN_DT)
public DateOnly? XrcBeginDt { get; private set; }
/// 행사종료일 (XRC_EXPRY_DT)
public DateOnly? XrcExpryDt { get; private set; }
/// 조기상환일 (ERLY_RED_DT)
public DateOnly ErlyRedDt { get; private set; }
/// 옵션구분코드 (OPTION_TPCD) — 9401CALL 9402PUT 9403CALL+PUT
public string? OptionTpcd { get; private set; }
/// 적용이자율 (APLI_IRATE)
public decimal? ApliIrate { get; private set; }
/// 조기상환금액 (ERLY_REDAMT_VAL)
public decimal? ErlyRedamtVal { get; private set; }
/// 이자지급금액 (INT_PAY_AMT)
public decimal? IntPayAmt { get; private set; }
/// 최근발행잔액 (ISSU_REMA)
public decimal? IssuRema { get; private set; }
/// 행사비율 (XRC_RATIO)
public decimal? XrcRatio { get; private set; }
public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow;
private BondEarlyRedemption() { }
public static BondEarlyRedemption Create(
string isin,
string? korSecnNm,
DateOnly? xrcBeginDt,
DateOnly? xrcExpryDt,
DateOnly erlyRedDt,
string? optionTpcd,
decimal? apliIrate,
decimal? erlyRedamtVal,
decimal? intPayAmt,
decimal? issuRema,
decimal? xrcRatio)
{
if (string.IsNullOrWhiteSpace(isin))
{
throw new ArgumentException("isin required", nameof(isin));
}
return new BondEarlyRedemption
{
Isin = isin.Trim(),
KorSecnNm = Trimmed(korSecnNm),
XrcBeginDt = xrcBeginDt,
XrcExpryDt = xrcExpryDt,
ErlyRedDt = erlyRedDt,
OptionTpcd = Trimmed(optionTpcd),
ApliIrate = apliIrate,
ErlyRedamtVal = erlyRedamtVal,
IntPayAmt = intPayAmt,
IssuRema = issuRema,
XrcRatio = xrcRatio
};
}
/// 재수집 반영 — 변경 필드가 있을 때만 UpdatedAt 갱신 (자연키 Isin/ErlyRedDt 는 불변)
public void Update(
string? korSecnNm,
DateOnly? xrcBeginDt,
DateOnly? xrcExpryDt,
string? optionTpcd,
decimal? apliIrate,
decimal? erlyRedamtVal,
decimal? intPayAmt,
decimal? issuRema,
decimal? xrcRatio)
{
var changed = false;
changed |= Set(Trimmed(korSecnNm), KorSecnNm, v => KorSecnNm = v);
changed |= Set(xrcBeginDt, XrcBeginDt, v => XrcBeginDt = v);
changed |= Set(xrcExpryDt, XrcExpryDt, v => XrcExpryDt = v);
changed |= Set(Trimmed(optionTpcd), OptionTpcd, v => OptionTpcd = v);
changed |= Set(apliIrate, ApliIrate, v => ApliIrate = v);
changed |= Set(erlyRedamtVal, ErlyRedamtVal, v => ErlyRedamtVal = v);
changed |= Set(intPayAmt, IntPayAmt, v => IntPayAmt = v);
changed |= Set(issuRema, IssuRema, v => IssuRema = v);
changed |= Set(xrcRatio, XrcRatio, v => XrcRatio = v);
if (changed)
{
UpdatedAt = DateTime.UtcNow;
}
}
private static string? Trimmed(string? value)
{
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
}
private static bool Set(T incoming, T current, Action assign)
{
if (EqualityComparer.Default.Equals(incoming, current))
{
return false;
}
assign(incoming);
return true;
}
}