feat(stocks): discover sector — 네이버 업종 코드 직접 조회로 재설계 (v2.2.250)

[버그] discover sector 가 항상 0개 반환. 원인: sectorHint 를 통합 API 의
없는 필드(industryInfo.name)에서 읽어 전 종목이 업종 미상 → 필터 전멸.

[근본 수정] "전 종목 시총 크롤 후 sectorHint 필터" → "네이버 업종 코드로
해당 섹터 종목 직접 조회". 실측: 2차전지 1000-5000억 0개 → 36개.
- stockSectors: 친화 섹터키 → 네이버 업종코드 묶음 (업종 79개 코드표). 17개 그룹.
- naverScreener.screenIndustry(): /api/stocks/industry/{code} 직접 수집 + 시총 필터 + dedup.
- naverFundamentals: sectorHint 를 industryCode→이름 매핑으로 수정 (기술력 키워드·judge 복구).
- stockDiscovery: 섹터 모드 3키워드 게이트 완화(≥1, "섹터 내 상대 추천").
- CLI: discover sector <섹터> [min] [max] / discover sectors.

테스트 8건. 라이브 e2e 확인.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 13:55:18 +09:00
parent ae021a8c16
commit 53953fb5f8
8 changed files with 308 additions and 26 deletions
+9 -3
View File
@@ -1,4 +1,5 @@
import { logError, logInfo } from '../../utils';
import { NAVER_INDUSTRY_NAMES } from './stockSectors';
/**
* Naver Finance 비공식 JSON API 로 개별 종목 펀더멘털 fetch.
@@ -38,8 +39,8 @@ export interface Fundamentals {
interface NaverIntegrationResponse {
stockName?: string;
totalInfos?: Array<{ code: string; key: string; value: string }>;
/** 종목 분류 / 업종 정보가 들어있을 수 있음 (옵션). */
industryInfo?: { name?: string };
/** 네이버 업종 코드 (숫자). 통합 응답의 실제 필드 — industryInfo 는 존재하지 않음. */
industryCode?: number | string;
}
interface NaverFinanceAnnualResponse {
@@ -124,7 +125,12 @@ export async function fetchFundamentals(symbol: string, timeoutMs = 10000): Prom
out.currentPrice = parseNumber(map.get('closePrice') || map.get('lastClosePrice'));
out.marketCapEok = parseMarketCapText(map.get('marketValue'));
}
if (integ?.industryInfo?.name) out.sectorHint = integ.industryInfo.name;
// 업종 — 통합 응답의 industryCode(숫자) → 업종명 매핑. (구버전은 없는 industryInfo.name
// 을 읽어 항상 빈 값이었음 → '기술력' 키워드·섹터 표시가 동작 안 했던 버그 수정.)
if (integ?.industryCode !== undefined) {
const code = typeof integ.industryCode === 'string' ? parseInt(integ.industryCode, 10) : integ.industryCode;
if (Number.isFinite(code) && NAVER_INDUSTRY_NAMES[code]) out.sectorHint = NAVER_INDUSTRY_NAMES[code];
}
// finance/annual — rowList 에서 최근 확정 연도 컬럼 값.
if (fin?.financeInfo?.rowList && fin.financeInfo.rowList.length > 0) {