- Python 98.4%
- Dockerfile 1.6%
data_gap #9 (DFII10), #10 (DGS30), #13 (MORTGAGE30US) 와 1:1 매칭. 다음 자동 수집 cycle 부터 잡힘. |
||
|---|---|---|
| .claude | ||
| .forgejo/workflows | ||
| docs | ||
| frontend/streamlit | ||
| scripts | ||
| src/financial_platform | ||
| tests | ||
| .devdbrc | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .mcp.json | ||
| .pre-commit-config.yaml | ||
| .python-version | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| main.py | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
| 생성일 | 마지막수정일 | 상태 | 타입 | 접근방식 |
|---|---|---|---|---|
| 2025-10-22 | 2026-04-25 | 개발중 | 프로젝트 | 통합플랫폼 |
투자 리서치 플랫폼 (financial-data-platform)
시장 데이터 자동 수집 + 분석 리포트 저장 + Claude 스킬용 API를 제공하는 통합 플랫폼.
프로젝트 정체성
이 레포는 [투자 리서치 플랫폼 통합 로드맵]의 데이터 & API 레이어를 담당한다. 원래 OpenBB 기반 수집 전용 프로젝트로 시작했으나, 분산되어 있던 매크로 리포트 워크플로우와 종목 분석 파이프라인을 하나로 묶기 위해 FastAPI 백엔드 + 리포트 저장소까지 확장 중이다.
통합 목표:
- 토큰 절약 — Claude 스킬이 매번 웹서치하던 정량 데이터를 DB 조회로 대체
- Obsidian 의존성 탈피 — 리포트를 자체 DB에 저장하고 웹 뷰어로 접근
- 자동화 — 수집 → 분석 → 발행까지 파이프라인화
연관 프로젝트:
reports.xhhan.com— 매크로 리포트 갤러리 (통합 예정)- 주식분석 자동화 파이프라인 — 종목 분석 스킬 (통합 예정)
현재 구현 상태 (2026-04-26, v0.3.6 기준)
수집 중인 데이터 (69개 심볼 + 12개 테이블)
경제 지표 (FRED 19개)
- 유동성 3대 축:
M2SL(M2 통화량),RRPONTSYD(역레포),WTREGEN(TGA) - 연준 자산:
WALCL(Fed Balance Sheet) - 금리:
FEDFUNDS,DGS10,DGS2,T10YIE(10Y 인플레 기대) - 경제 지표:
UNRATE,CPIAUCSL,PCEPI,UMCSENT,ICSA - 채권 스프레드:
BAMLH0A0HYM2(하이일드),BAMLC0A0CM(IG) - 시장 규모:
TCMDO,GDP,GFDEBTN - 은행 신용:
TOTBKCR
주식/ETF (50개)
- 주요 지수:
SPY,QQQ,DIA,IWM - SPDR 섹터 11개 전체:
XLK,XLF,XLV,XLE,XLY,XLP,XLI,XLB,XLU,XLRE,XLC - 팩터:
MTUM,QUAL,VLUE,USMV,SIZE - 채권 세분화:
TLT,SHY,IEF,LQD,HYG - 지역:
EEM,EFA,EWJ,FXI,EWZ,INDA,EWY - 통화/원자재:
UUP,FXY,DX-Y.NYB,GC=F,HG=F,CL=F - 테마:
SMH,ARKK,XBI,GLD,USO,IBIT - Fed Funds Futures:
ZQ=F(근월물) - 주식:
AMD,TSLA,FCX - 지수:
^VIX,^W5000
암호화폐 — BTC-USD
신규 수집 레이어 (리서치용)
insider_trades— SEC EDGAR Form 4, watchlist 종목의 내부자 매매margin_debt— FINRA 월간 마진 부채 (1997년부터 29년치)gdpnow_vintages— Atlanta Fed GDPNow 일간 나우캐스트 (#11)fed_expectations— CME FedWatch 월물 체인 기반 회의별 확률 (#8)
DB 구성 (SQLite, ~30 MB, 12개 테이블)
| 테이블 | 행 수 | 비고 |
|---|---|---|
| equity_prices | 74,415 | 50개 심볼, 6년치 |
| economic_indicators | 60,200 | 19개 FRED 시리즈, 일부 1945년부터 |
| crypto_prices | 2,191 | BTC 6년치 |
| margin_debt | 350 | FINRA 월간, 29년치 |
| insider_trades | 117 | AMD/TSLA/FCX 최근 90일 |
| gdpnow_vintages | — | Atlanta Fed GDPNow 일간 vintage (ALFRED) |
| fed_expectations | — | CME FedWatch 확률 (관측일 × 회의일) |
| collection_logs | — | 수집 이력 |
| watchlist | 3 | 분석 대상 종목 |
| api_keys | — | REST API 인증 키 (SHA256 해시) |
| reports | 0 | 스키마만 (스킬 통합 시) |
| data_gaps | 0 | 스킬이 못 찾은 데이터 누적 (#15, capabilities 짝꿍) |
구현된 수집기
| 수집기 | 소스 | 빈도 | 상태 |
|---|---|---|---|
OpenBB (openbb_collector.py) |
FRED / yfinance | 일간 | 운영 중 |
SEC EDGAR (edgar_collector.py) |
data.sec.gov | 수동/주간 | 검증 완료 |
FINRA (finra_collector.py) |
finra.org XLSX | 월간 | 검증 완료 |
Atlanta Fed (atlanta_fed_collector.py) |
FRED ALFRED | 일간 | 운영 중 (#11) |
CME FedWatch (cme_fedwatch_collector.py) |
yfinance ZQ 체인 | 수동/주간 | 운영 중 (#8) |
빠른 시작
환경 준비
# 패키지 설치
uv sync
# 환경 변수 설정
cp .env.example .env
# .env 편집: FRED_API_KEY, OBB_FRED_API_KEY 입력
# DB 초기화 (최초 1회)
uv run python scripts/init_db.py
# watchlist 시드 (최초 1회)
uv run python scripts/init_watchlist.py
FRED API 키 발급: https://fred.stlouisfed.org/docs/api/api_key.html
데이터 수집
# 전체 일간 수집 (69개 심볼)
uv run python scripts/collect_daily.py
# 단일/복수 심볼 수집
uv run python scripts/collect_single.py SPY QQQ AMD
# 히스토리컬 백필 (특정 기간만)
uv run python scripts/backfill_historical.py --category etfs \
--start-date 2020-01-01 --end-date 2024-12-31
# SEC EDGAR 내부자 매매 (watchlist 전체, 최근 90일)
uv run python scripts/collect_insider.py --days 90
# FINRA 마진 부채 (월 1회)
uv run python scripts/collect_margin_debt.py
분석 도구
# 섹터 자금 흐름 분석
uv run python scripts/analyze_sector_flows.py
# Streamlit 대시보드
uv run streamlit run frontend/streamlit/app.py
- 운영 페이지 —
app.py기동 후 사이드바에서 이동:Collection History(#22) — 수집 이력 heatmap + 최근 실패 로그Data Coverage(#22) — 테이블/심볼 커버리지 + gaps 경고Manual Trigger(#22) —/api/collect/*버튼식 수동 실행 (Tailscale 전용)API Keys(#46) — 키 발급/폐기/회전 UI (Tailscale 전용)
- API URL /
X-API-Key는 사이드바 입력 (세션 내 유지). 기본 URL 은 환경변수API_URL로 덮어쓸 수 있음. - Tailscale 게이트된 페이지는 로컬에서
ADMIN_FORCE_ON=1환경변수로 우회 가능 (예:ADMIN_FORCE_ON=1 uv run streamlit run frontend/streamlit/app.py).
테스트
# 전체 테스트 (in-memory SQLite, 외부 I/O 없음)
uv run pytest
# 특정 파일
uv run pytest tests/api/test_health.py
# 커버리지 리포트
uv run pytest --cov=src/financial_platform --cov-report=term-missing
PR 이 열리면 Forgejo Actions 가 자동으로 uv run ruff check . + uv run pytest 를 순차 실행한다 (.forgejo/workflows/test.yml). 실패 시 Actions 탭에 빨간 체크. 신규 엔드포인트/수집기는 테스트 동반 작성 을 관례로 한다 (TDD).
커밋 전 자동 린트 (pre-commit)
최초 1회만 아래 명령으로 Git 훅을 설치. 이후 git commit 할 때마다 ruff 가 자동으로 돌고 실패하면 커밋이 차단된다.
uv run pre-commit install # 1회
uv run pre-commit run --all-files # 전체 파일 수동 실행
훅 정의는 .pre-commit-config.yaml, 규칙은 pyproject.toml [tool.ruff]. ruff-format 은 전면 재포맷 범위를 피하기 위해 현재 비활성이며, 별도 PR 로 일괄 적용 후 켜질 예정.
API 서버 (로컬 개발)
# 개발 서버 실행 (reload, 기본 포트 8000)
uv run python scripts/run_api.py
# 포트/리로드 제어
uv run python scripts/run_api.py --port 9000 --no-reload
문서:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
- Scalar: http://localhost:8000/scalar
- OpenAPI JSON: http://localhost:8000/openapi.json
API 서버 (Docker Compose)
# 빌드 + 기동
docker compose up -d --build
# 최초 1회: DB 초기화 + watchlist 시드
docker compose run --rm api python scripts/init_db.py
docker compose run --rm api python scripts/init_watchlist.py
# API 키 발급 (원문은 한 번만 표시됨)
docker compose run --rm api \
python scripts/apikey.py create --name "skill-macro" --scopes "read"
# 데이터 수집 트리거
docker compose exec api python scripts/collect_daily.py
# 로그
docker compose logs -f api
# 종료
docker compose down
docker-compose.yml 에는 stock.xhhan.com 으로 라우팅하는 Traefik 라벨이 이미 활성화되어 있다. NAS 의 Traefik 이 traefik-public 네트워크에서 자동으로 이 컨테이너를 잡아 Cloudflare Tunnel 뒤에서 서빙한다. 다른 도메인을 쓰려면 Host( 규칙만 바꾸면 된다.
Streamlit 운영 대시보드 (Docker Compose, #44)
같은 docker-compose.yml 에 streamlit 서비스가 포함돼 있어 API 와 함께 기동된다. stock-admin.xhhan.com 으로 Traefik 라우팅.
# API + Streamlit 한 번에 기동
docker compose up -d --build
# Streamlit 만 재빌드
docker compose up -d --build streamlit
# 로그
docker compose logs -f streamlit
배포 준비
Cloudflare Tunnel 이 *.xhhan.com 을 Traefik 으로 와일드카드 포워딩하도록 구성되어 있어 별도 Tunnel/DNS 작업 불필요. docker compose up -d --build 한 번이면 stock-admin.xhhan.com 에 Traefik 라벨 기반으로 자동 라우팅.
접근 방식 (하이브리드)
- 외부 공개 접근 (
https://stock-admin.xhhan.com): Collection History / Data Coverage 를 키 입력 없이 조회. 조회 엔드포인트는 전부 공개라 사이드바 키 불필요. - Tailscale 접근 (NAS 호스트의 Tailscale IP
:8501직접): Manual Trigger / API Keys 페이지도 활성. 브라우저에서 JS 프로브로100.100.100.100확인해 자동 감지. write 작업에만 API 키 필요 — 사이드바에 write 스코프 키 입력. - 로컬 개발 우회:
.env에ADMIN_FORCE_ON=1→ Tailscale 없이 모든 페이지 활성.
Claude 스킬 통합 — capabilities 부터 시작 (#62)
스킬(매크로 리포트, 종목 분석 등) 이 매 실행마다 같은 웹서치를 반복하는 비용을 줄이는 것이 본 플랫폼의 핵심 목표. 스킬은 시작 시점에 다음 한 번을 호출해 "이 플랫폼이 어떤 데이터를 줄 수 있는지" 마크다운으로 흡수한 뒤 필요한 엔드포인트를 호출한다.
curl -s https://stock.xhhan.com/api/meta/capabilities
응답은 text/markdown. JSON 파싱 단계 없이 그대로 LLM 컨텍스트로 흡수된다. 본문에 포함되는 정보:
- 사용 가능한 엔드포인트 (path + 한 줄 요약, 라우터 스캔으로 자동 생성)
- 데이터 소스 (FRED / Equity / Crypto 카테고리별 심볼 수)
- 테이블 커버리지 (행수 + 최신일)
- 사용 규칙 (인증, CompactSeries 응답 포맷, data-gaps 짝꿍 안내)
응답은 동적 생성 — 새 라우트/심볼/데이터가 추가되면 capabilities 도 자동 반영되므로 스킬 프롬프트는 안 건드려도 최신 능력을 인지한다. 데이터가 비어 있거나 부정확하면 짝꿍 엔드포인트(POST /api/meta/data-gaps, #15) 로 빈틈을 기록 — 다음 수집기 우선순위 자동 도출.
API 인증
조회(GET) 엔드포인트는 공개 — 키 불필요. 쓰기(POST/PATCH/DELETE) 엔드포인트 는 X-API-Key 헤더 + write 스코프 필요. 헬스체크/문서(/api/health, /api/version, /docs, /redoc, /scalar, /openapi.json) 도 공개.
# 키 발급
uv run python scripts/apikey.py create --name "skill-macro" --scopes "read"
# 키 목록 (활성만)
uv run python scripts/apikey.py list
# 키 목록 (폐기 포함)
uv run python scripts/apikey.py list --all
# 폐기
uv run python scripts/apikey.py revoke --name "skill-macro"
# 교체 (기존 폐기 + 같은 이름 재발급)
uv run python scripts/apikey.py rotate --name "skill-macro"
# 조회 호출 (키 불요)
curl http://localhost:8000/api/prices/SPY?limit=3
# 쓰기 호출 (write 스코프 키 필요)
curl -X POST -H "X-API-Key: irp_xxxxxxxxxx..." \
"http://localhost:8000/api/collect/single?symbols=SPY,QQQ"
개발용 인증 비활성화: .env에 API_AUTH_DISABLED=1 설정 시 모든 요청이 통과. 프로덕션에서는 반드시 비워둘 것. 원문 키는 발급 시 한 번만 표시되며 DB에는 SHA256 해시만 저장된다.
배포 검증 — /api/version
CI/CD 파이프라인 또는 운영자가 "실제로 어떤 커밋이 떠 있는지" 확인하기 위한 엔드포인트. 인증 면제.
curl https://stock.xhhan.com/api/version
# {
# "version": "0.1.0",
# "commit": "37f5bd4003f7bfa9326ae6955bf4cd3cad92d2e2",
# "commit_short": "37f5bd4",
# "tag": "v0.1.0",
# "branch": "main",
# "build_time": "2026-04-21T13:16:32Z"
# }
값은 Docker 빌드 시점 ARG로 주입(GIT_COMMIT, GIT_TAG, GIT_BRANCH, BUILD_TIME). 로컬 docker compose build 시에도 환경변수로 전달 가능:
GIT_COMMIT=$(git rev-parse HEAD) \
GIT_TAG=v0.1.0-dev \
BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
docker compose up -d --build
배포 자동화 (Forgejo Actions + self-hosted Runner)
태그 v*를 push하면 NAS에서 자동으로 빌드·재기동·헬스체크·커밋 일치 검증까지 수행한다. 워크플로 정의는 .forgejo/workflows/deploy.yml.
동작 요약
flowchart LR
dev["개발자<br/>git tag v0.2.0 && git push --tags"] --> forgejo["Forgejo<br/>(git.xhhan.com)"]
forgejo -->|"push.tags == v*"| runner["Self-hosted Runner<br/>(NAS)"]
runner -->|"git checkout tag<br/>docker compose build<br/>docker compose up -d"| nas["NAS Docker"]
runner -.->|"curl /api/health<br/>curl /api/version → commit 일치 검증"| nas
runner -->|"성공/실패 상태"| forgejo
Runner 전제
이 레포는 기존에 NAS에서 운영 중인 Forgejo Runner를 재사용한다 (git-pages 등 다른 워크플로가 이 러너로 이미 돌고 있음). 따라서 새 러너를 띄우거나 systemd 서비스를 만들지 않는다.
현재 러너 구성 (홈서버 표준):
| 항목 | 값 |
|---|---|
| 방식 | Docker Compose (/home/xhh/docker/forgejo-runner) |
| 라벨 | docker, ubuntu-latest |
| 네트워크 | traefik-public |
| docker 접근 | /var/run/docker.sock 마운트로 host docker 제어 |
워크플로의 runs-on: docker가 이 라벨과 매칭된다.
Forgejo Actions Secrets 등록 (1회)
저장소 Settings → Actions → Secrets 에 다음 값들을 넣는다. 워크플로가 매 배포마다 Runner 환경변수로 주입해 .env 파일을 재생성한다. 로그에 자동 마스킹되어 안전.
| Secret 이름 | 필수 | 설명 |
|---|---|---|
FRED_API_KEY |
✅ | https://fred.stlouisfed.org/docs/api/api_key.html |
OBB_FRED_API_KEY |
⬜ | 비워두면 FRED_API_KEY와 동일 값 사용 |
SEC_CONTACT_EMAIL |
⬜ | SEC EDGAR User-Agent용 (선택) |
배포 시 .env는 이 Secrets를 소스로 매번 덮어쓰기된다. NAS에 .env를 수동 편집해도 다음 배포에서 초기화되므로, 모든 값은 Secrets를 단일 진실 공급원으로 사용할 것.
배포 디렉토리 준비 (1회)
# NAS에서 — 빈 디렉토리만 만들어 두면 된다. .env는 워크플로가 자동 생성.
mkdir -p /home/xhh/docker/financial-data-platform
cd /home/xhh/docker/financial-data-platform
git clone https://git.xhhan.com/xhh/financial-data-platform.git .
첫 배포 전 로컬에서 원하는 경우에만 수동 기동으로 파일 구조 확인 가능:
# 단 이 시점엔 .env가 없어서 docker compose가 환경변수 경고를 낸다.
# 정식 동작은 태그 push로 워크플로가 .env 생성 + 기동한 뒤부터.
docker compose config >/dev/null && echo "compose 파일 유효"
최초 초기화 (첫 태그 배포 성공 후)
# 컨테이너가 올라온 뒤 DB 테이블/시드/키 발급
docker compose exec api python scripts/init_db.py
docker compose exec api python scripts/init_watchlist.py
docker compose exec api python scripts/apikey.py create --name "initial" --scopes "read,write"
# 원문 키는 한 번만 표시되니 안전 보관
Runner가 배포 디렉토리에 접근하려면
기본적으로 Forgejo Runner 컨테이너는 격리되어 호스트 경로를 볼 수 없다. Runner 쪽 docker-compose.yml에 다음 마운트가 필요:
volumes:
- /var/run/docker.sock:/var/run/docker.sock # host docker 제어
- /home/xhh/docker:/home/xhh/docker # 배포 디렉토리 접근
두 번째 라인이 없으면 워크플로의 cd "$DEPLOY_DIR"가 실패한다. git-pages 워크플로가 동작 중이라면 이미 설정돼 있을 가능성이 높으니 먼저 확인하고, 없으면 docker-compose.yml에 추가 후 Runner 재기동.
Forgejo 저장소 변수 설정
저장소 Settings → Actions → Variables 에서 필요 시 재정의:
| 변수 | 기본값 | 설명 |
|---|---|---|
DEPLOY_DIR |
/home/xhh/docker/financial-data-platform |
Runner가 checkout할 디렉토리 |
API_URL |
http://localhost:8000 |
헬스체크/버전 확인용 기준 URL. Runner 컨테이너에서 host API에 접근해야 하므로 http://host.docker.internal:8000 또는 traefik-public 네트워크 내 컨테이너 이름(http://financial-platform-api:8000) 사용 가능 |
릴리스 플로우
# 로컬에서 태그 생성 + push
git tag v0.2.0
git push origin v0.2.0
Runner가 자동으로:
DEPLOY_DIR로 이동해 해당 태그 체크아웃GIT_COMMIT/GIT_TAG/BUILD_TIME을--build-arg로 주입해 이미지 빌드docker compose up -d --remove-orphans로 재기동/api/health성공 폴링 (최대 60초)/api/version응답의commit이 트리거한github.sha와 일치하는지 검증- 실패 시 컨테이너 로그 50줄을 워크플로 출력에 첨부
롤백
# 이전 태그로 되감기 (태그를 새 커밋으로 옮길 때는 force)
git tag -f v0.2.0 <이전 안정 커밋>
git push origin v0.2.0 --force
# 또는 NAS에서 수동으로
cd /home/xhh/docker/financial-data-platform
git checkout v0.1.9
docker compose up -d --build
배포 이력은 Forgejo 웹의 Actions 탭에서 확인.
아키텍처
전체 타깃 아키텍처를 한 장의 그림으로 보되, 완료 / 진행 / 예정 상태를 색상으로 구분한다.
flowchart LR
subgraph 수집["수집 레이어"]
openbb["OpenBB<br/>FRED · yfinance"]
edgar["SEC EDGAR<br/>Form 4"]
finra["FINRA<br/>마진 부채 XLSX"]
extra["ETF flows · Analyst<br/>CME FedWatch · TIC/QRA"]
utils["collection_utils<br/>(공통 수집 로직)"]
end
subgraph 저장["저장 레이어"]
sqlite[("SQLite<br/>data/financial_data.db")]
end
subgraph 서비스["서비스 레이어"]
api["FastAPI (Sprint 1+2)<br/>prices · indicators · insider<br/>margin-debt · analysis · system<br/>watchlist · reports · collect · meta"]
auth["X-API-Key 인증<br/>(SHA256 해시 저장)"]
scheduler["APScheduler<br/>(일간 09:00 KST + 주간/월간)"]
end
subgraph 소비자["소비자"]
skill["Claude 스킬<br/>(매크로 · 종목 분석)"]
viewer["reports.xhhan.com<br/>통합 뷰어"]
end
openbb --> utils
edgar --> utils
finra --> utils
extra -.-> utils
utils --> sqlite
sqlite --> api
auth --- api
scheduler -.-> utils
api -.-> skill
skill -.->|"리포트 저장"| api
api -.-> viewer
classDef done fill:#c8e6c9,stroke:#2e7d32,color:#1b5e20
classDef wip fill:#fff9c4,stroke:#f9a825,color:#e65100
classDef planned fill:#eeeeee,stroke:#9e9e9e,color:#424242,stroke-dasharray: 4 3
class openbb,edgar,finra,utils,sqlite,api,auth,scheduler done
class extra wip
class skill,viewer planned
- ■ 완료 — 수집(OpenBB/EDGAR/FINRA) + 저장(SQLite) + 서비스(FastAPI Sprint 1+2 + X-API-Key 인증) + APScheduler 정기 수집
- ■ 진행 중 (Phase 2) — 데이터 소스 확장 (ETF flows, 애널리스트, FedWatch 확률, TIC/QRA)
- ■ 예정 — 스킬 DB 전환(Phase 4), 통합 뷰어(Phase 3)
프로젝트 구조
financial-data-platform/
├── pyproject.toml # uv 프로젝트 설정
├── .env.example # 환경 변수 템플릿
├── CLAUDE.md # Claude 컨텍스트
├── Dockerfile # 프로덕션 이미지 (멀티스테이지)
├── docker-compose.yml # 개발/NAS 운영
├── .dockerignore
│
├── src/financial_platform/
│ ├── collectors/
│ │ ├── openbb_collector.py # OpenBB 기반 FRED/yfinance
│ │ ├── edgar_collector.py # SEC EDGAR Form 4
│ │ ├── finra_collector.py # FINRA 마진 부채
│ │ └── collection_utils.py # 공통 수집 로직
│ ├── storage/
│ │ ├── database.py # SQLAlchemy 세션/저장 메서드
│ │ └── models.py # 12개 테이블 모델 (api_keys, data_gaps 포함)
│ ├── api/ # FastAPI 백엔드 (Sprint 1)
│ │ ├── main.py # 앱, CORS, /docs, /redoc, /scalar
│ │ ├── auth.py # X-API-Key 인증 의존성
│ │ ├── deps.py # DB 세션 의존성
│ │ ├── schemas/ # Pydantic 응답 모델
│ │ └── routers/ # prices·indicators·insider·margin·analysis·system
│ ├── config/
│ │ ├── config.yaml # DB 경로, 로그 레벨
│ │ └── indicators.yaml # 수집 대상 심볼 정의
│ └── utils/
│ ├── logger.py # UTF-8 콘솔 로거
│ └── openbb_config.py # OpenBB API 키 설정
│
├── scripts/
│ ├── init_db.py # DB 테이블 생성
│ ├── init_watchlist.py # watchlist 시드
│ ├── apikey.py # API 키 CLI (create/list/revoke/rotate)
│ ├── run_api.py # API 개발 서버 실행
│ ├── collect_daily.py # 전체 일간 수집
│ ├── collect_single.py # 단일/복수 심볼
│ ├── collect_insider.py # SEC EDGAR Form 4
│ ├── collect_margin_debt.py # FINRA 마진 부채
│ ├── backfill_historical.py # 히스토리컬 백필
│ └── analyze_sector_flows.py # 섹터 자금 흐름 분석
│
├── frontend/streamlit/ # Streamlit 프로토타입
├── data/ # SQLite DB (Git 제외)
└── tests/
로드맵 요약
상세 계획은 [투자 리서치 플랫폼 통합 로드맵] 문서 참조. 이 레포 기준 체크포인트:
완료
- OpenBB 수집기 (FRED 19 + 주식/ETF 50 + BTC)
- SQLite 스토리지 + SQLAlchemy 모델 10종 (api_keys 포함)
- SEC EDGAR Form 4 수집기
- FINRA 마진 부채 수집기
- 백필 스크립트 (기간 지정 가능)
- Streamlit 대시보드 프로토타입
- FastAPI 백엔드 Sprint 1 — 10개 엔드포인트
- Market Data:
/api/prices/{symbol},/api/prices/batch/{symbols} - Indicators:
/api/indicators/{symbol},/api/indicators/latest - Insider:
/api/insider/{ticker}/summary - Margin Debt:
/api/margin-debt/recent - Analysis:
/api/analysis/liquidity-snapshot,/api/analysis/yield-curve - System:
/api/health,/api/meta/symbols,/api/meta/capabilities(#62, 스킬 디스커버리 진입점 — 마크다운 응답)
- Market Data:
- X-API-Key 인증 — SHA256 해시 저장, CLI 발급/폐기/교체
- 자동 문서화 — Swagger UI
/docs, ReDoc/redoc, Scalar/scalar - CompactSeries 응답 포맷 — 시계열 토큰 30~40% 절감
- Docker Compose 구성 — 멀티스테이지 Dockerfile + NAS 운영 템플릿
- NAS 자동 배포 (v0.1.0) — Forgejo Actions + 전용 Runner(커스텀 이미지)로 태그 push → 빌드 → compose up → 헬스체크 → 커밋 해시 검증. Secrets 기반
.env자동 생성. - Traefik + Cloudflare Tunnel 연동 —
https://stock.xhhan.com으로 외부 노출, SSL은 Cloudflare 종단 - Quality Foundation (v0.2.0) — pytest + httpx TestClient 인프라, PR CI 자동 실행 (Forgejo Actions
test.yml). v0.3.6 기준 113 테스트 운영 중.deps.get_session트랜잭션 회귀 테스트 포함. - ruff + pre-commit (#32) —
ruff check를 CI 단계와 커밋 훅 양쪽에서 강제.pyproject.toml에 rule set 정의..pre-commit-config.yaml의 훅이--fix로 자동 수정까지 수행. - Sprint 2 주요 API 완료:
/api/watchlistCRUD (#17)/api/reportsPOST/GET/PATCH + 종목별 이력 (#25) — Share Note 탈피 핵심/api/meta/coverage— 테이블/심볼별 커버리지 + gaps 분석 (#28)/api/collect/*트리거 5개 + logs/history (#29)/api/admin/keys/*CRUD +/bootstrap(#46, #50) — 내부망 전용, CLI 없이 브라우저에서 키 관리
- APScheduler 정기 수집 (#5, #31) — FastAPI lifespan 에서
BackgroundScheduler기동. KST 기준 매일 09:00collect_daily, 매주 월 09:30collect_insider, 매월 3주차 화 10:00collect_margin_debt.SCHEDULER_ENABLED=0으로 비활성화 가능 (테스트 기본값). - 공개 조회 API (#49) — 조회 엔드포인트 전부 키 없이 호출 가능. 쓰기 엔드포인트만
X-API-Key+ write 스코프 요구./api/admin/*는require_private_origin으로 공개 인터넷 원천 차단 (#50). - Phase 2 데이터 소스 2종 — Atlanta Fed GDPNow 일간 vintage (#11), CME FedWatch 월물 체인 확률 역산 (#8)
- Streamlit 운영 대시보드 (v0.3.x) — NAS 배포.
https://stock-admin.xhhan.com공개.- 공개: Collection History / Data Coverage (키 없이 조회)
- Tailscale 전용: Manual Trigger / API Keys —
ADMIN_PROBE_URL기반 자동 감지 + 수동 토글 fallback
- 스킬 디스커버리 진입점 (v0.3.6) —
GET /api/meta/capabilities가 사용 가능한 엔드포인트/심볼/테이블을 LLM 친화 마크다운으로 제공 (#62). Claude 스킬이 시작 시 한 번 fetch 해 본 API 우선 호출 — 통합 로드맵의 토큰 절감 가설 검증 진입점. - 운영 대시보드 DB 용량 표시 (v0.3.6) —
/api/meta/coverage응답에db_size_bytes(#55). Data Coverage 페이지 상단 메트릭 (KB/MB/GB 자동 단위). - Streamlit 레거시 페이지 API 마이그레이션 (v0.3.6) — Market_Coverage / Sector_Flows / Indicator_Detail 페이지가 더 이상 SQLite 파일을 직접 읽지 않음. 컨테이너에서
./data:/app/data:ro볼륨 마운트 제거 → 공격면 축소 (#54). - data_gaps 피드백 루프 (#15) — capabilities 짝꿍 엔드포인트
POST/GET/PATCH /api/meta/data-gaps+/summary. 스킬이 본 플랫폼에서 못 찾은 데이터를 append-only 로 누적, 주기적 리뷰로 다음 수집기 우선순위에 환원.
진행 중 (Phase 2 일부)
- watchlist 확장 (현재 3종목)
다음 (Phase 2 → Phase 3 게이트)
- #6 Claude 스킬 시범 전환 (유동성 분석 →
/api/analysis/liquidity-snapshot) — Phase 2 핵심 검증 - #7 토큰 절감 측정 리포트 —
docs/token-savings.md에 페어 누적 중 (1/5) - #55 운영 대시보드에 DB 용량 표시
- #13 Docker 이미지 크기 축소
보류 (조건부 재개)
- #9 ETF 자금 흐름 — 무료 소스 전멸 (etf.com Cloudflare 차단, ICI 멤버십), 유료 API 결정 필요
- #10 Treasury TIC/QRA — 스코프 과다 (TIC 다차원 + QRA 이벤트 문서), 설계 토론 선행
- #12 애널리스트 목표가 — FMP/Benzinga 유료 결정 대기
이후 단계
- Phase 3 — 리포트 뷰어 통합 (reports.xhhan.com 리팩토링)
- Phase 4 — 스킬 DB 조회 전환, 예측 정확도 추적, 토큰 비용 추적
알려진 제약
- FRED
RRPONTSYD(역레포 잔액): OpenBBfred_seriesprovider가 이 특정 시리즈에 빈 응답을 반환. FRED REST API 직접 호출하면 정상 (openbb_collector.fetch_fred_series가 자동 fallback). - Streamlit 컨테이너가
data/볼륨 read-only 마운트: 레거시 프로토타입 페이지가 SQLite 를 직접 읽기 때문. #54 완료 시 제거 예정.
기술 스택
백엔드
- 패키지 관리:
uv - Python: 3.11+
- 데이터 수집: OpenBB Platform, yfinance, requests (SEC/FINRA)
- 데이터 저장: SQLite + SQLAlchemy (MVP) → PostgreSQL (확장 시)
- API: FastAPI + Uvicorn (Sprint 1+2 완료) + Pydantic 스키마
- 문서화: Swagger UI / ReDoc / Scalar (자동 생성)
- 인증: X-API-Key 헤더 (SHA256 해시 저장, CLI 관리)
- 스케줄링: APScheduler (운영 중, KST cron — 일간/주간/월간)
- 데이터 처리: pandas, numpy, openpyxl
프론트엔드
- 현재: Streamlit (프로토타입)
- Phase 3: 기존 Flask 갤러리(reports.xhhan.com) 확장 또는 React/Next.js
인프라
- Docker Compose (멀티스테이지 Dockerfile, 비루트 실행, healthcheck)
- Traefik 라우팅 (compose 템플릿 주석으로 준비됨)
- NAS 셀프호스팅 (Forgejo + Docker)
개발 도구
- 린터: ruff (
pyproject.toml [tool.ruff]), CI + pre-commit 양쪽에서 강제 - 훅: pre-commit — 커밋 직전
ruff check --fix자동 실행 - 테스트: pytest + httpx TestClient (105 케이스, PR 에서 자동 실행)
개발 가이드라인
코딩 스타일
- 주석과 커밋 메시지: 한국어
- 변수/함수명: 영어 snake_case
- 클래스명: 영어 PascalCase
- 이모지 사용 금지
핵심 원칙
- API 키는
.env에 저장,python-dotenv로 로드 - 에러 처리: 재시도 로직, 구조적 로깅, 유니크 제약으로 중복 방지
- DRY: 공통 수집 로직을
collection_utils.py에 집중 - 단일 책임: 수집(collectors/) / 저장(storage/) / 분석(scripts/) 분리
주요 명령어
# 패키지 관리
uv add <package> # 의존성 추가
uv add --dev <package> # 개발 의존성
uv sync # 동기화
# 실행
uv run python <script> # 스크립트 실행
uv run pytest # 테스트 (105 케이스)
uv run ruff check . # 린트 (CI 와 동일)
uv run ruff check . --fix # 안전 자동 수정
uv run pre-commit install # 커밋 훅 설치 (최초 1회)
uv run pre-commit run --all-files # 전체 파일 훅 수동 실행
OpenBB 패턴
from openbb import obb
# FRED 경제 지표
data = obb.economy.fred_series("M2SL")
# 주식/ETF
spy = obb.equity.price.historical("SPY", provider="yfinance")
SEC EDGAR 수집기 사용
from financial_platform.collectors.edgar_collector import EdgarCollector
c = EdgarCollector()
cik = c.lookup_cik("AMD") # 2488
filings = c.fetch_form4_list(cik)
for f in filings[:3]:
trades = c.fetch_form4_detail(
cik, f["accession_no"], f["primary_doc"]
)
SEC 에티켓: SEC_CONTACT_EMAIL 환경변수로 User-Agent 커스터마이즈 가능. 요청 간격 0.15초, 429/403 시 지수 백오프.
데이터 소스 선정 원칙
- 공식 무료 API 우선 — SEC EDGAR, FINRA, FRED
- 장기 안정성 > 최신 정확도 — 스크래핑보다 CSV/JSON 다운로드
- 유료 API는 대체재가 없을 때만 — FMP, Benzinga는 Phase 4 이후 결정
- 원시 데이터 확보 > 파생 지표 즉시 구현 — 예: ZQ=F 가격 먼저 저장, FedWatch 확률 계산은 Phase 3
현재 활용 중인 무료 데이터 소스
| 소스 | 제공 데이터 | 제한 |
|---|---|---|
| FRED | 경제 지표 전체 | API 키 필수, rate limit 관대 |
| yfinance (OpenBB) | 주식/ETF/선물/암호화폐 가격 | 제한 없음 (비공식) |
| SEC EDGAR | Form 4 내부자 매매, 기타 filing | 10 req/sec, User-Agent 필수 |
| FINRA | 월간 마진 부채 | 공개 XLSX 다운로드 |
향후 탐색 대상
| 소스 | 제공 데이터 | 도입 예상 시점 |
|---|---|---|
| CME (내부) | FedWatch 확률 | Phase 3, 스크래핑 안정성 검토 후 |
| Atlanta Fed | Market Probability Tracker | Phase 3, CSV 다운로드 자동화 |
| Treasury.gov | TIC, QRA | Phase 2 후반 |
| ICI | ETF 자금 흐름 주간 | Phase 2 후반 |
| etf.com | Creation/Redemption 단위 | Phase 2~3, 스크래핑 법적 검토 |
업데이트 주기 (현재)
- 일별 (월~금 수집 권장) — 가격 데이터, VIX, 금리, ETF, 하이일드 스프레드, RRP
- 주간 (월요일) — M2, WALCL, 은행 신용
- 월간 (지표 발표일+1) — 실업률, CPI, PCE, FINRA 마진 부채
- 이벤트 기반 — SEC Form 4 (내부자 매매는 2영업일 내 제출)
관련 문서
- 프로젝트 컨텍스트:
CLAUDE.md - 통합 로드맵:
D:/xvault/01_Projects/사이드프로젝트/투자 리서치 플랫폼 통합 로드맵.md - 토큰 절감 측정 리포트:
docs/token-savings.md— Claude 스킬 A/B 페어 누적 (#7) - Forgejo 레포: https://git.xhhan.com/xhh/financial-data-platform
라이선스
개인 프로젝트. 외부 데이터 소스 라이선스는 각 제공자 정책 준수 (OpenBB AGPLv3, SEC/FINRA/FRED 공개).