Files
2026-08-31 14:33:53 +09:00

14 KiB

US2KR — 미국 장 마감 → 한국 장 시작 전 브리핑 봇 (설계 계획)

작성일: 2026-08-25

1. 목표

미국 정규장이 끝난 뒤(16:00 ET), 한국 장 시작(09:00 KST) 전에 하루 1회 미국 시장 요약 브리핑을 자동 생성·발송하는 Python 상주 프로그램.

  • 입력: 지수/선물/금리/환율/원자재, 한국 연관 종목(반도체·ADR), 뉴스, 실적·경제지표 일정
  • 처리: 수집 → 정규화/저장 → MiniMax(M3)로 요약(한국 시장 관점 포함) → Markdown 렌더링
  • 출력: Telegram(기본) / Slack / 이메일 + 로컬 아카이브
  • 운영: 24시간 상주, 휴장일·서머타임 자동 처리, 실패 시 알림

2. 시간 설계 (핵심)

항목 ET KST
미국 정규장 마감 16:00 05:00 (EDT, 311월) / 06:00 (EST, 113월)
애프터마켓 실적 발표 집중 16:00~17:30 05:00~06:30
애프터마켓 종료 20:00 09:00 / 10:00
한국 동시호가 / 개장 — 08:30 / 09:00

실행 시각 규칙 (하드코딩 금지, 거래소 캘린더 기반 계산)

  • 메인 브리핑: XNYS 세션 종가 시각 + 75분 → 대략 06:15 (EDT) / 07:15 (EST) KST
    • 애프터마켓 실적 반응까지 포함, 한국 개장 전 1.5시간 이상 여유
    • 조기 폐장일(예: 추수감사절 다음날 13:00 ET)도 캘린더의 실제 close 시각을 따르므로 자동 대응
  • (선택) 개장 직전 업데이트: 08:20 KST — 야간 선물·환율·주요 헤드라인 5줄 요약
  • 미국 휴장 → 해당일 스킵. 한국 휴장 → 리포트는 만들되 헤더에 "오늘 한국 휴장" 표기 (설정으로 스킵 가능)
  • 시간대는 반드시 zoneinfo(America/New_York, Asia/Seoul)로 처리. 서머타임 전환 자동.
  • 라이브러리: exchange_calendars (XNYS, XKRX 모두 지원 → 휴장일·조기폐장·세션 시각)

3. 데이터 소스

원칙: 무료·키 불필요를 1차, 장애 대비 2차 소스, 일부 실패해도 리포트는 발행(누락 항목 표기).

3.1 시세 (yfinance 1차, Stooq/Finnhub 2차)

  • 지수: ^GSPC ^DJI ^IXIC ^RUT ^VIX ^SOX
  • 선물(야간 흐름): ES=F NQ=F YM=F
  • 금리: ^IRX ^FVX ^TNX ^TYX (2y는 ^FVX 대체 또는 FRED)
  • 환율/달러: KRW=X DX-Y.NYB JPY=X
  • 원자재/크립토: CL=F GC=F HG=F BTC-USD
  • 섹터 ETF: XLK XLF XLE XLV XLI SMH
  • 한국 연관: EWY(MSCI Korea ETF), ADR CPNG KB SHG PKX KEP LPL SKM, 반도체 NVDA TSM MU AMD AVGO ASML, 빅테크 AAPL MSFT GOOGL AMZN META TSLA
  • 수집 항목: 종가, 전일대비 %, 장중 고저, 애프터마켓 가격(가능한 경우), 거래량 비율

3.2 뉴스 (RSS, feedparser)

  • CNBC Top News / Markets, MarketWatch, Yahoo Finance, Investing.com, Fed 보도자료 RSS
  • 최근 18시간 이내 기사만, 제목+요약+링크, 중복 제거(제목 유사도)
  • 상위 N개(예: 40개)만 LLM에 전달 → 토큰 통제

3.3 일정

  • 당일 발표된 주요 경제지표(CPI, 고용, FOMC 등)와 다음 24시간 예정 이벤트
  • 1차: FRED API(무료 키) 로 실제 발표값 확인, 2차: Finnhub economic calendar(무료 티어)
  • 애프터마켓 실적: yfinance earnings_dates 또는 Finnhub earnings calendar

3.4 저장 (SQLite)

  • snapshots(date, symbol, close, chg_pct, ...) — 전일·주간 비교("연속 3일 하락" 등) 가능
  • reports(date, json, markdown, sent_at, channel) — 중복 발송 방지(idempotency) 및 아카이브

4. 요약 (MiniMax API)

2026-08-25 확정: 요약 LLM은 MiniMax 사용. .env의 MINIMAX_API_KEY(Coding/Token Plan 키, sk-cp-…)로 글로벌 엔드포인트 https://api.minimax.io 에서 M3/M2.7/M2.5 호출 및 JSON Schema 출력·reasoning_split 동작을 실제 호출로 검증함. (중국 엔드포인트 api.minimaxi.com 은 이 키로 401 → 사용 금지)

  • 엔드포인트: OpenAI 호환 POST https://api.minimax.io/v1/chat/completions
    • 클라이언트: openai SDK에 base_url="https://api.minimax.io/v1" 지정 (재시도·타임아웃 내장). 순수 httpx 로 대체 가능
    • Anthropic 호환 …/anthropic/v1/messages 도 동작하지만, 한 가지로 통일 → OpenAI 호환 채택
  • 모델: 기본 MiniMax-M3 (1M 컨텍스트, thinking 제어 가능, 프롬프트 캐시 cached_tokens 확인됨)
    • 장애/오류 시 폴백: MiniMax-M2.7 → MiniMax-M2.5 (설정으로 순서 변경)
    • M2.x 는 thinking 비활성 불가 → 반드시 reasoning_split 사용
  • 필수 요청 파라미터
    • reasoning_split: true → 추론이 message.reasoning_content 로 분리되고 content 에는 답만 남음 (미설정 시 content 안에 <think>…</think> 가 섞여 나옴 — 방어적으로 <think> 블록 strip 유틸도 둠)
    • response_format: {"type":"json_schema","json_schema":{"name":…,"schema":…}} → Pydantic 모델의 model_json_schema() 를 그대로 사용, 응답은 model_validate_json 으로 검증
    • max_completion_tokens: 8192 (리포트 JSON + 추론 여유). M3 권장 상한 131072
    • M3 한정 thinking: {"type":"adaptive"} (기본) — 요약 품질 위해 켜둠. 비용/속도 필요 시 disabled
  • 프롬프트 캐시: 고정 시스템 프롬프트(역할·출력 규칙·용어집·스키마 설명)를 앞에, 당일 데이터는 user 메시지 뒤에 → prompt_tokens_details.cached_tokens 로 적중 확인
  • LLM 계층 추상화: us2kr/llm/base.py 에 summarize(payload) -> ReportSchema 인터페이스, llm/minimax.py 구현. 나중에 Claude/OpenAI 로 바꾸려면 구현체만 추가 (프롬프트·스키마는 공용)
  • 리포트 스키마(초안):
    headline: str                 # 한 줄 총평
    market_overview: str          # 지수/섹터 흐름 3~5문장
    key_drivers: list[str]        # 상승/하락 요인
    rates_fx_commodities: str     # 금리·달러·원화·유가
    korea_implications: list[str] # 반도체/SOX, 환율, ADR, EWY → 한국 장 시사점
    watchlist_today: list[str]    # 오늘 한국 장에서 볼 것(지표 발표, 실적, 이벤트)
    risk_flags: list[str]         # 주의사항
    data_gaps: list[str]          # 수집 실패 항목(투명성)
    
  • 프롬프트 원칙: 숫자는 제공 데이터만 사용(환각 금지), 확인 안 된 뉴스는 "보도에 따르면" 표기, 투자 조언 아닌 정보 요약 톤, 출력 언어 한국어
  • 비용: Coding/Token Plan 구독 키 → 토큰당 과금 없이 플랜 쿼터 소모. 1일 1~2회 호출(입력 ~15K/출력 ~3K 토큰)이라 쿼터 부담 미미. 레이트리밋·쿼터 초과(429) 시 지수 백오프 재시도 후 폴백 모델

5. 발송

  • 1차: Telegram Bot (python-telegram-bot 또는 raw HTTPS) — 설정 가장 단순, 모바일 알림
  • 선택: Slack Incoming Webhook, 이메일(SMTP), 로컬 reports/YYYY-MM-DD.md
  • Telegram 4096자 제한 → 섹션 단위 분할 전송, 또는 요약본 + 전체본 파일 첨부
  • 실패 알림: 파이프라인 예외·데이터 전부 누락 시 운영자 채널로 에러 메시지

6. 상주 실행 구조

[daemon.py]  APScheduler(BackgroundScheduler)
   ├─ 매일 00:05 ET: 캘린더 조회 → 오늘 XNYS 세션 있으면 close+75m 에 run_briefing 예약
   ├─ (선택) 08:20 KST: run_premarket_update
   ├─ 매시간: heartbeat(로그/헬스파일) 
   └─ 예외 → 재시도(3회, 지수 백오프) → 실패 알림
  • 프로세스 감시자는 OS에 맡김: macOS launchd(KeepAlive) / Linux systemd(Restart=always) / Docker(restart: unless-stopped)
  • 재시작 후에도 중복 발송 방지: reports 테이블에 당일 기록 있으면 스킵
  • 시각 판단은 항상 "다음 실행 시각 계산" 방식 → 프로세스가 죽었다가 살아나도 놓친 브리핑은 catch-up 정책(마감 후 3시간 이내면 즉시 실행, 아니면 스킵)
  • 로깅: logging + 일자별 회전 파일, 수집 원본 JSON도 날짜별 보관(디버깅용)

7. 프로젝트 구조

US2KR/
├── pyproject.toml            # deps: openai(MiniMax OpenAI-호환 클라이언트), yfinance, feedparser, exchange_calendars,
│                             #       apscheduler, pydantic, pydantic-settings, python-dotenv
├── .env.example              # MINIMAX_API_KEY, MINIMAX_BASE_URL(=https://api.minimax.io/v1), MINIMAX_MODEL(=MiniMax-M3),
│                             # TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, FRED_API_KEY ...
├── us2kr/
│   ├── config.py             # pydantic-settings, 심볼 목록, 실행 오프셋 등
│   ├── market_time.py        # exchange_calendars 래퍼: 세션/휴장/다음 실행 시각
│   ├── collectors/
│   │   ├── base.py           # Collector 프로토콜, 타임아웃·재시도·실패 격리
│   │   ├── prices.py         # yfinance (+fallback)
│   │   ├── news.py           # RSS
│   │   └── events.py         # 경제지표·실적 일정
│   ├── store.py              # SQLite (snapshots, reports)
│   ├── llm/
│   │   ├── base.py           # LLM 인터페이스 + ReportSchema(Pydantic)
│   │   ├── minimax.py        # OpenAI-호환 호출, reasoning_split, json_schema, 폴백
│   │   └── prompts.py        # 시스템 프롬프트(캐시 대상)·유저 템플릿
│   ├── summarize.py          # payload 구성 → llm.summarize → 검증
│   ├── render.py             # JSON → Markdown/Telegram 포맷
│   ├── deliver/
│   │   ├── telegram.py
│   │   ├── slack.py
│   │   └── file.py
│   ├── pipeline.py           # run_briefing(date): collect → store → summarize → render → deliver
│   ├── daemon.py             # 스케줄러 상주 루프
│   └── cli.py                # us2kr run-once [--date] [--dry-run] | daemon | backfill | test-notify
├── deploy/
│   ├── com.us2kr.daemon.plist
│   ├── us2kr.service
│   └── Dockerfile / compose.yaml
├── tests/                    # market_time(서머타임·휴장·조기폐장), render, 파이프라인(수집기 mock)
└── reports/                  # 생성된 브리핑 아카이브

8. 구현 단계

단계 내용 완료 기준
P1 MVP config, prices collector, llm/minimax, summarize, render, run-once --dry-run 터미널에서 오늘자 브리핑 Markdown 출력
P2 스케줄 market_time, daemon, store(idempotency), catch-up 서머타임·휴장·조기폐장 테스트 통과, 상주 실행
P3 데이터 확장 news, events collector, 전일 대비 비교, data_gaps 뉴스·일정 포함 리포트
P4 발송 Telegram(+파일 아카이브), 실패 알림, 분할 전송 실제 폰으로 수신
P5 배포 launchd/systemd/Docker, 로그 회전, README 재부팅 후 자동 기동, 1주 무인 운영
P6 (선택) 08:20 개장 직전 업데이트, Slack/이메일, 주간 리뷰 —

9. 결정 필요 사항 (기본값으로 진행하되 바꿀 수 있음)

  1. 발송 채널: 기본 Telegram. Slack/이메일 원하면 P4에서 추가
  2. 실행 환경: 이 Mac에서 launchd로 상주 vs 별도 서버/Docker. 기본은 Mac launchd + Docker 파일 동봉
  3. 데이터 유료화 여부: 기본 무료(yfinance/RSS/FRED). 안정성 필요하면 Polygon/Finnhub 유료 티어
  4. 리포트 톤/길이: 기본 A4 1장 내 한국어. 영어 병기 여부
  5. 08:20 프리마켓 업데이트 포함 여부 (기본 미포함, 옵션)

10. 리스크와 대응

  • yfinance 비공식 API → 스키마 변경/차단 가능: 수집기 추상화 + 2차 소스 + 실패 시에도 발행
  • 서머타임 전환 주 오류 → zoneinfo + 캘린더 기반 계산, 전환일 단위 테스트
  • LLM 환각(숫자) → 구조화 출력 + "제공 데이터만 사용" 규칙 + 렌더링 시 숫자는 원본 데이터에서 직접 삽입
  • MiniMax <think> 누출 / JSON 깨짐 → reasoning_split 필수 + strip 유틸 + Pydantic 검증 실패 시 1회 재요청
  • MiniMax 장애·429 → 모델 폴백(M3→M2.7→M2.5) → 그래도 실패면 LLM 없이 '숫자 요약표만' 발송(degraded mode)
  • 중복/누락 발송 → SQLite 기록 기반 idempotency + catch-up 정책
  • 키 유출 → .env + .gitignore, 로그에 시크릿 마스킹

11. 구현 현황 (2026-08-25)

P1~P5 코드 구현 완료. 검증: pytest 287개 통과, ruff 클린, 라이브 dry-run(MiniMax-M3 요약 포함) 정상, 데몬 기동/스케줄/SIGTERM 종료 확인.

영역 파일 상태
시간/캘린더 us2kr/market_time.py ✅ XNYS/XKRX, 조기폐장·DST·휴장 테스트, 임시휴장 override(US2KR_KRX_EXTRA_HOLIDAYS)
수집 collectors/prices.py, news.py, events.py ✅ yfinance 배치 + 애프터마켓(1분봉), RSS 7개, FRED(키 필요)·실적
요약 llm/minimax.py, llm/prompts.py, summarize.py ✅ M3→M2.7→M2.5 폴백, reasoning_split, JSON Schema, 수리 재시도
저장/렌더 store.py, render.py ✅ SQLite(WAL), 히스토리 노트, Markdown + Telegram HTML 청크
발송 deliver/file.py, deliver/telegram.py ✅ 파일 아카이브 항상, Telegram은 토큰 설정 시 (아직 미설정)
오케스트레이션 pipeline.py, daemon.py, cli.py, logging_setup.py ✅ 멱등성(저장→발송 순), catch-up, misfire 복구, 시크릿 마스킹
배포 deploy/ ✅ launchd / systemd / Docker 파일 (미설치)

남은 운영 작업:

  1. .env에 TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID 추가 → us2kr test-notify로 확인
  2. (선택) FRED_API_KEY 추가 → 경제지표 섹션 활성화
  3. bash deploy/install-launchd.sh로 상주 등록 (노트북이면 pmset 예약 기동 필요)
  4. 첫 실제 브리핑(2026-08-26 06:15 KST) 결과 확인 후 프롬프트/길이 튠

알려진 제한: 실적 스캔은 15종목 상한(ADR 일부 미포함), 뉴스는 수집 시점 기준 상한 없음(정규 실행에는 무영향), LLM 산출 data_gaps는 렌더에 미표시.