stocks: 미국 주식 지원(개별 종목) + datacollect LLM 직접 호출 + 백엔드 기본 NAS

미국 주식 (개별 종목 조회 — add/check/judge/analysis/position):
- marketUtils: KR(6자리)/US(티커) 시장 판별, 통화·시총 포매팅($/원, B·T/억·조)
- yahooClient: US는 raw 티커(.KQ/.KS 미부착), 심볼 라우팅 분리
- yahooFundamentals: Yahoo quoteSummary(무키) cookie+crumb 핸드셰이크로 ROE/PER/PBR/마진/성장/부채 fetch (429·crumb 하드닝)
- fundamentalsRouter: 심볼별 Naver(KR)/Yahoo(US) 분기
- criteriaEval: market-aware — US는 유보율 미보고라 유동성·안정성을 부채비율(D/E)·시총($B)으로 대체
- types: Stock.market 필드; slashStocks/llmJudge: 통화·라우팅·프롬프트 US 대응
- 테스트: stocksMarket + criteriaEval US 케이스 (전체 통과)

datacollect/llm.ts: LLM을 확장(PC)에서 직접 호출(과거 bridge /api/lm 프록시 제거)
 → 백엔드 NAS 이전 시 PC→NAS→PC 실패 제거, 스크래핑=NAS·LLM 추론=PC 분리

package.json: datacollectBridge 기본값 nas + https://dc.koritips.com; 버전 2.2.261

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 18:43:04 +09:00
parent 4288b212d5
commit e6d780be61
13 changed files with 531 additions and 119 deletions
+16 -11
View File
@@ -1,19 +1,26 @@
import { logError, logInfo } from '../../utils';
import { detectMarket } from './marketUtils';
/**
* Yahoo 심볼 후보 생성 — 시장에 따라 suffix 처리.
* - 이미 '.' 있으면 (예: 005930.KS, BRK.B) 그대로 단일 후보.
* - 한국(6자리): `.KQ`(코스닥) 우선, `.KS`(코스피) 재시도.
* - 미국(알파벳 티커): suffix 없이 raw 그대로. (`AAPL.KQ` 로 잘못 붙던 버그 차단.)
*/
function yahooCandidates(symbol: string): string[] {
if (symbol.includes('.')) return [symbol];
return detectMarket(symbol) === 'US' ? [symbol] : [`${symbol}.KQ`, `${symbol}.KS`];
}
/**
* Yahoo Finance public chart endpoint 로 현재가 fetch. invest_results/quick_check.js
* 의 동일 로직 — symbol 에 suffix 없으면 `.KQ` (코스닥) 우선, 실패 시 `.KS` (코스피) 재시도.
* 의 동일 로직 — 한국 심볼은 `.KQ`/`.KS` 자동 부착, 미국 티커는 그대로.
*
* Yahoo 가 한국 종목은 `<6자리>.KQ` 또는 `<6자리>.KS` 형식. US 종목은 그대로.
* symbol 에 이미 `.` 있으면 그대로 사용.
*
* Returns null 이면 두 suffix 다 실패 — 호출자가 skip 처리.
* Returns null 이면 모든 후보 실패 — 호출자가 skip 처리.
*/
export async function fetchYahooPrice(symbol: string, timeoutMs = 8000): Promise<number | null> {
if (!symbol) return null;
const candidates: string[] = symbol.includes('.')
? [symbol]
: [`${symbol}.KQ`, `${symbol}.KS`];
const candidates: string[] = yahooCandidates(symbol);
for (const yahooSymbol of candidates) {
try {
@@ -73,9 +80,7 @@ export interface YahooHistory {
export async function fetchYahooHistory(symbol: string, timeoutMs = 10000): Promise<YahooHistory | null> {
if (!symbol) return null;
const candidates: string[] = symbol.includes('.')
? [symbol]
: [`${symbol}.KQ`, `${symbol}.KS`];
const candidates: string[] = yahooCandidates(symbol);
for (const yahooSymbol of candidates) {
try {