BondIndexParserTests.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using Infrastructure.StockData;
  2. namespace Application.Tests;
  3. [TestClass]
  4. public sealed class BondIndexParserTests
  5. {
  6. [TestMethod]
  7. public void ParseBondIndexPrices_MapsFields_CommasAndEmptyToNull()
  8. {
  9. // KRX OpenAPI(idx/bon_dd_trd) 라이브 응답 샘플 — 1행은 전 지표 제공, 2행은 제로/Call재투자·시장가격 미제공("") → null.
  10. const string json = """
  11. {"OutBlock_1":[
  12. {"BAS_DD":"20250102","BND_IDX_GRP_NM":"KRX 채권지수","TOT_EARNG_IDX":"200.78","TOT_EARNG_IDX_CMPPREVDD":"1.12","NETPRC_IDX":"103.84","NETPRC_IDX_CMPPREVDD":"0.58","ZERO_REINVST_IDX":"193.89","ZERO_REINVST_IDX_CMPPREVDD":"1.08","CALL_REINVST_IDX":"199.47","CALL_REINVST_IDX_CMPPREVDD":"1.12","MKT_PRC_IDX":"104.55","MKT_PRC_IDX_CMPPREVDD":"0.56","AVG_DURATION":"5.646","AVG_CONVEXITY_PRC":"91.702","BND_IDX_AVG_YD":"2.886"},
  13. {"BAS_DD":"20250102","BND_IDX_GRP_NM":"국고채프라임지수","TOT_EARNG_IDX":"1,199.20","TOT_EARNG_IDX_CMPPREVDD":"0.72","NETPRC_IDX":"109.08","NETPRC_IDX_CMPPREVDD":"0.39","ZERO_REINVST_IDX":"","ZERO_REINVST_IDX_CMPPREVDD":"","CALL_REINVST_IDX":"-","CALL_REINVST_IDX_CMPPREVDD":"-","MKT_PRC_IDX":"","MKT_PRC_IDX_CMPPREVDD":"","AVG_DURATION":"4.105","AVG_CONVEXITY_PRC":"22.500","BND_IDX_AVG_YD":"2.700"}
  14. ]}
  15. """;
  16. var rows = KrxBondIndexParser.ParseBondIndexPrices(json);
  17. Assert.AreEqual(2, rows.Count);
  18. var krx = rows[0];
  19. Assert.AreEqual("KRX 채권지수", krx.GroupName);
  20. Assert.AreEqual(new DateOnly(2025, 1, 2), krx.TradeDate);
  21. Assert.AreEqual(200.78m, krx.TotalEarningIndex);
  22. Assert.AreEqual(1.12m, krx.TotalEarningChange);
  23. Assert.AreEqual(103.84m, krx.NetPriceIndex);
  24. Assert.AreEqual(0.58m, krx.NetPriceChange);
  25. Assert.AreEqual(193.89m, krx.ZeroReinvestIndex);
  26. Assert.AreEqual(1.08m, krx.ZeroReinvestChange);
  27. Assert.AreEqual(199.47m, krx.CallReinvestIndex);
  28. Assert.AreEqual(1.12m, krx.CallReinvestChange);
  29. Assert.AreEqual(104.55m, krx.MarketPriceIndex);
  30. Assert.AreEqual(0.56m, krx.MarketPriceChange);
  31. Assert.AreEqual(5.646m, krx.AvgDuration);
  32. Assert.AreEqual(91.702m, krx.AvgConvexity);
  33. Assert.AreEqual(2.886m, krx.AvgYield);
  34. var prime = rows[1];
  35. Assert.AreEqual("국고채프라임지수", prime.GroupName);
  36. Assert.AreEqual(1199.20m, prime.TotalEarningIndex, "콤마 천단위 제거");
  37. Assert.IsNull(prime.ZeroReinvestIndex, "\"\" 제로재투자지수는 null");
  38. Assert.IsNull(prime.ZeroReinvestChange);
  39. Assert.IsNull(prime.CallReinvestIndex, "\"-\" Call재투자지수는 null");
  40. Assert.IsNull(prime.MarketPriceIndex, "\"\" 시장가격지수는 null");
  41. Assert.AreEqual(4.105m, prime.AvgDuration);
  42. Assert.AreEqual(2.700m, prime.AvgYield);
  43. }
  44. [TestMethod]
  45. public void ParseBondIndexPrices_EmptyOrMissingBlock_ReturnsEmpty()
  46. {
  47. var empty = KrxBondIndexParser.ParseBondIndexPrices("""{"OutBlock_1":[]}""");
  48. Assert.AreEqual(0, empty.Count);
  49. var missing = KrxBondIndexParser.ParseBondIndexPrices("""{"respMsg":"Unauthorized API Call","respCode":"401"}""");
  50. Assert.AreEqual(0, missing.Count);
  51. }
  52. [TestMethod]
  53. public void ParseBondIndexPrices_SkipsRowsWithoutGroupNameOrDate()
  54. {
  55. // 그룹명 없거나 날짜 파싱 실패 행은 스킵
  56. const string json = """
  57. {"OutBlock_1":[
  58. {"BAS_DD":"20250102","BND_IDX_GRP_NM":"","TOT_EARNG_IDX":"100"},
  59. {"BAS_DD":"","BND_IDX_GRP_NM":"그룹","TOT_EARNG_IDX":"100"},
  60. {"BAS_DD":"20250102","BND_IDX_GRP_NM":"정상","TOT_EARNG_IDX":"100"}
  61. ]}
  62. """;
  63. var rows = KrxBondIndexParser.ParseBondIndexPrices(json);
  64. Assert.AreEqual(1, rows.Count);
  65. Assert.AreEqual("정상", rows[0].GroupName);
  66. }
  67. }