namespace Infrastructure.StockData; /// /// SEIBro getXrcStkOptionXrcInfo(주식관련사채 행사내역) 응답 파서 — 순수 C#. 공용 SeibroXml envelope 입력. /// ⚠️ 실샘플 fixture 가 result="0"(0행)이라 필드 매핑을 라이브로 검증하지 못했다 — 주식.md 스펙 기준으로 구현했으며 /// 운영 첫 수집 시 로그로 필드명(대소문자 포함)을 확인해야 한다. /// 날짜 스윕(권리행사일 RGT_STD_DT) 결과 — BOND_ISIN·RGT_STD_DT 중 하나라도 없으면 건너뛴다. /// XRC_AMT/XRC_QTY/XRC_PRICE 는 소수 표기 가능 → decimal. /// public static class SeibroXrcStkOptionXrcParser { public sealed record Row( string BondIsin, string? BondKorSecnNm, string? BondKindNm, string? XrcStkIsin, string? StkKorSecnNm, DateOnly RgtStdDt, DateOnly? XrcPossBeginDt, DateOnly? XrcPossExpryDt, decimal? XrcAmt, decimal? XrcQty, decimal? XrcPrice, DateOnly? ListDt ); public static IReadOnlyList Parse(SeibroXml.Envelope envelope) { var rows = new List(); foreach (var fields in envelope.Rows) { var bondIsin = SeibroXml.GetOrNull(fields, "BOND_ISIN")?.Trim(); var rgtStdDt = SeibroFieldParse.Date(SeibroXml.GetOrNull(fields, "RGT_STD_DT")); if (string.IsNullOrEmpty(bondIsin) || rgtStdDt is null) { continue; } rows.Add(new Row( bondIsin, SeibroXml.GetOrNull(fields, "BOND_KOR_SECN_NM")?.Trim(), SeibroXml.GetOrNull(fields, "BOND_KIND_NM")?.Trim(), SeibroXml.GetOrNull(fields, "XRC_STK_ISIN")?.Trim(), SeibroXml.GetOrNull(fields, "STK_KOR_SECN_NM")?.Trim(), rgtStdDt.Value, SeibroFieldParse.Date(SeibroXml.GetOrNull(fields, "XRC_POSS_BEGIN_DT")), SeibroFieldParse.Date(SeibroXml.GetOrNull(fields, "XRC_POSS_EXPRY_DT")), SeibroFieldParse.Decimal(SeibroXml.GetOrNull(fields, "XRC_AMT")), SeibroFieldParse.Decimal(SeibroXml.GetOrNull(fields, "XRC_QTY")), SeibroFieldParse.Decimal(SeibroXml.GetOrNull(fields, "XRC_PRICE")), SeibroFieldParse.Date(SeibroXml.GetOrNull(fields, "LIST_DT")) )); } return rows; } }