using System.ComponentModel.DataAnnotations;
namespace Domain.Entities.Stocks;
///
/// SEIBro 파생결합증권 종목 정보 (getDerivCombiIsinInfo) — 원금보전·만기·발행잔량·기초자산수 (Wave 5). PK Isin.
/// rolling per-ISIN 대상 = DerivIssuance.Isin. ELS/DLS 상세 조회의 주 마스터. 발행잔량(IssuRemq)·만기(XpirDt) 는 리스크 지표.
/// 소수/금액 precision 은 넉넉히(파생결합증권.md NUMBER(18,2)/NUMBER(13,10)/NUMBER(6,3)). 재수집 시 스냅샷 갱신.
///
public class DerivMaster
{
/// 종목코드 (ISIN) — PK
[Key]
[MaxLength(12)]
public string Isin { get; private set; } = default!;
/// 한글종목명 (KOR_SECN_NM)
public string? KorSecnNm { get; private set; }
/// 발행회사고객번호 (ISSUCO_CUSTNO)
public int? IssucoCustno { get; private set; }
/// 종목구분명 (SECN_KANM) — ELS/ELB/ELW/DLS/DLB/ETN
public string? SecnKanm { get; private set; }
/// 발행통화코드 (ISSU_CUR_CD) — KRW
public string? IssuCurCd { get; private set; }
/// 모집방법코드 (RECU_WHCD) — 11공모 21사모
public string? RecuWhcd { get; private set; }
/// 최초발행수량 (FIRST_ISSU_QTY)
public decimal? FirstIssuQty { get; private set; }
/// 발행잔량 (ISSU_REMQ)
public decimal? IssuRemq { get; private set; }
/// 납입금액비율 (PAYIN_AMT_RATIO)
public decimal? PayinAmtRatio { get; private set; }
/// 납입금액 (PAYIN_AMT)
public decimal? PayinAmt { get; private set; }
/// 발행일자 (ISSU_DT)
public DateOnly? IssuDt { get; private set; }
/// 계약일자 (CONT_DT)
public DateOnly? ContDt { get; private set; }
/// 만기일자 (XPIR_DT)
public DateOnly? XpirDt { get; private set; }
/// 중도상환가능여부 (MIDRED_POSS_YN, Y/N)
public bool? MidredPossYn { get; private set; }
/// 상환일자 (RED_DT) — 실제 상환일
public DateOnly? RedDt { get; private set; }
/// 파생증권권리행사구분코드 (DERISEC_EXER_TPCD) — 2만기 3조기
public string? DerisecExerTpcd { get; private set; }
/// 원금보전구분코드 (PRCP_PRSV_TPCD) — 1원금보장 2부분보장 3비보장 4기타 9해당없음
public string? PrcpPrsvTpcd { get; private set; }
/// 원금보전율 (PRCP_PRSV_RATE)
public decimal? PrcpPrsvRate { get; private set; }
/// 담보설정구분코드 (COLAT_SETUP_TPCD) — 1설정 2미설정
public string? ColatSetupTpcd { get; private set; }
/// 기초자산 개수 (BASSET_CNT)
public int? BassetCnt { get; private set; }
/// 월지급여부 (MM_PAY_YN, Y/N)
public bool? MmPayYn { get; private set; }
public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow;
private DerivMaster() { }
public static DerivMaster Create(string isin, DerivMasterFields f)
{
if (string.IsNullOrWhiteSpace(isin))
{
throw new ArgumentException("isin required", nameof(isin));
}
var entity = new DerivMaster { Isin = isin.Trim() };
entity.Apply(f);
return entity;
}
/// 재수집 반영 (PK Isin 은 불변) — 스냅샷 갱신, 변경 시에만 UpdatedAt
public void Update(DerivMasterFields f)
{
Apply(f);
}
private void Apply(DerivMasterFields f)
{
var changed = false;
changed |= Set(Trimmed(f.KorSecnNm), KorSecnNm, v => KorSecnNm = v);
changed |= Set(f.IssucoCustno, IssucoCustno, v => IssucoCustno = v);
changed |= Set(Trimmed(f.SecnKanm), SecnKanm, v => SecnKanm = v);
changed |= Set(Trimmed(f.IssuCurCd), IssuCurCd, v => IssuCurCd = v);
changed |= Set(Trimmed(f.RecuWhcd), RecuWhcd, v => RecuWhcd = v);
changed |= Set(f.FirstIssuQty, FirstIssuQty, v => FirstIssuQty = v);
changed |= Set(f.IssuRemq, IssuRemq, v => IssuRemq = v);
changed |= Set(f.PayinAmtRatio, PayinAmtRatio, v => PayinAmtRatio = v);
changed |= Set(f.PayinAmt, PayinAmt, v => PayinAmt = v);
changed |= Set(f.IssuDt, IssuDt, v => IssuDt = v);
changed |= Set(f.ContDt, ContDt, v => ContDt = v);
changed |= Set(f.XpirDt, XpirDt, v => XpirDt = v);
changed |= Set(f.MidredPossYn, MidredPossYn, v => MidredPossYn = v);
changed |= Set(f.RedDt, RedDt, v => RedDt = v);
changed |= Set(Trimmed(f.DerisecExerTpcd), DerisecExerTpcd, v => DerisecExerTpcd = v);
changed |= Set(Trimmed(f.PrcpPrsvTpcd), PrcpPrsvTpcd, v => PrcpPrsvTpcd = v);
changed |= Set(f.PrcpPrsvRate, PrcpPrsvRate, v => PrcpPrsvRate = v);
changed |= Set(Trimmed(f.ColatSetupTpcd), ColatSetupTpcd, v => ColatSetupTpcd = v);
changed |= Set(f.BassetCnt, BassetCnt, v => BassetCnt = v);
changed |= Set(f.MmPayYn, MmPayYn, v => MmPayYn = 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;
}
}
/// DerivMaster 필드 묶음 (getDerivCombiIsinInfo 필드 다수 — 생성/갱신 인자 축약)
public sealed record DerivMasterFields(
string? KorSecnNm,
int? IssucoCustno,
string? SecnKanm,
string? IssuCurCd,
string? RecuWhcd,
decimal? FirstIssuQty,
decimal? IssuRemq,
decimal? PayinAmtRatio,
decimal? PayinAmt,
DateOnly? IssuDt,
DateOnly? ContDt,
DateOnly? XpirDt,
bool? MidredPossYn,
DateOnly? RedDt,
string? DerisecExerTpcd,
string? PrcpPrsvTpcd,
decimal? PrcpPrsvRate,
string? ColatSetupTpcd,
int? BassetCnt,
bool? MmPayYn
);