pykrx 에 의존하지 않고, 자체 클라이언트로 KRX·Naver·OpenDART 데이터를 직접 호출해
한국 주식 모닝 브리핑 데이터와 코스피200 추천 스크리너를 JSON 으로 생성하는 파이프라인.
산출 JSON 은 AI(Claude 등)가 읽어 장 시작 전 브리핑을 작성하는 입력으로 쓴다.
⚠️ 면책: 투자 자문이 아니다. 공개 데이터 기반 단순 스크리닝이며, 모든 투자 판단·손익 책임은 사용자에게 있다.설계 원칙·판단 기준·의사결정 근거는 docs/DESIGN.md, 전체 시스템 구조(Layer·데이터 흐름·Processor 확장법)는 ARCHITECTURE.md 참조. 출력 수치는 실측값(또는 보편식 파생)만 쓰고 추측·근사는 넣지 않는다.
- 모닝 브리핑 —
python -m krxfree.briefing→results/briefing_data.json- 보유종목 현재가·등락률·RSI·이동평균·피벗·평가손익 + KOSPI/KOSDAQ 지수 + 미국 종목
- 보유종목은
portfolio.json에서 읽음(무로그인: Naver·KRX OpenAPI·yfinance)
- 코스피200 스크리너 —
python -m krxfree.screener→results/kospi200_screen.json- 다중 팩터(모멘텀·가치·유동성·사이즈) 점수화 + 기술적·재무 가점으로 추천
- 유니버스: KRX 로그인 시 코스피200 구성종목 자동 조회, 아니면 시총 상위 200 근사
- 무인 자동화 — GitHub Actions(
.github/workflows/krx-morning.yml, 매 영업일 08:05 KST)가 브리핑·스크리너·포트폴리오 엔진을 실행해 Cloudflare Worker(KV)에 업로드, Claude 예약이 WebFetch로 읽음. 로컬 PC 상태와 무관하게 동작. 기존 Windows 작업 스케줄러(automation/)는 백업용으로 비활성화 상태로 남겨둠(§자동화 참조). - Knowledge Engine —
knowledge/company/{종목코드}/에 기업별 공시 이력·투자 Investment Case 를 장기 누적(스크리너 실행마다 자동 증분 업데이트). 아래 Knowledge Engine 참조.
results/*.json 은 매번 새로 덮어써지는 일회성 브리핑 데이터지만, knowledge/company/{종목코드}/
는 시간이 지날수록 쌓이는 장기 데이터다. 스크리너(python -m krxfree.screener) 를 돌릴 때마다
보유종목의 공시 이벤트가 자동으로 여기 누적된다(삭제 없음, 증분만).
파일 4개 중 manual.json 만 직접 편집하는 파일이고 나머지는 자동 생성(커밋 안 됨):
| 파일 | 누가 채우나 | 우선순위 |
|---|---|---|
manual.json |
사용자가 직접 작성 | 최우선 |
dart.json |
(예정, 아직 없음) | 2순위 |
generated.json |
Processor 자동 계산(timeline 등) | 3순위 |
merged.json |
위 3개를 합친 최종 결과 | — |
knowledge/company/005930/manual.json 을 직접 만들어서 관심 있는 투자 테마를 정의하면,
그 종목 timeline 에서 키워드가 매칭되는 공시만 모아 자동으로 상태(강화/유지/약화)·추세·근거를 계산한다:
{
"investment_cases": [
{"name": "HBM 성장", "keywords": ["HBM", "고대역폭메모리"], "importance": 95}
]
}keywords에 매칭되는 공시가 없으면 그 case 는 그냥 "관련 이벤트 없음"으로 남는다(테마를 억지로 지어내지 않음).status/trend/reason은 매칭된 실제 공시의impact_score·날짜로만 계산(LLM 추론 없음, 재현 가능).founder/ceo/website/products/competitors같은 필드도 같은 방식으로manual.json에 채워 넣으면merged.json에 최우선으로 반영된다(DART 가 안 주는 정보라 자동 채움은 없음).
merged.json 의 digest 는 timeline 을 월/분기/연 단위로 압축한 것(자연어 요약 아님 — 브리핑
작성 시 LLM 이 이걸 읽고 문장을 만든다). 묶는 단위·기간별 최대 이벤트 수는 config/digest_rules.json
에서 바꾼다(코드 수정 불필요):
{"period_unit": "month", "max_events_per_period": 5, "include_event_types": null,
"exclude_event_types": [], "sort": "desc"}저장소 루트에 .env 생성. 양식은 .env.example 참고.
KRX_ID=<KRX 로그인 ID> # 스크리너 PER/PBR·구성종목 자동조회용 (브리핑엔 불필요)
KRX_PW=<KRX 로그인 PW>
KRX_API=<KRX OpenAPI 인증키> # https://openapi.krx.co.kr
DART_API=<OpenDART 인증키> # https://opendart.fss.or.kr
- 브리핑만 돌릴 거면
KRX_API만 있으면 됨(로그인 불필요). - 스크리너는 PER/PBR(가치 팩터)·구성종목 자동조회 위해
KRX_ID/KRX_PW, 재무 가점 위해DART_API필요. .env는 평문 저장 → git 커밋 금지(.gitignore등록됨).- KRX OpenAPI 는 서비스별 이용신청 필요, 인증키 최대 12개월 후 만료. DART 는 키 1개로 전체 접근.
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS/Linux
source .venv/bin/activate
pip install -e .저장소 루트에서:
python -m krxfree.briefing # -> results/briefing_data.json (무로그인)
python -m krxfree.screener # -> results/kospi200_screen.json (KRX 로그인 + DART)보유종목·평단은 코드가 아니라 루트의 portfolio.json 에서 읽는다(개인정보 분리, git 제외). 없으면 브리핑은 지수만 산출. 양식은 portfolio.json.example 참고.
{
"holdings": [
{"market": "KR", "name": "삼성전자", "code": "005930", "shares": 10, "avg": 70000},
{"market": "US", "name": "엔비디아", "ticker": "NVDA", "shares": 1, "avg": 100},
{"code": "000660"},
{"ticker": "AAPL"}
]
}- 최소 입력: 국내는
code(6자리), 미국은ticker(yfinance 심볼) 하나만 있으면 된다(위 3·4번째). 나머지(name/shares/avg/market)는 생략 가능. shares+avg(평단) 있으면 평가손익 계산(KRpnl_krw/ USpnl), 없으면 시세·지표만 표기.name생략 시 코드/티커로 대체.market생략 시ticker있으면 US, 없으면 KR 자동 판정.
.github/workflows/krx-morning.yml 이 매 영업일 08:05 KST(cron 5 23 * * 0-4, TZ=Asia/Seoul 고정)에
briefing → screener → portfolio_engine 순서로 실행하고, 산출 JSON 3종(briefing/screen/portfolio)을
Cloudflare Worker(cloudflare-worker/worker.js, KV: KRX_DATA)에 POST 업로드한다. Claude 예약은
로컬 파일이 아니라 이 Worker를 WebFetch로 읽는다(results/SKILL.md/SKILL_V2.md 참조).
- 필요 GH repo secrets:
KRX_ID/KRX_PW/KRX_API/DART_API/PORTFOLIO_JSON/WRITE_TOKEN. - Worker 읽기는
READ_TOKEN(쿼리파라미터)으로 인증 — WebFetch가 커스텀 헤더를 지원하지 않아 불가피한 구조. 유출 우려 시 로테이션(wrangler secret put READ_TOKEN+results/SKILL*.md값 갱신). - 수동 실행:
gh workflow run "KRX Morning Data" --repo <owner>/krxbrief - Claude 예약 세팅:
results/SKILL_example.md(또는SKILL_V2_example.md)을results/SKILL.md로 복사한 뒤YOUR-WORKER-SUBDOMAIN·YOUR_READ_TOKEN·YOUR_SLACK_CHANNEL_ID를 실제 값으로 채운다. 실 파일은 토큰이 들어가므로 커밋하지 않는다(gitignore 처리됨).
로컬 PC 의존 없이 위 GH Actions로 전환하면서 기존 로컬 자동화는 비활성화만 해두고 삭제하지 않음(언제든 복원 가능).
schtasks /query /tn KRX_Morning_Data /v /fo LIST :: 상태 확인
schtasks /change /tn KRX_Morning_Data /enable :: 복원(재활성화)
schtasks /change /tn KRX_Morning_Data /disable :: 다시 비활성화automation/register_krx_task.ps1이 배터리 무관 시작·절전 깨우기(WakeToRun)·놓친 실행 따라잡기(StartWhenAvailable)까지 설정해 등록(.bat은 관리자 권한 자가승격 런처). 처음부터 다시 등록하려면automation\register_krx_task.bat더블클릭.automation/run_morning.ps1이 루트의 venv 로python -m krxfree.briefing→krxfree.screener를 일괄 실행(로컬results/에만 저장, Worker 업로드 없음).
krxfree/ 패키지
├─ paths.py 루트·결과·.env 경로
├─ loaders.py portfolio.json / kospi200_members.json 로더
├─ briefing.py 모닝 브리핑 진입점 (python -m krxfree.briefing)
├─ screener.py 코스피200 스크리너 진입점 (python -m krxfree.screener)
└─ clients/
├─ naver.py Naver OHLCV (무인증)
├─ openapi.py KRX 공식 OpenAPI — 지수·전종목 시세 (인증키)
├─ login.py KRX 로그인 — PER/PBR·지수구성종목·외국인수급 (로그인)
├─ dart.py OpenDART — 성장률/ROE/부채/업종/공시/유증·CB 상세 (인증키)
├─ news.py Google News RSS — 종목명 최근 기사 수 (무인증)
└─ macro.py 미국10년물·달러원(FRED)·코스피추세·외국인수급 — ETF 보유 판단용
.github/workflows/krx-morning.yml GH Actions — 매 영업일 08:05 KST 무인 실행 + Worker 업로드
cloudflare-worker/ worker.js · wrangler.toml (krx-proxy, KV: KRX_DATA)
automation/ run_morning.ps1 · register_krx_task.ps1 / .bat (로컬 백업, 현재 비활성화)
docs/DESIGN.md 설계 원칙·판단요소·의사결정 기록
results/ 산출 JSON (자동 생성, 내용물 gitignore)
results/SKILL.md · SKILL_example.md Claude 예약이 읽는 브리핑 스킬 지시서(_example=양식, 실 파일은 READ_TOKEN 포함이라 gitignore)
results/SKILL_V2.md · SKILL_V2_example.md 위와 동일(버핏 스타일 버전)
portfolio.json[.example] 보유종목 입력(.example=양식). 입력은 gitignore
.env[.example] 자격증명·인증키(.example=양식). .env 커밋 금지
pyproject.toml 의존 패키지(dependencies) + 빌드 설정
corp_map.json / sector_map.json DART 캐시 (자동 생성, gitignore)
의존 패키지 (pyproject.toml): pandas · numpy · requests · python-dotenv · yfinance(미국 시세, 미설치 시 해당 항목 생략) · defusedxml(RSS 파싱). 그 외는 표준 라이브러리.
호출량(1회): KRX OpenAPI 2~5콜 · KRX 로그인 1회(PER/PBR+구성종목) · Naver ~25콜 · DART ~25콜(캐시) · company.json ~25콜(업종, 캐시).
results/ 의 JSON 파일을 Claude(또는 다른 AI)에 첨부해 아침 브리핑을 받는 데 주로 쓴다.
| 파일 | 내용 | AI 활용 |
|---|---|---|
briefing_data.json |
보유종목 시세·손익·기술적 지표 + 지수 | 내 포트폴리오 현황 브리핑 |
kospi200_screen.json |
코스피200 팩터 스코어 + 추천 종목 | 오늘 주목할 종목 분석 |
모닝 브리핑 + 스크리너 분석 (briefing_data.json + kospi200_screen.json 첨부 후):
portfolio.json 이 없어도 두 파일은 정상 생성된다(보유종목 없는 상태로). 그 경우 1·2번은 자연히 빈 결과로 건너가고 3~5번(스크리너 분석)만 의미 있게 동작한다.
briefing_data.json = 내 현재 포트폴리오(시세·손익·기술적 지표)
kospi200_screen.json = 오늘 코스피200 스크리닝 결과(팩터/공시/뉴스/매크로 포함)
다음을 알려줘.
1. 내 보유종목별 등락률·평가손익 요약하고, RSI·이동평균으로 주의 필요한 종목 짚어줘.
2. 보유종목이 kospi200_screen.json의 recommendations에도 있는지 확인하고,
있으면 thesis(오늘/30일/1년 누적 점수·상태·reasons·action·buffett_lens)·
momentum_label·disclosure까지 같이 설명해줘.
3. recommendations 상위 종목 중 팩터 균형이 좋은 것(가치 PER/PBR + 모멘텀이 함께 좋은
종목) 위주로 설명해줘. momentum_label도 같이 확인:
- "원인 불명 변동성"/"재료 미확인 상승"인 종목은 따로 모아서 왜 그런지(뉴스 적음/실적
근거 없음) 짚어주고 추격 매수 주의 종목으로 표시해줘.
- "실적 동반 상승"/"공시 모멘텀"인 종목은 근거를 같이 설명해줘.
4. disclosure는 dart(기업 공시)/krx(거래소 시장조치) 섹션을 반드시 구분해서 설명해줘.
dilution(특히 제3자배정·일반공모)이 있는 종목은 경고로 따로 알려줘.
disclosure_checked가 false인 종목은 "공시 미확인" 표시. thesis.state가
WEAKENED/BROKEN/UNCONFIRMED인 종목은 thesis.action.items를 행동 변화로 강조해줘.
5. kodex200_holding 섹션(보유 중이면 존재)이 있으면 close/nav/fluc_rt/momentum_pct를
macro 섹션(us10y, usdkrw, kospi, foreign_netflow_7d_won)과 같이 보고 지금 환경이
KODEX200 같은 지수상품 보유에 우호적인지 비우호적인지 한 줄로 평가해줘
(개별 공시·뉴스는 ETF엔 적용 안 됨, macro로만 판단).
매일 08:15, Claude Cowork의 반복 작업 예약하기 기능으로
briefing_data.json + kospi200_screen.json 을 자동 분석하도록 설정 가능.
- 08:05 스케줄러가 JSON 생성 완료
- 08:25 Claude Cowork 예약 브리핑 실행
⚠️ AI 분석은 참고용이며 매수·매도 지시가 아니다. 투자 판단·손익 책임은 사용자에게 있다.
- docs/DESIGN.md — 데이터 원칙(사실 기반), 가치 판단요소(스크리너 방법론), 데이터 접근 방식 의사결정 기록, 한계/확장 여지
- docs/API_LIMITS.md — 각 API 일일 한도 · 데이터 반영 시점 정리