| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- using Domain.Entities.Stocks.ValueObject;
- using Infrastructure.StockData;
- namespace Application.Tests;
- [TestClass]
- public sealed class IndexPriceParserTests
- {
- [TestMethod]
- public void ParseIndexPrices_MapsFields_CommasAndDash()
- {
- // KRX OpenAPI(kospi_dd_trd) 표준 응답 샘플 — 콤마 천단위 + "-"(결측) 혼재, 등락률 %→Bp 변환 검증
- const string json = """
- {"OutBlock_1":[
- {"BAS_DD":"20260703","IDX_CLSS":"KOSPI","IDX_NM":"코스피","CLSPRC_IDX":"3,150.25","CMPPREVDD_IDX":"-22.10","FLUC_RT":"-0.70","OPNPRC_IDX":"3,172.00","HGPRC_IDX":"3,180.55","LWPRC_IDX":"3,145.10","ACC_TRDVOL":"512,345,678","ACC_TRDVAL":"9,870,000,000,000","MKTCAP":"2,100,870,169,275,000"},
- {"BAS_DD":"20260703","IDX_CLSS":"KOSPI","IDX_NM":"코스피 200","CLSPRC_IDX":"420.15","CMPPREVDD_IDX":"6.05","FLUC_RT":"1.46","OPNPRC_IDX":"415.00","HGPRC_IDX":"421.00","LWPRC_IDX":"414.50","ACC_TRDVOL":"-","ACC_TRDVAL":"-","MKTCAP":"-"}
- ]}
- """;
- var rows = KrxIndexParser.ParseIndexPrices(json, MarketIndexSeries.KOSPI);
- Assert.AreEqual(2, rows.Count);
- var kospi = rows[0];
- Assert.AreEqual(MarketIndexSeries.KOSPI, kospi.Series);
- Assert.AreEqual("코스피", kospi.IndexName);
- Assert.AreEqual(new DateOnly(2026, 7, 3), kospi.TradeDate);
- Assert.AreEqual(3150.25m, kospi.Close, "콤마 천단위를 제거하고 소수 종가를 파싱해야 한다");
- Assert.AreEqual(-22.10m, kospi.ChangeVal);
- Assert.AreEqual(-70, kospi.FlucRateBp, "FLUC_RT -0.70% → -70 Bp");
- Assert.AreEqual(3172.00m, kospi.Open);
- Assert.AreEqual(3180.55m, kospi.High);
- Assert.AreEqual(3145.10m, kospi.Low);
- Assert.AreEqual(512345678L, kospi.Volume, "거래량 콤마 제거");
- Assert.AreEqual(9870000000000L, kospi.Value, "거래대금 콤마 제거");
- Assert.AreEqual(2100870169275000L, kospi.MarketCap);
- var kospi200 = rows[1];
- Assert.AreEqual("코스피 200", kospi200.IndexName);
- Assert.AreEqual(146, kospi200.FlucRateBp, "FLUC_RT 1.46% → 146 Bp");
- Assert.AreEqual(0L, kospi200.Volume, "\"-\" 거래량은 0 으로 흡수");
- Assert.AreEqual(0L, kospi200.Value, "\"-\" 거래대금은 0 으로 흡수");
- Assert.IsNull(kospi200.MarketCap, "\"-\" 시가총액은 null");
- }
- [TestMethod]
- public void ParseIndexPrices_EmptyOrMissingBlock_ReturnsEmpty()
- {
- // 결과 없음 — OutBlock_1 이 빈 배열
- var empty = KrxIndexParser.ParseIndexPrices("""{"OutBlock_1":[]}""", MarketIndexSeries.KOSDAQ);
- Assert.AreEqual(0, empty.Count);
- // OutBlock_1 노드 자체가 없는 응답도 안전하게 0건
- var missing = KrxIndexParser.ParseIndexPrices("""{"respMsg":"Unauthorized API Call","respCode":"401"}""", MarketIndexSeries.KRX);
- Assert.AreEqual(0, missing.Count);
- }
- [TestMethod]
- public void ParseIndexPrices_Derivative_SubsetShape_VolumeValueCapDefaults()
- {
- // 파생상품지수(idx/drvprod_dd_trd) 응답 — OHLC 는 있으나 ACC_TRDVOL/ACC_TRDVAL/MKTCAP 필드 자체가 없다.
- // KrxIndexParser 는 없는 필드를 0(거래량/거래대금)·null(시총)로 흡수하고 나머지는 IndexDailyPrice 로 매핑해야 한다.
- const string json = """
- {"OutBlock_1":[
- {"BAS_DD":"20250102","IDX_CLSS":"선물지수","IDX_NM":"미국달러선물지수","CLSPRC_IDX":"1,599.06","CMPPREVDD_IDX":"-8.83","FLUC_RT":"-0.55","OPNPRC_IDX":"1,606.04","HGPRC_IDX":"1,607.35","LWPRC_IDX":"1,596.77"}
- ]}
- """;
- var rows = KrxIndexParser.ParseIndexPrices(json, MarketIndexSeries.Derivative);
- Assert.AreEqual(1, rows.Count);
- var row = rows[0];
- Assert.AreEqual(MarketIndexSeries.Derivative, row.Series);
- Assert.AreEqual("미국달러선물지수", row.IndexName);
- Assert.AreEqual(new DateOnly(2025, 1, 2), row.TradeDate);
- Assert.AreEqual(1599.06m, row.Close);
- Assert.AreEqual(-8.83m, row.ChangeVal);
- Assert.AreEqual(-55, row.FlucRateBp, "FLUC_RT -0.55% → -55 Bp");
- Assert.AreEqual(1606.04m, row.Open);
- Assert.AreEqual(1607.35m, row.High);
- Assert.AreEqual(1596.77m, row.Low);
- Assert.AreEqual(0L, row.Volume, "ACC_TRDVOL 필드 부재 → 0");
- Assert.AreEqual(0L, row.Value, "ACC_TRDVAL 필드 부재 → 0");
- Assert.IsNull(row.MarketCap, "MKTCAP 필드 부재 → null");
- }
- [TestMethod]
- public void ParseIndexPrices_RoundsHalfAwayFromZero()
- {
- // 등락률 반올림 경계 — 0.005% → 1 Bp (AwayFromZero), -0.005% → -1 Bp
- const string json = """
- {"OutBlock_1":[
- {"BAS_DD":"20260703","IDX_NM":"경계+","CLSPRC_IDX":"100","CMPPREVDD_IDX":"0","FLUC_RT":"0.005","OPNPRC_IDX":"100","HGPRC_IDX":"100","LWPRC_IDX":"100","ACC_TRDVOL":"0","ACC_TRDVAL":"0","MKTCAP":"0"},
- {"BAS_DD":"20260703","IDX_NM":"경계-","CLSPRC_IDX":"100","CMPPREVDD_IDX":"0","FLUC_RT":"-0.005","OPNPRC_IDX":"100","HGPRC_IDX":"100","LWPRC_IDX":"100","ACC_TRDVOL":"0","ACC_TRDVAL":"0","MKTCAP":"0"}
- ]}
- """;
- var rows = KrxIndexParser.ParseIndexPrices(json, MarketIndexSeries.KRX);
- Assert.AreEqual(1, rows[0].FlucRateBp);
- Assert.AreEqual(-1, rows[1].FlucRateBp);
- }
- }
|