Galaxy-PO 설계 문서
1. 개요
프로젝트명: galaxy-po
목적: 개인 투자 관리 + 퀀트 연구/백테스트 통합 웹 애플리케이션
통합 대상:
- make-quant-py (콴트 매니저): 멀티 팩터, 슈퍼 퀄리티, 슈퍼 밸류 모멘텀 전략
- 퇴직연금 관리 시스템: ETF 포트폴리오, 리밸런싱 계산, 수익률 추적
2. 기술 스택
| 영역 |
기술 |
| Frontend |
Next.js 15, React 19, TypeScript, Tailwind CSS, Node.js 24 |
| Backend |
FastAPI, SQLAlchemy, Alembic, APScheduler, Python 3.14 |
| Database |
PostgreSQL 15 |
| Infrastructure |
Docker, Docker Compose |
| Data Sources |
KRX, pykrx, DART OpenAPI, 한국투자증권 OpenAPI |
3. 프로젝트 구조
galaxy-po/
├── backend/ # FastAPI 백엔드
│ ├── app/
│ │ ├── api/ # API 라우터
│ │ │ ├── auth.py # 인증
│ │ │ ├── portfolio.py # 포트폴리오 관리
│ │ │ ├── rebalance.py # 리밸런싱 계산
│ │ │ ├── strategy.py # 퀀트 전략
│ │ │ ├── backtest.py # 백테스트
│ │ │ └── market.py # 시세 조회
│ │ ├── core/ # 핵심 설정
│ │ ├── models/ # SQLAlchemy 모델
│ │ ├── schemas/ # Pydantic 스키마
│ │ ├── services/ # 비즈니스 로직
│ │ │ ├── data_collector.py
│ │ │ ├── strategy_engine.py
│ │ │ └── backtest_engine.py
│ │ └── main.py
│ ├── jobs/ # 배치 작업
│ │ ├── scheduler.py
│ │ ├── collectors/
│ │ │ ├── base.py
│ │ │ ├── stock_collector.py
│ │ │ ├── sector_collector.py
│ │ │ ├── price_collector.py
│ │ │ ├── valuation_collector.py
│ │ │ ├── financial_collector.py
│ │ │ └── etf_collector.py
│ │ └── tasks.py
│ ├── requirements.txt
│ └── Dockerfile
├── frontend/ # Next.js 프론트엔드
│ ├── src/
│ │ ├── app/ # App Router (페이지)
│ │ ├── components/ # React 컴포넌트
│ │ └── lib/ # 유틸리티, API 클라이언트
│ ├── package.json
│ └── Dockerfile
├── docker-compose.yml
└── docs/
└── plans/
4. 데이터베이스 모델
4.1 퀀트 데이터 (배치 수집)
stocks (종목 마스터)
| 컬럼 |
타입 |
설명 |
| ticker |
VARCHAR (PK) |
종목코드 |
| name |
VARCHAR |
종목명 |
| market |
VARCHAR |
시장구분 (KOSPI/KOSDAQ) |
| close_price |
DECIMAL |
종가 |
| market_cap |
BIGINT |
시가총액 |
| eps |
DECIMAL |
EPS |
| forward_eps |
DECIMAL |
선행EPS |
| bps |
DECIMAL |
BPS |
| dividend_per_share |
DECIMAL |
주당배당금 |
| stock_type |
VARCHAR |
종목구분 (common/spac/preferred/reit) |
| base_date |
DATE |
기준일 |
sectors (섹터 분류)
| 컬럼 |
타입 |
설명 |
| ticker |
VARCHAR (PK) |
종목코드 |
| sector_code |
VARCHAR |
섹터코드 (IDX_CD) |
| company_name |
VARCHAR |
종목명 |
| sector_name |
VARCHAR |
섹터명 |
| base_date |
DATE |
기준일 |
valuations (밸류 지표)
| 컬럼 |
타입 |
설명 |
| ticker |
VARCHAR (PK) |
종목코드 |
| base_date |
DATE (PK) |
기준일 |
| per |
DECIMAL |
PER |
| pbr |
DECIMAL |
PBR |
| psr |
DECIMAL |
PSR |
| pcr |
DECIMAL |
PCR |
| dividend_yield |
DECIMAL |
배당수익률 |
prices (가격 데이터)
| 컬럼 |
타입 |
설명 |
| ticker |
VARCHAR (PK) |
종목코드 |
| date |
DATE (PK) |
날짜 |
| open |
DECIMAL |
시가 |
| high |
DECIMAL |
고가 |
| low |
DECIMAL |
저가 |
| close |
DECIMAL |
종가 |
| volume |
BIGINT |
거래량 |
financials (재무제표)
| 컬럼 |
타입 |
설명 |
| ticker |
VARCHAR (PK) |
종목코드 |
| base_date |
DATE (PK) |
기준일 |
| report_type |
VARCHAR (PK) |
공시구분 (annual/quarterly) |
| account |
VARCHAR (PK) |
계정명 |
| value |
DECIMAL |
값 |
account 값 매핑:
- revenue, gross_profit, operating_income, net_income
- total_assets, total_equity, total_liabilities
- operating_cash_flow, depreciation, interest_expense
- income_tax, cash, current_assets, current_liabilities, non_current_assets
4.2 포트폴리오 관리
users
| 컬럼 |
타입 |
설명 |
| id |
SERIAL (PK) |
ID |
| username |
VARCHAR |
사용자명 |
| email |
VARCHAR |
이메일 |
| hashed_password |
VARCHAR |
해시된 비밀번호 |
| created_at |
TIMESTAMP |
생성일 |
portfolios
| 컬럼 |
타입 |
설명 |
| id |
SERIAL (PK) |
ID |
| user_id |
INTEGER (FK) |
사용자 ID |
| name |
VARCHAR |
포트폴리오명 |
| portfolio_type |
VARCHAR |
유형 (pension/general) |
| created_at |
TIMESTAMP |
생성일 |
| updated_at |
TIMESTAMP |
수정일 |
targets (목표 비율)
| 컬럼 |
타입 |
설명 |
| portfolio_id |
INTEGER (PK, FK) |
포트폴리오 ID |
| ticker |
VARCHAR (PK) |
종목코드 |
| target_ratio |
DECIMAL |
목표 비율 (%) |
holdings (보유 자산)
| 컬럼 |
타입 |
설명 |
| portfolio_id |
INTEGER (PK, FK) |
포트폴리오 ID |
| ticker |
VARCHAR (PK) |
종목코드 |
| quantity |
INTEGER |
보유 수량 |
| avg_price |
DECIMAL |
평균 매수가 |
transactions (거래 내역)
| 컬럼 |
타입 |
설명 |
| id |
SERIAL (PK) |
ID |
| portfolio_id |
INTEGER (FK) |
포트폴리오 ID |
| ticker |
VARCHAR |
종목코드 |
| tx_type |
VARCHAR |
거래 유형 (buy/sell) |
| quantity |
INTEGER |
수량 |
| price |
DECIMAL |
가격 |
| executed_at |
TIMESTAMP |
체결일시 |
| memo |
TEXT |
메모 |
portfolio_snapshots
| 컬럼 |
타입 |
설명 |
| id |
SERIAL (PK) |
ID |
| portfolio_id |
INTEGER (FK) |
포트폴리오 ID |
| total_value |
DECIMAL |
총 평가금액 |
| snapshot_date |
DATE |
스냅샷 날짜 |
snapshot_holdings
| 컬럼 |
타입 |
설명 |
| snapshot_id |
INTEGER (PK, FK) |
스냅샷 ID |
| ticker |
VARCHAR (PK) |
종목코드 |
| quantity |
INTEGER |
보유 수량 |
| price |
DECIMAL |
당시 가격 |
| value |
DECIMAL |
평가 금액 |
| current_ratio |
DECIMAL |
당시 비율 (%) |
4.3 ETF (퇴직연금용)
etfs
| 컬럼 |
타입 |
설명 |
| ticker |
VARCHAR (PK) |
종목코드 |
| name |
VARCHAR |
ETF명 |
| asset_class |
VARCHAR |
자산군 (equity/bond/gold/mixed) |
| market |
VARCHAR |
시장 |
| expense_ratio |
DECIMAL |
보수율 |
etf_prices
| 컬럼 |
타입 |
설명 |
| ticker |
VARCHAR (PK) |
종목코드 |
| date |
DATE (PK) |
날짜 |
| close |
DECIMAL |
종가 |
| nav |
DECIMAL |
NAV |
| volume |
BIGINT |
거래량 |
4.4 배치 작업 관리
job_logs
| 컬럼 |
타입 |
설명 |
| id |
SERIAL (PK) |
ID |
| job_name |
VARCHAR |
작업명 |
| status |
VARCHAR |
상태 (running/success/failed) |
| started_at |
TIMESTAMP |
시작 시간 |
| finished_at |
TIMESTAMP |
종료 시간 |
| records_count |
INTEGER |
처리 건수 |
| error_msg |
TEXT |
에러 메시지 |
5. API 엔드포인트
5.1 인증
| Method |
Endpoint |
설명 |
| POST |
/api/auth/login |
로그인 (JWT 발급) |
| POST |
/api/auth/logout |
로그아웃 |
| GET |
/api/auth/me |
현재 사용자 정보 |
5.2 포트폴리오
| Method |
Endpoint |
설명 |
| GET |
/api/portfolios |
포트폴리오 목록 |
| POST |
/api/portfolios |
포트폴리오 생성 |
| GET |
/api/portfolios/{id} |
포트폴리오 상세 |
| PUT |
/api/portfolios/{id} |
포트폴리오 수정 |
| DELETE |
/api/portfolios/{id} |
포트폴리오 삭제 |
| GET |
/api/portfolios/{id}/targets |
목표 비율 조회 |
| PUT |
/api/portfolios/{id}/targets |
목표 비율 설정 |
| GET |
/api/portfolios/{id}/holdings |
보유 자산 조회 |
| PUT |
/api/portfolios/{id}/holdings |
보유 자산 수정 |
| GET |
/api/portfolios/{id}/transactions |
거래 내역 조회 |
| POST |
/api/portfolios/{id}/transactions |
거래 기록 추가 |
| GET |
/api/portfolios/{id}/snapshots |
스냅샷 목록 |
| POST |
/api/portfolios/{id}/snapshots |
스냅샷 생성 |
5.3 리밸런싱
| Method |
Endpoint |
설명 |
| GET |
/api/portfolios/{id}/rebalance |
리밸런싱 계산 |
| POST |
/api/portfolios/{id}/rebalance/simulate |
추가 입금 시뮬레이션 |
5.4 시세
| Method |
Endpoint |
설명 |
| GET |
/api/market/stocks/{ticker} |
종목 정보 |
| GET |
/api/market/stocks/{ticker}/price |
현재가 (OpenAPI) |
| GET |
/api/market/stocks/{ticker}/prices |
과거 시세 (DB) |
| GET |
/api/market/etfs/{ticker} |
ETF 정보 |
| GET |
/api/market/etfs/{ticker}/price |
ETF 현재가 |
| GET |
/api/market/search?q= |
종목 검색 |
5.5 퀀트 전략
| Method |
Endpoint |
설명 |
| POST |
/api/strategy/multi-factor |
멀티 팩터 전략 |
| POST |
/api/strategy/quality |
슈퍼 퀄리티 전략 |
| POST |
/api/strategy/value-momentum |
슈퍼 밸류 모멘텀 전략 |
5.6 백테스트
| Method |
Endpoint |
설명 |
| POST |
/api/backtest |
백테스트 실행 |
5.7 데이터 수집 (관리자)
| Method |
Endpoint |
설명 |
| POST |
/api/admin/collect/stocks |
종목 마스터 수집 |
| POST |
/api/admin/collect/sectors |
섹터 정보 수집 |
| POST |
/api/admin/collect/prices |
가격 데이터 수집 |
| POST |
/api/admin/collect/financials |
재무제표 수집 |
| POST |
/api/admin/collect/valuations |
밸류 지표 수집 |
| GET |
/api/admin/collect/status |
수집 작업 상태 |
6. 프론트엔드 페이지
| 경로 |
설명 |
| / |
대시보드 |
| /login |
로그인 |
| /portfolio |
포트폴리오 목록 |
| /portfolio/[id] |
포트폴리오 상세 |
| /portfolio/[id]/rebalance |
리밸런싱 계산 |
| /portfolio/[id]/history |
스냅샷/수익률 히스토리 |
| /portfolio/new |
새 포트폴리오 생성 |
| /strategy |
퀀트 전략 메인 |
| /strategy/multi-factor |
멀티 팩터 전략 |
| /strategy/quality |
슈퍼 퀄리티 전략 |
| /strategy/value-momentum |
슈퍼 밸류 모멘텀 전략 |
| /backtest |
백테스트 |
| /backtest/result/[id] |
백테스트 결과 |
| /market |
시세 조회 |
| /market/[ticker] |
종목 상세 |
| /admin/data |
데이터 수집 관리 |
7. 데이터 배치 수집
7.1 수집 대상 및 소스
| 데이터 |
소스 |
수집 주기 |
| stocks |
KRX (data.krx.co.kr) |
매일 18:00 |
| sectors |
WISEindex |
매일 18:00 |
| prices |
pykrx / KRX |
매일 18:00 |
| valuations |
KRX |
매일 18:00 |
| financials |
DART OpenAPI |
분기별 |
| etf_prices |
pykrx |
매일 18:00 |
7.2 스케줄러 설정 (APScheduler)
jobs:
- id: daily_stock_data
func: collect_stocks_and_sectors
trigger: cron, hour=18, minute=0, day_of_week=mon-fri
- id: daily_prices
func: collect_prices
trigger: cron, hour=18, minute=30, day_of_week=mon-fri
- id: daily_valuations
func: collect_valuations
trigger: cron, hour=19, minute=0, day_of_week=mon-fri
- id: quarterly_financials
func: collect_financials
trigger: cron, month=1,4,7,10, day=15
8. 퀀트 전략 엔진
8.1 팩터 계산
밸류 팩터:
- PER 역수 (1/PER)
- PBR 역수 (1/PBR)
- PSR 역수 (1/PSR)
- PCR 역수 (1/PCR)
- 배당수익률
퀄리티 팩터:
- ROE = 당기순이익 / 자본
- GP/A = 매출총이익 / 자산
- 영업현금흐름 / 자산
- 부채비율 역수
모멘텀 팩터:
- 12개월 수익률
- 6개월 수익률
- 최근 1개월 제외 11개월 수익률
F-Score (9점 만점):
- 수익성: ROA, CFO, ΔROA, Accrual (4점)
- 재무건전성: ΔLeverage, ΔLiquidity, Equity (3점)
- 운영효율성: ΔMargin, ΔTurnover (2점)
8.2 전략 실행 흐름
- 유니버스 필터 (시장, 시가총액, 종목구분)
- 팩터별 z-score 계산
- 가중치 적용하여 종합 점수 산출
- 순위 정렬 후 상위 N개 반환
8.3 백테스트 엔진
입력:
- strategy: 전략 종류 및 파라미터
- start_date, end_date: 테스트 기간
- rebalance_period: 리밸런싱 주기 (월별/분기별)
- initial_capital: 초기 자본
출력:
- total_return: 총 수익률
- cagr: 연평균 수익률
- mdd: 최대 낙폭
- sharpe_ratio: 샤프 비율
- holdings_history: 기간별 보유 종목
- equity_curve: 자산 추이
9. Docker 구성
9.1 docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_USER: galaxy
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: galaxy_po
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
backend:
build: ./backend
environment:
DATABASE_URL: postgresql://galaxy:${DB_PASSWORD}@postgres:5432/galaxy_po
KIS_APP_KEY: ${KIS_APP_KEY}
KIS_APP_SECRET: ${KIS_APP_SECRET}
JWT_SECRET: ${JWT_SECRET}
ports:
- "8000:8000"
depends_on:
- postgres
frontend:
build: ./frontend
environment:
NEXT_PUBLIC_API_URL: http://backend:8000
ports:
- "3000:3000"
depends_on:
- backend
volumes:
postgres_data:
9.2 Dockerfile (Backend)
FROM python:3.14-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
9.3 Dockerfile (Frontend)
FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD ["npm", "start"]
9.4 환경 변수 (.env)
# Database
DB_PASSWORD=your_secure_password
# JWT
JWT_SECRET=your_jwt_secret_key
# 한국투자증권 OpenAPI
KIS_APP_KEY=your_kis_app_key
KIS_APP_SECRET=your_kis_app_secret
KIS_ACCOUNT_NO=your_account_number
# DART OpenAPI
DART_API_KEY=your_dart_api_key
10. 구현 순서
Phase 1: 기반 구축
- 프로젝트 초기화 (backend/frontend 구조)
- Docker Compose 설정
- PostgreSQL + DB 모델 정의
- FastAPI 기본 구조 + 인증 (JWT)
- Next.js 기본 구조 + 레이아웃
Phase 2: 데이터 수집
- 데이터 수집기 구현 (stocks, sectors, prices)
- 배치 스케줄러 설정
- 관리자 데이터 수집 UI
Phase 3: 포트폴리오 관리
- 포트폴리오 CRUD API
- 목표 비율 / 보유 자산 관리
- 거래 내역 기록
- 리밸런싱 계산 로직
- 포트폴리오 UI (대시보드, 상세, 리밸런싱)
Phase 4: 퀀트 전략
- 팩터 계산 로직 (value, quality, momentum)
- 전략 엔진 (multi-factor, super-quality, value-momentum)
- 전략 UI
Phase 5: 백테스트
- 백테스트 엔진
- 백테스트 UI + 결과 시각화
Phase 6: 마무리
- 스냅샷 / 수익률 추적
- ETF 시세 연동 (OpenAPI)
- 테스트 / 버그 수정
- 배포
11. 핵심 의존성
backend/requirements.txt
fastapi
uvicorn
sqlalchemy
alembic
psycopg2-binary
pydantic
python-jose[cryptography]
passlib[bcrypt]
apscheduler
pykrx
requests
beautifulsoup4
pandas
numpy
frontend/package.json (dependencies)
{
"next": "^15",
"react": "^19",
"typescript": "^5",
"tailwindcss": "^4",
"recharts": "^2",
"axios": "^1",
"zustand": "^5"
}
문서 버전: 1.0
작성일: 2026-02-02