Handler.cs 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Domain.Entities.Stocks.ValueObject;
  4. using Microsoft.EntityFrameworkCore;
  5. namespace Application.Features.Api.Stocks.GetInterestRates;
  6. /// <summary>
  7. /// 금리 목록 — 국제금리는 Yahoo 수집분(MarketQuoteSnapshot, Category=BondYield·GroupCode="macro")의 미국채 수익률(%)을 반환 (익명).
  8. /// koreaexim AP02/AP03 은 봇차단 WAF 로 이 서버망에서 수집 불가 → 이미 수집 중인 Yahoo 매크로 시세로 소스 전환 (2026-07-14).
  9. /// 대출금리(Loan)는 Yahoo 대응이 없어 빈 목록으로 반환한다(개요 화면은 International 만 사용). Date 파라미터는 스냅샷 특성상 무시(항상 최신).
  10. /// </summary>
  11. internal sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Response>
  12. {
  13. public async Task<Response> Handle(Query request, CancellationToken ct)
  14. {
  15. // Yahoo 는 국제금리(미국채 수익률)만 제공 — 대출금리(Loan)는 미수집
  16. if (request.Type != RateType.International)
  17. {
  18. return new Response
  19. {
  20. Type = request.Type,
  21. Total = 0,
  22. TradeDate = null,
  23. List = []
  24. };
  25. }
  26. var rows = await db.MarketQuoteSnapshot.AsNoTracking()
  27. .Where(c => c.Category == QuoteCategory.BondYield && c.GroupCode == "macro")
  28. .OrderBy(c => c.Symbol)
  29. .Select(c => new { c.Name, c.Close, c.TradeDate })
  30. .ToListAsync(ct);
  31. if (rows.Count == 0)
  32. {
  33. return new Response
  34. {
  35. Type = request.Type,
  36. Total = 0,
  37. TradeDate = null,
  38. List = []
  39. };
  40. }
  41. var list = rows
  42. .Select(c => new Response.Row
  43. {
  44. ItemName = c.Name,
  45. Rate = c.Close
  46. })
  47. .ToList();
  48. return new Response
  49. {
  50. Type = request.Type,
  51. Total = list.Count,
  52. TradeDate = rows.Max(c => c.TradeDate),
  53. List = list
  54. };
  55. }
  56. }