market.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // 시장 데이터 표시용 순수 유틸 (서버·클라이언트 공용 — 'use client'/'use server' 미선언)
  2. // 소수 포함 숫자 (지수·환율·금리 등) — 천 단위 구분 + 소수 자릿수 지정. null 은 —
  3. export function formatDecimal(value: number|null|undefined, fractionDigits = 2): string {
  4. if (value === null || value === undefined) {
  5. return '—';
  6. }
  7. return value.toLocaleString('ko-KR', {
  8. minimumFractionDigits: fractionDigits,
  9. maximumFractionDigits: fractionDigits
  10. });
  11. }
  12. // bp(만분율) → % 문자열 (부호 없이 절대값, 색·부호는 마크업에서 병행). 예: 1234 → "12.34%"
  13. export function formatBpRate(bp: number|null|undefined): string {
  14. if (bp === null || bp === undefined) {
  15. return '—';
  16. }
  17. return `${(Math.abs(bp) / 100).toFixed(2)}%`;
  18. }
  19. // 금리 % (미고시 null → —). 예: 3.5 → "3.50%"
  20. export function formatRatePercent(value: number|null|undefined, fractionDigits = 2): string {
  21. if (value === null || value === undefined) {
  22. return '—';
  23. }
  24. return `${value.toFixed(fractionDigits)}%`;
  25. }
  26. // 최신 기준일 라벨 (tradeDate null 이면 대체 문구)
  27. export function tradeDateLabel(date: string|null|undefined): string {
  28. return date ? `${date} 기준` : '데이터 준비 중';
  29. }
  30. // 공시 접수번호 → DART 원문 링크
  31. export function dartViewerUrl(rceptNo: string): string {
  32. return `https://dart.fss.or.kr/dsaf001/main.do?rcpNo=${encodeURIComponent(rceptNo)}`;
  33. }
  34. // SEIBro 코드 → 라벨 조회 (미매칭 시 원문 코드, 값 없으면 —)
  35. export function codeLabel(code: string|null|undefined, map: Record<string, string>): string {
  36. if (code === null || code === undefined || code === '') {
  37. return '—';
  38. }
  39. return map[code] ?? code;
  40. }
  41. // 주식수 등 정수 수량 (null 은 —). 예: 12345678 → "12,345,678"
  42. export function formatShares(value: number|null|undefined): string {
  43. if (value === null || value === undefined) {
  44. return '—';
  45. }
  46. return value.toLocaleString('ko-KR');
  47. }
  48. // 큰 금액(원/USD) → 조/억/만 축약 (외화커스터디·ELS 미상환·채권 발행액). null·0 은 —
  49. export function formatAmountCompact(value: number|null|undefined, unit = '원'): string {
  50. if (!value) {
  51. return '—';
  52. }
  53. const eok = value / 100_000_000;
  54. if (eok >= 10_000) {
  55. const jo = Math.floor(eok / 10_000);
  56. const rest = Math.floor(eok % 10_000);
  57. return rest > 0 ? `${jo.toLocaleString('ko-KR')}조 ${rest.toLocaleString('ko-KR')}억${unit}` : `${jo.toLocaleString('ko-KR')}조${unit}`;
  58. }
  59. if (eok >= 1) {
  60. return `${Math.floor(eok).toLocaleString('ko-KR')}억${unit}`;
  61. }
  62. const man = value / 10_000;
  63. if (man >= 1) {
  64. return `${Math.floor(man).toLocaleString('ko-KR')}만${unit}`;
  65. }
  66. return `${value.toLocaleString('ko-KR')}${unit}`;
  67. }
  68. // yyyy-MM-dd 없으면 대체문구
  69. export function dateOrDash(date: string|null|undefined): string {
  70. return date && date.length > 0 ? date : '—';
  71. }
  72. // 총회시각 HHmm → "HH:mm" (없으면 빈 문자열)
  73. export function meetingTimeLabel(hhmm: string|null|undefined): string {
  74. if (!hhmm || hhmm.length < 3) {
  75. return '';
  76. }
  77. const padded = hhmm.padStart(4, '0');
  78. return `${padded.slice(0, 2)}:${padded.slice(2, 4)}`;
  79. }
  80. // KOSIS 수록시점 → 표시 라벨 (월간 YYYYMM → "YYYY.MM", 연간 YYYY 그대로, 그 외 원문). null 은 —
  81. export function macroPeriodLabel(period: string|null|undefined): string {
  82. if (!period) {
  83. return '—';
  84. }
  85. if (/^\d{6}$/.test(period)) {
  86. return `${period.slice(0, 4)}.${period.slice(4, 6)}`;
  87. }
  88. return period;
  89. }
  90. // 거시지표 값 (천 단위 구분 + 소수 최대 2자리 — 단위는 마크업에서 병기). null 은 —
  91. export function formatMacroValue(value: number|null|undefined): string {
  92. if (value === null || value === undefined) {
  93. return '—';
  94. }
  95. return value.toLocaleString('ko-KR', { maximumFractionDigits: 2 });
  96. }