개인 투자 리서치 시스템. 리서치·정리·계산·모니터링만 한다. 매매 판단은 하지 않는다.
클론해서 API 키만 넣으면 각자 로컬에서 돌아갑니다. 보유 종목·산출물은 이 저장소에 올라가지 않습니다 — 전부 로컬에만 남습니다.
원형이 된 방법론: Claude Code로 개인 투자 리서치 자동화한 방법 이 저장소는 그 구조를 코드로 구현하고, 웹검색 대신 1차 출처(SEC·FRED·ECB)에 직접 연결한 것입니다.
- 일일 브리핑 — 한국·미국 증시, 매크로·환율, 보유 종목 밤사이 움직임, 시장 주요 종목, 실적 임박
- 포트폴리오 콕핏 — 집중도(HHI), ETF 경유 숨은 중복 노출, 자산유형별 평가 잣대, 환노출 시나리오
- 가격 판독기 — 역DCF로 "이 가격이 요구하는 성장률"을 이분법으로 역산 + WACC 민감도
- 스토리 리더 — 연도별 공시 문구 비교 (신규/삭제 문장,
will→may톤다운, 헤지 어휘 증감) - 액션 신호 — 매수·매도가 아니라 어느 딥다이브를 돌릴지만 제시
- 급등락 이상치 경고 — 거래정지 재개·신규상장·액면분할을 걸러내고, 한국 종목은 DART 공시로 원인을 확정
- 다중 선택 배치 분석 — 여러 종목을 체크해 한 번에. 동시 실행이라 3종목 119초 (순차 300초) · 비교 표 + 종목별 접이식
- 초보자용 해설 — 시가총액·요구 성장률·FCF 같은 값을 주식·회계를 몰라도 읽을 수 있게 풀어 씀 (매매 권유는 테스트로 차단)
- 주주환원·내부자 거래 — 배당·자사주 매입(FCF 대비 %)·주식수 추이·Form 4 내부자 매매를 1차 출처로 (미국)
- 장단기 금리차 — 10y−2y 스프레드·커브 역전을 브리핑·대시보드에 파생값으로 표기
필요한 것: Python 3.11 이상. (서사 자동 작성만 Claude Code CLI 를 추가로 씁니다 — 없어도 사실 계산은 전부 돌아갑니다.)
git clone https://github.com/<you>/stock-analysis.git && cd stock-analysis
pip install requests PyYAML # 의존성 2개가 전부
cp .env.example .env # SEC_USER_AGENT 만 채워도 동작
cp portfolio/holdings.example.yaml portfolio/holdings.yaml # 데모 데이터 — 본인 것으로 바꾸세요
cp portfolio/watchlist.example.yaml portfolio/watchlist.yaml
python3 -m src.config # 무엇이 되고 안 되는지 진단
python3 -m unittest discover -s tests -t . -q # 328개 테스트 (키 없이 통과)
python3 -m src.pipelines.dashboard # → dashboard/index.html예시 보유는 데모입니다. 그대로 두면 화면이 "보유 현황이 N일 전 기준"이라고 알려줍니다 — 본인 보유로 바꾸면 사라집니다.
python3 -m src.pipelines.serve # → http://127.0.0.1:8766 ← 권장| 파일로 직접 열기 | 로컬 서버 | |
|---|---|---|
| 표·지표·차트 | ✅ | ✅ |
| 종목 검색 · 분석 생성 | ❌ | ✅ |
| 다중 선택 배치 분석 · 비교 | ❌ | ✅ |
| 보유 편집 | ❌ | ✅ |
file:// 에서는 브라우저가 /api/* 요청을 막습니다. 화면이 이를 판별해 이유를 적고
입력창을 끕니다 — 고장난 게 아닙니다.
python3 -m src.pipelines.event_scanner # 지금 볼 종목 자동 선정 → reports/events/
python3 -m src.pipelines.stock_page NVDA # 종목 상세 → dashboard/stocks/NVDA.html
python3 -m src.pipelines.company_decoder AAPL # 기업 해독 카드 → reports/cards/
python3 -m src.pipelines.story_reader NVDA # 3개년 10-K 문구 변화 → reports/story/
python3 -m src.pipelines.serve # 대시보드 + 검색 + 서사 + 다중선택 배치 (127.0.0.1:8766)
BATCH_WORKERS=6 python3 -m src.pipelines.serve # 배치 동시 실행 수 조절 (기본 4, 최대 8)
python3 -m src.pipelines.narrator TSLA # 서사만 따로 생성
python3 -m src.pipelines.editor # 포트폴리오 편집 UI (127.0.0.1:8765, 폼 방식)
# 보유 편집은 대시보드 '보유·포트폴리오' 뷰에서도 됩니다 (serve 필요)
python3 -m src.pipelines.dashboard --public # 개인 정보 뺀 공개용 → dashboard/public.html| 변수 | 용도 | 비용 | 필수 |
|---|---|---|---|
SEC_USER_AGENT |
SEC EDGAR 가 요구하는 연락처 (키 아님) | — | 예 |
FRED_API_KEY |
미국 금리·매크로 · 발급 | 무료 | 권장 |
TOSS_CLIENT_ID / TOSS_CLIENT_SECRET |
시세·지수·랭킹·환율 (한국+미국) | 무료 | 권장 |
OPENDART_API_KEY |
한국 공시·재무 · 발급 | 무료 | 한국 종목 시 필수 |
ECOS_API_KEY |
한국 기준금리·국고채 (한국 종목 할인율) · 발급 | 무료 | 권장 (한국 종목) |
FMP_API_KEY |
어닝콜 트랜스크립트 — 미구현. 키를 넣어도 동작하지 않음 | 유료 | 선택 |
키가 없으면 해당 소스만 확인 필요로 표기되고 나머지는 정상 동작합니다.
실측: 새로 클론해 SEC_USER_AGENT 하나만 채운 상태에서 대시보드가 정상 생성되고,
미국 기업 해독 카드도 나옵니다. 못 채운 부분은 화면이 스스로 이름을 대며 밝힙니다
(국내 지수 미확보 — TOSS_CLIENT_ID 미설정).
claude CLI 가 없으면 서사(해석)만 빠지고 사실 계산은 전부 돌아갑니다.
토스증권: WTS > 설정 > Open API 에서 발급하고, 같은 화면 하단 허용 IP 관리에
공인 IP를 등록해야 합니다 (curl -s ifconfig.me).
| 등급 | 정의 | 소스 | 수치 사용 |
|---|---|---|---|
| 1차 | 발행 주체가 직접 배포 | SEC EDGAR(XBRL·10-K), FRED, ECB(Frankfurter), ETF 발행사 | 허용 |
| 2차 | 벤더가 정규화·집계 | 토스증권 Open API | 허용 |
| 3차 | 비공식 스크래핑·웹검색 | 웹검색 | 금지 — 정성 전용 |
3차 출처로 수치를 만들려 하면 provenance.py 가 예외를 던집니다.
models ← sources 외부 I/O. 벤더가 바뀌면 여기만 바뀐다
↑
├──── core 순수 계산. I/O 금지. 네트워크 없이 테스트된다
↑
├──── render 표현
↑
└──── pipelines 조율. 이 계층만 셋 모두를 안다
의존은 항상 안쪽으로만. tests/test_layering.py 가 이를 검사합니다.
이 프로젝트의 핵심입니다. 원칙을 프롬프트에 적지 않고 실행 단계에서 막습니다.
| 원칙 | 구현 | 위반 시 |
|---|---|---|
| 출처 없는 숫자 금지 | provenance.require_sourced() |
렌더 단계 예외 |
| 웹검색에 페이지 번호 금지 | Source.__post_init__ |
생성 단계 예외 |
| 3차 출처로 수치 금지 | Sourced.__post_init__ |
생성 단계 예외 |
| 암산 금지 | core/valuation/reverse_dcf.py 이분법 + 수렴 진단 |
|
| 역DCF 는 기업가치 기준 | enterprise_value(시총, 순부채) — 시총만 쓰면 레버리지가 왜곡 |
|
| 가정이 숨지 않게 | basis_comparison() 최신/3년평균 병기 · growth_axes() 구간 병기 |
— |
| 변화 없으면 "변화 없음" | sentence_diff.SentenceDiff.is_material |
— |
| 매매 신호 금지 | SignalKind 에 매매 항목 부재 + Signal 이 매매 표현 거부 |
ValueError |
| 통화 혼합 합산 금지 | models.Money — 통화 다른 값의 + 자체가 예외. 콕핏은 기준통화 환산 후에만 비중·HHI·환노출 산출, 환율 미확보면 확인 필요 |
ConsistencyError |
| 회계연도-제출일 정합 | models.Filing.__post_init__ — FY 는 기간종료 연도(reportDate), 제출 연도와 어긋나면 생성 거부 |
ConsistencyError |
| 세그먼트 분모 정합 | sec_segments.denominator_check() — 소계 이중계상 감지 + 행합≠총계면 비중 미산출 |
비중 확인 필요 |
| 캐시 신선도 위조 금지 | _http.last_fetch() — 만료 캐시 폴백이면 실제 확보 시각·만료 캐시 폴백 표기가 출처에 실림 |
— |
| 벤더 등락률을 그대로 믿지 않음 | core/anomalies.py 정황 → open_dart.corporate_actions() 확정 |
— |
| 서사가 낡았는지 시간이 아니라 사건으로 | pipelines/filings.check_basis() 접수번호 대조 |
— |
| 브로커 주문 경로 차단 | toss.ALLOWED_PATHS + 계좌 헤더 미생성 |
OrderPathBlocked |
| 문서-코드 동기화 | tests/test_doc_sync.py — SKILL.md 가 인용하는 상수(분할 오차 등)·초보자 캡션을 코드와 대조 |
테스트 실패 |
| 자유텍스트 매매 표현 금지 | core/narrative/advocacy.py — 정성 관찰(macro_watch)을 렌더 전 검사, 부정문은 통과 |
해당 항목 표시 안 함 |
| 로컬 서버 CSRF·리바인딩 | pipelines/_websec.py — Host 검사 + 기동 토큰. 부작용 API 는 POST+토큰 필수 |
403 |
| 계층 의존 방향 | tests/test_layering.py |
테스트 실패 |
토스 자격증명은 주문 권한도 갖지만, 이 코드로는 주문을 낼 수 없습니다.
ALLOWED_PATHS화이트리스트 — 시세·종목·환율·랭킹 경로만X-Tossinvest-Account헤더를 생성하는 코드가 없음 — 토스는 계좌·주문 API에 이 헤더를 요구하므로, 헤더가 없으면 그 API는 애초에 동작하지 않습니다- GET 전용 (POST는 토큰 발급 1건)
tests/test_layering.py::TestBrokerBoundary 5개 테스트가 검사합니다.
.claude/skills/ 에 7개 스킬이 있습니다. Claude Code 에서 트리거 문구로 호출합니다.
| 스킬 | 트리거 | 계층 |
|---|---|---|
company-decoder |
AAPL 분석해줘 |
2층 |
story-reader |
AAPL 스토리 분석해줘 |
2층 |
price-decoder |
AAPL 지금 사도 되나 |
2층 |
portfolio-cockpit |
포트폴리오 봐줘 |
1.5층 |
daily-brief |
오늘 브리핑 |
1층 |
dashboard-refresh |
갱신해줘 |
1층 |
macro-brief |
지정학 이슈 정리 · 매크로 브리핑 |
1층 (정성) |
1층이 신호를 내고 2층이 그 신호를 받아 깊게 들어갑니다.
운영 규칙은 CLAUDE.md 에 있고 모든 스킬에 자동 적용됩니다.
| 소스 | 상태 |
|---|---|
| SEC EDGAR (재무 XBRL) | 동작 · 키 불필요 |
| Frankfurter (ECB 환율) | 동작 · 키 불필요 |
| ETF 구성종목 | 동작 · SPDR 자동 / 타 발행사는 CSV 수동 공급 |
| FRED (매크로) | 동작 · 무료 키 |
| 토스증권 (시세·지수·랭킹) | 동작 · 무료 키 |
| 10-K 본문 다운로드 | 동작 · 키 불필요 (SEC Archives) |
| 스토리 리더 (공시 문구 diff) | 동작 · 어닝콜 없이 공시 축만 |
| 기업 해독기 (재무 골격) | 동작 · 미국(SEC) + 한국(DART) |
| 세그먼트·제품·지역별 매출 | 동작 · SEC 렌더링 재무제표(R-file) · 키 불필요 |
| 순부채·총차입 추이 | 동작 · 미국 |
| 이벤트 스캐너 + 과거 반응 시나리오 | 동작 · SEC 8-K + 일봉 · 키 불필요 |
| 급등락 이상치 경고 | 동작 · 한국은 DART 공시로 확정 / 미국은 정황까지 |
| 서사 근거 보고서 추적 | 동작 · 새 10-K·사업보고서가 나오면 서사에 새 보고서 나옴 배지 |
| 다중 선택 배치 분석 | 동작 · 체크박스로 골라 동시 생성 → 비교 표 + 접이식 상세 |
| 주요 기업 목록 | 동작 · 한국 시가총액 상위(파생) / 미국 S&P 500 편입 비중(1차) |
| 초보자용 수치 해설 | 동작 · 용어 10종 + 종목별 평문 읽기 |
| 좌측 목차 · 섹션 전환 | 동작 · 스크롤 대신 목차에서 골라 한 섹션만 · 해시로 북마크 |
| 보유 편집 (대시보드 내) | 동작 · 목록 체크·검색으로 추가 · 저장 시 검증 실패면 원복 |
| 종목 상세 페이지 (사실 + 서사) | 동작 · dashboard/stocks/<티커>.html |
| 종목 검색 + 온디맨드 생성 | 동작 · 7,673종목 자동완성 · 로컬 서버 필요 |
| 서사 자동 작성 | 동작 · claude CLI 호출 · 별도 API 키 불필요 |
| 이익-현금 정합성 경고 | 동작 · 미국 |
| 주주환원 (배당·자사주·주식수) | 동작 · 미국(SEC companyfacts) · 한국은 확인 필요 표기 |
| 내부자 거래 (Form 4) | 동작 · 미국 · 원문 XML 파싱, 코드별 집계 |
| 10y−2y 스프레드 | 동작 · FRED 파생값 · 브리핑·대시보드 |
| ECOS (한국 기준금리·국고채) | 동작 · 무료 키 · 한국 종목 역DCF 할인율에 사용 |
| N-PORT ETF 구성종목 폴백 | 동작 · iShares·Vanguard 등 · 분기 지연 명시 (IVV 실측) |
| KRX 수급·공매도 | 실험적 · 비공식 엔드포인트 — 환경에 따라 미확보(사유 표기) |
| 시장 이슈 보드 | 동작 · 계량 8항목(FRED·토스·Frankfurter) + 공식 피드(Fed·ECB RSS, 1차) · 지정학은 자동 감지 안 함 |
| 지정학·매크로 정성 브리핑 | 동작 · macro-brief 스킬(NotebookLM/웹검색) → 사람 검토 → macro_watch.yaml · 매매 표현 렌더 전 차단 |
| OpenDART (한국 재무·공시목록) | 동작 · 무료 키 · 본문 파싱은 미구현 |
| 어닝콜 트랜스크립트 | 미구현 (무료 소스 없음) |
| 실적 캘린더 | 무료 소스 없음 → watchlist.yaml 수동 |
- 실시간 계좌 연동을 하지 않습니다. 보유 현황은 수동 갱신합니다.
- 자동 스케줄 실행을 하지 않습니다. 호출할 때만 돕니다.
- 한국 상장사는 어닝콜 전문 공개가 드물어 스토리 분석 정밀도가 낮습니다 — 시스템이 산출물에 스스로 명시합니다.
- 이 시스템의 어떤 결론도 투자 자문이 아닙니다. 1차 스크리너로만 쓰고, 판단에 직접 쓰는 숫자는 원문에서 재확인하십시오.
MIT