From b4c775563c4b88fd89b3b36637e9d4803f2b869e Mon Sep 17 00:00:00 2001 From: sinmb79 Date: Mon, 30 Mar 2026 16:02:04 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=9D=B8=EC=A6=9D=20=EB=AF=B8=EB=93=A4?= =?UTF-8?q?=EC=9B=A8=EC=96=B4=20=ED=99=9C=EC=84=B1=ED=99=94,=20lifespan=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC,=20Docker=20=EB=84=A4?= =?UTF-8?q?=ED=8A=B8=EC=9B=8C=ED=81=AC=20=EB=B0=94=EC=9D=B8=EB=94=A9=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=AC=B8=EC=84=9C=20=EC=A0=84?= =?UTF-8?q?=EB=A9=B4=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - hydra/main.py: auth_guard 미들웨어에 실제 API 키 검증 로직 추가 - hydra/main.py: lifespan 초기화 블록 try-except 감싸기, finally에서 ohlcv_store None 체크 추가 - Dockerfile: --host 127.0.0.1 → 0.0.0.0 (컨테이너 간 통신 가능하도록) - hydra/config/settings.py: 기본 API 키 사용 시 경고 validator 추가 - README.md: 첫 사용자를 위한 상세 가이드로 전면 재작성 - docs/QUICKSTART_KO.md: 단계별 시작 가이드 개선 - docs/API_REFERENCE_KO.md: 전체 엔드포인트 응답 예시 및 파라미터 설명 추가 Co-Authored-By: Claude Sonnet 4.6 --- Dockerfile | 2 +- README.md | 382 +++++++++++++++++++++++++++++--------- docs/API_REFERENCE_KO.md | 386 +++++++++++++++++++++++++++++++-------- docs/QUICKSTART_KO.md | 164 ++++++++++++----- hydra/config/settings.py | 13 ++ hydra/main.py | 92 ++++++---- 6 files changed, 785 insertions(+), 254 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8732aa1..c9b4040 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,4 +18,4 @@ RUN useradd -m hydra && chown -R hydra:hydra /app USER hydra EXPOSE 8000 -CMD ["uvicorn", "hydra.main:app", "--host", "127.0.0.1", "--port", "8000"] +CMD ["uvicorn", "hydra.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/README.md b/README.md index 645ce30..8754413 100644 --- a/README.md +++ b/README.md @@ -1,154 +1,267 @@ # HYDRA Engine -HYDRA Engine은 로컬 우선(Local-first) 철학으로 설계된 자동매매 엔진 프로젝트입니다. -데이터 수집, 지표 계산, 레짐 분류, 시그널 생성, 보조 데이터 수집, 백테스트, FastAPI API, Typer CLI를 하나의 저장소에서 관리합니다. +HYDRA Engine은 **로컬 우선(Local-first)** 철학으로 설계된 자동매매 엔진입니다. +데이터 수집 → 지표 계산 → 레짐 분류 → 시그널 생성 → 백테스트 → 실거래까지 하나의 저장소에서 관리합니다. -이 저장소는 "실거래 수익 보장"을 목표로 하지 않습니다. 먼저 안전하게 실행하고, 충분히 검증하고, 필요할 때만 확장하는 것을 목표로 합니다. +> **이 프로젝트는 교육·연구·실험용입니다.** +> 실거래 수익을 보장하지 않으며, 사용에 따른 모든 책임은 사용자 본인에게 있습니다. +> 반드시 [DISCLAIMER.md](DISCLAIMER.md)를 먼저 읽으세요. -## 1. 현재 포함된 기능 +--- -- FastAPI 기반 제어/API 서버 -- Redis 기반 상태 공유 -- OHLCV 수집기와 SQLite/TimescaleDB 저장소 -- 지표 계산 엔진 -- 레짐(Regime) 분류 엔진 -- 전략 시그널 엔진 -- 오더북 / 이벤트 / 감성 보조 데이터 수집 -- 인메모리 백테스트 엔진 -- Kill Switch, 주문 큐, 리스크 엔진, 설정 검증 -- CLI 도구와 Docker Compose 프로필(lite / pro / expert) +## 목차 -## 2. 이 프로젝트를 어떻게 이해하면 좋은가 +1. [포함된 기능](#1-포함된-기능) +2. [사용 철학 — 어떻게 접근할 것인가](#2-사용-철학--어떻게-접근할-것인가) +3. [준비물 설치](#3-준비물-설치) +4. [처음 시작하기 (5단계)](#4-처음-시작하기-5단계) +5. [테스트 실행](#5-테스트-실행) +6. [Docker로 전체 파이프라인 실행](#6-docker로-전체-파이프라인-실행) +7. [API 사용법](#7-api-사용법) +8. [CLI 사용법](#8-cli-사용법) +9. [Docker 프로필 선택](#9-docker-프로필-선택) +10. [자주 발생하는 문제 (FAQ)](#10-자주-발생하는-문제-faq) +11. [문서](#11-문서) +12. [라이선스](#12-라이선스) -HYDRA는 한 번에 모든 기능을 다 켜는 프로젝트가 아닙니다. +--- -1. 먼저 데이터를 수집합니다. -2. 지표와 레짐, 시그널을 계산합니다. -3. API나 CLI로 상태를 확인합니다. -4. 백테스트로 전략을 검증합니다. -5. 실거래는 마지막 단계에서 매우 조심스럽게 붙입니다. +## 1. 포함된 기능 -현재 저장소에는 실거래로 연결되는 기반 코드가 일부 포함되어 있지만, 여러 CLI 명령은 아직 "예정" 상태의 placeholder를 포함합니다. 공개 배포용으로는 안전하게 시험, 학습, 백테스트, 데이터 파이프라인 검증부터 시작하는 것을 권장합니다. +| 모듈 | 설명 | +|------|------| +| FastAPI 서버 | REST API로 모든 기능 제어 | +| OHLCV 수집기 | 거래소에서 캔들 데이터 수집, SQLite/TimescaleDB 저장 | +| 지표 계산 엔진 | RSI, MACD, Bollinger Band 등 자동 계산 | +| 레짐 분류 엔진 | 시장 상태(추세/횡보/변동성) 분류 | +| 전략 시그널 엔진 | 매수/매도 시그널 생성 | +| 보조 데이터 수집 | 오더북, 이벤트 일정, 감성 점수 | +| 인메모리 백테스트 | 수집된 데이터로 전략 성과 검증 | +| Kill Switch | 긴급 전 포지션 청산 | +| 주문 큐 | 안전한 주문 처리 파이프라인 | +| 리스크 엔진 | 포지션 및 리스크 관리 | +| CLI 도구 | 터미널에서 모든 기능 제어 | +| Telegram 알림 | 주요 이벤트 실시간 알림 | -## 3. 빠른 시작 +--- -가장 쉬운 시작 방법은 아래 두 가지입니다. +## 2. 사용 철학 — 어떻게 접근할 것인가 -- 로컬 Python 환경에서 테스트부터 실행 -- Docker Compose Lite 프로필로 전체 파이프라인 기동 +HYDRA는 **한 번에 모든 기능을 켜는 프로젝트가 아닙니다.** -### 3.1 요구 사항 +``` +1단계: 테스트 실행으로 코드 정상 확인 +2단계: 데이터 수집 (거래소 API 키 없어도 공개 데이터 가능) +3단계: 지표·레짐·시그널 계산 확인 +4단계: API/CLI로 상태 관찰 +5단계: 백테스트로 전략 검증 +6단계: (충분한 검증 후) 실거래 연결 +``` -- Python 3.11 이상 -- Docker / Docker Compose -- Redis -- Git +처음 사용하는 분은 **1~4단계**부터 시작하는 것을 강력히 권장합니다. -### 3.2 저장소 준비 +--- + +## 3. 준비물 설치 + +### 필수 소프트웨어 + +| 소프트웨어 | 버전 | 설치 링크 | +|-----------|------|----------| +| Python | 3.11 이상 | https://www.python.org/downloads/ | +| Git | 최신 | https://git-scm.com/ | +| Docker Desktop | 최신 | https://www.docker.com/products/docker-desktop | + +> Docker Desktop을 설치하면 Docker와 Docker Compose가 함께 설치됩니다. + +### 설치 확인 + +터미널(명령 프롬프트 / PowerShell / Terminal)에서 아래 명령을 실행해 버전을 확인합니다. + +```bash +python --version # Python 3.11.x 이상이어야 함 +git --version +docker --version +docker compose version +``` + +--- + +## 4. 처음 시작하기 (5단계) + +### 4.1 저장소 다운로드 ```bash git clone https://github.com/sinmb79/Hydra-Engine.git cd Hydra-Engine +``` + +### 4.2 Python 가상환경 생성 및 활성화 + +가상환경은 이 프로젝트 전용 Python 환경을 만들어 다른 프로젝트와 충돌하지 않게 합니다. + +```bash python -m venv .venv ``` -Windows PowerShell: - +**Windows (PowerShell):** ```powershell .venv\Scripts\Activate.ps1 ``` -macOS / Linux: +> PowerShell에서 실행 오류가 발생하면 먼저 아래 명령을 실행하세요: +> ```powershell +> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +> ``` +**macOS / Linux:** ```bash source .venv/bin/activate ``` -패키지 설치: +활성화되면 터미널 앞에 `(.venv)`가 표시됩니다. + +### 4.3 패키지 설치 ```bash pip install -e .[dev] ``` -### 3.3 환경 변수 설정 +> 처음 설치 시 수분이 걸릴 수 있습니다. -`.env.example`를 복사해서 `.env`를 만드세요. +### 4.4 환경 변수 설정 +`.env.example` 파일을 복사해 `.env`를 만듭니다. + +**macOS / Linux:** ```bash cp .env.example .env ``` -Windows PowerShell: - +**Windows (PowerShell):** ```powershell Copy-Item .env.example .env ``` -최소 필수 항목: +생성된 `.env` 파일을 텍스트 에디터로 열어 아래 항목을 수정합니다. ```env -HYDRA_API_KEY=change-me-to-a-random-secret +# 반드시 변경하세요 — 이 값이 API 접근 비밀번호입니다 +HYDRA_API_KEY=여기에-랜덤-문자열-입력 + +# 프로필: lite(입문) / pro(중급) / expert(고급) HYDRA_PROFILE=lite + +# Redis 주소 (Docker 사용 시 기본값 유지) REDIS_URL=redis://localhost:6379 ``` -`pro` 또는 `expert` 프로필에서는 `DB_PASSWORD`가 필요합니다. +> **HYDRA_API_KEY**는 API 호출 시 인증에 사용됩니다. +> 아무 문자열이나 사용할 수 있습니다. 예: `my-hydra-secret-2024` -## 4. 가장 먼저 해볼 것 - -### 4.1 테스트 실행 +### 4.5 테스트 실행으로 정상 확인 ```bash pytest -q ``` -정상이라면 전체 테스트가 통과해야 합니다. +모든 테스트가 통과하면 준비 완료입니다. -### 4.2 Lite 프로필로 실행 +--- + +## 5. 테스트 실행 + +```bash +# 전체 테스트 +pytest -q + +# 특정 파일만 +pytest tests/test_backtest_runner.py -v + +# 상세 출력 +pytest -v +``` + +--- + +## 6. Docker로 전체 파이프라인 실행 + +Docker Desktop이 실행 중인지 확인한 후 아래 명령을 실행합니다. ```bash docker compose -f docker-compose.lite.yml up --build ``` -서버 헬스체크: +> 첫 실행 시 이미지 빌드로 수분이 걸립니다. + +### 실행 확인 + +새 터미널을 열고 헬스체크를 합니다. ```bash curl http://127.0.0.1:8000/health ``` -## 5. 주요 사용 흐름 +아래와 같은 응답이 오면 정상입니다. -### 5.1 활성 시장 확인 +```json +{"status": "ok"} +``` + +### 종료 ```bash -curl -H "X-HYDRA-KEY: change-me-to-a-random-secret" \ +# Ctrl+C 로 중지 후 +docker compose -f docker-compose.lite.yml down +``` + +--- + +## 7. API 사용법 + +모든 API 호출은 `/health`를 제외하고 `X-HYDRA-KEY` 헤더를 포함해야 합니다. + +```bash +curl -H "X-HYDRA-KEY: 여기에-API-키" http://127.0.0.1:8000/엔드포인트 +``` + +### 7.1 헬스체크 (인증 불필요) + +```bash +curl http://127.0.0.1:8000/health +``` + +### 7.2 활성 시장 확인 + +```bash +curl -H "X-HYDRA-KEY: my-hydra-secret-2024" \ http://127.0.0.1:8000/markets ``` -### 5.2 수집 중인 심볼 확인 +### 7.3 수집 중인 심볼 확인 ```bash -curl -H "X-HYDRA-KEY: change-me-to-a-random-secret" \ +curl -H "X-HYDRA-KEY: my-hydra-secret-2024" \ http://127.0.0.1:8000/data/symbols ``` -### 5.3 캔들 조회 +### 7.4 캔들(OHLCV) 데이터 조회 ```bash curl -G http://127.0.0.1:8000/data/candles \ - -H "X-HYDRA-KEY: change-me-to-a-random-secret" \ + -H "X-HYDRA-KEY: my-hydra-secret-2024" \ --data-urlencode "market=binance" \ --data-urlencode "symbol=BTC/USDT" \ --data-urlencode "timeframe=1h" \ - --data-urlencode "limit=200" + --data-urlencode "limit=100" ``` -### 5.4 백테스트 실행 +### 7.5 백테스트 실행 ```bash curl -X POST http://127.0.0.1:8000/backtest/run \ -H "Content-Type: application/json" \ - -H "X-HYDRA-KEY: change-me-to-a-random-secret" \ + -H "X-HYDRA-KEY: my-hydra-secret-2024" \ -d '{ "market": "binance", "symbol": "BTC/USDT", @@ -161,63 +274,152 @@ curl -X POST http://127.0.0.1:8000/backtest/run \ }' ``` -### 5.5 Kill Switch +> `since`와 `until`은 Unix timestamp (밀리초) 입니다. +> 위 예시는 2024년 1월 1일 ~ 2024년 2월 1일 구간입니다. -Kill Switch는 전 포지션 청산을 시도하는 고위험 명령입니다. 테스트 목적이 아니라면 함부로 사용하지 마세요. - -CLI: +### 7.6 포지션 / 손익 확인 ```bash -python -m hydra.cli.app kill +curl -H "X-HYDRA-KEY: my-hydra-secret-2024" http://127.0.0.1:8000/positions +curl -H "X-HYDRA-KEY: my-hydra-secret-2024" http://127.0.0.1:8000/pnl ``` -API: +### 7.7 Kill Switch (주의: 전 포지션 청산) ```bash curl -X POST "http://127.0.0.1:8000/killswitch?reason=manual_test" \ - -H "X-HYDRA-KEY: change-me-to-a-random-secret" + -H "X-HYDRA-KEY: my-hydra-secret-2024" ``` -## 6. CLI 예시 +> Kill Switch는 실거래 중 긴급 상황에서만 사용하세요. + +전체 API 목록은 [docs/API_REFERENCE_KO.md](docs/API_REFERENCE_KO.md)를 참고하세요. + +--- + +## 8. CLI 사용법 ```bash +# 도움말 python -m hydra.cli.app --help + +# 초기 설정 마법사 python -m hydra.cli.app setup + +# 현재 상태 확인 python -m hydra.cli.app status + +# 시장 목록 확인 python -m hydra.cli.app market list-markets + +# 시장 활성화 (paper = 모의거래) python -m hydra.cli.app market enable binance --mode paper -python -m hydra.cli.app trade crypto binance BTC/USDT buy 0.01 + +# Kill Switch (긴급 청산) +python -m hydra.cli.app kill ``` -주의: +> `trade`, `strategy`, `module` 명령 일부는 현재 개발 예정 상태입니다. -- `trade`, `strategy`, `module` 일부 명령은 아직 placeholder 메시지를 출력합니다. -- 공개 버전 기준으로는 데이터 수집, 관찰, 백테스트 중심으로 사용하는 것이 안전합니다. +--- -## 7. Docker 프로필 +## 9. Docker 프로필 선택 -- `docker-compose.lite.yml` - - SQLite 사용 - - 개인 PC / 테스트 / 입문용 -- `docker-compose.pro.yml` - - TimescaleDB + Redis - - 중간 규모 수집/분석용 -- `docker-compose.expert.yml` - - 고사양 장비 / 확장 시나리오용 +| 프로필 | 파일 | 데이터베이스 | 권장 대상 | +|--------|------|------------|----------| +| **lite** | `docker-compose.lite.yml` | SQLite | 처음 시작하는 분, 개인 PC | +| **pro** | `docker-compose.pro.yml` | TimescaleDB + Redis | 중간 규모 수집·분석 | +| **expert** | `docker-compose.expert.yml` | 고사양 확장 구성 | 대용량 데이터, 고성능 서버 | -## 8. 문서 +처음 사용자는 **lite**부터 시작하세요. -- 자세한 시작 가이드: [docs/QUICKSTART_KO.md](docs/QUICKSTART_KO.md) -- API 레퍼런스: [docs/API_REFERENCE_KO.md](docs/API_REFERENCE_KO.md) -- 법적 고지: [DISCLAIMER.md](DISCLAIMER.md) +```bash +# lite +docker compose -f docker-compose.lite.yml up --build -## 9. 안전 안내 +# pro (DB_PASSWORD 설정 필요) +docker compose -f docker-compose.pro.yml up --build -- 이 저장소는 교육, 연구, 실험용입니다. -- 실거래 전에는 반드시 paper 모드와 백테스트로 먼저 검증하세요. -- `.env`, API 키, 계정 정보는 절대 Git에 올리지 마세요. +# expert +docker compose -f docker-compose.expert.yml up --build +``` + +--- + +## 10. 자주 발생하는 문제 (FAQ) + +### Q: `pytest` 실행 시 ModuleNotFoundError가 발생해요 + +가상환경이 활성화되어 있는지 확인하세요. + +```bash +# 가상환경 활성화 확인 +# 터미널 앞에 (.venv)가 보여야 함 + +# 다시 설치 +pip install -e .[dev] +``` + +### Q: Docker 실행 시 Redis 연결 오류가 발생해요 + +Docker Desktop이 실행 중인지 확인하세요. 그 다음 `.env` 파일의 `REDIS_URL`을 확인합니다. + +Docker Compose 환경에서는 Redis가 컨테이너로 자동 실행되므로 기본값을 유지하세요. + +```env +REDIS_URL=redis://redis:6379 # Docker Compose 내부 +REDIS_URL=redis://localhost:6379 # 로컬 직접 실행 +``` + +### Q: API 호출 시 403 오류가 발생해요 + +`X-HYDRA-KEY` 헤더가 `.env`의 `HYDRA_API_KEY`와 일치하는지 확인하세요. + +```bash +curl -H "X-HYDRA-KEY: 설정한-키-값" http://127.0.0.1:8000/markets +``` + +### Q: `HYDRA_API_KEY가 기본값` 경고가 뜨는데 괜찮나요? + +로컬 테스트 목적이면 무시할 수 있지만, 외부에 서버를 노출할 경우 반드시 변경하세요. +`.env` 파일에서 `HYDRA_API_KEY=change-me`를 다른 값으로 바꾸면 경고가 사라집니다. + +### Q: Windows에서 PowerShell 실행 정책 오류가 발생해요 + +```powershell +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +``` + +### Q: Docker 빌드가 너무 느려요 + +처음 빌드는 수분이 걸립니다. 두 번째 실행부터는 캐시를 사용해 빠릅니다. +빌드 없이 실행하려면 `--build` 옵션을 제거하세요. + +```bash +docker compose -f docker-compose.lite.yml up +``` + +--- + +## 11. 문서 + +| 문서 | 설명 | +|------|------| +| [docs/QUICKSTART_KO.md](docs/QUICKSTART_KO.md) | 10분 빠른 시작 가이드 | +| [docs/API_REFERENCE_KO.md](docs/API_REFERENCE_KO.md) | 전체 API 엔드포인트 레퍼런스 | +| [DISCLAIMER.md](DISCLAIMER.md) | 법적 고지 및 책임 한계 | + +--- + +## 12. 안전 안내 + +- `.env` 파일과 API 키는 절대 Git에 올리지 마세요. (`.gitignore`에 이미 포함되어 있습니다) +- 실거래 전에는 반드시 paper 모드와 백테스트로 전략을 충분히 검증하세요. - 기본적으로 로컬/사설 네트워크에서만 운용하는 것을 권장합니다. +- 거래소 API 키는 필요한 최소 권한만 부여하세요. -## 10. 라이선스 +--- -이 저장소는 [MIT License](LICENSE)를 따릅니다. +## 13. 라이선스 + +[MIT License](LICENSE) diff --git a/docs/API_REFERENCE_KO.md b/docs/API_REFERENCE_KO.md index f332b31..200fe21 100644 --- a/docs/API_REFERENCE_KO.md +++ b/docs/API_REFERENCE_KO.md @@ -1,113 +1,271 @@ # HYDRA Engine API 레퍼런스 -모든 보호된 엔드포인트는 아래 헤더를 요구합니다. +## 인증 + +`/health`를 제외한 모든 엔드포인트는 아래 헤더를 요구합니다. ```http X-HYDRA-KEY: ``` -## 1. 헬스체크 +`.env`에 설정한 `HYDRA_API_KEY` 값을 사용합니다. -### `GET /health` +**인증 실패 시 응답:** +```json +HTTP 403 +{"detail": "Invalid or missing API key. Set X-HYDRA-KEY header."} +``` -인증 없이 호출할 수 있습니다. +--- + +## 엔드포인트 목록 + +### 1. 헬스체크 + +#### `GET /health` + +서버 상태를 확인합니다. **인증 불필요.** ```bash curl http://127.0.0.1:8000/health ``` -## 2. 시스템 +**응답:** +```json +{"status": "ok"} +``` -### `GET /status` +--- -서버 프로필과 상태를 조회합니다. +### 2. 시스템 -### `GET /modules` +#### `GET /status` -활성 모듈 상태를 조회합니다. +서버 프로필, 가동 시간 등 시스템 상태를 조회합니다. -## 3. 시장 관리 +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/status +``` -### `GET /markets` +#### `GET /modules` -현재 활성 시장 목록을 반환합니다. +각 모듈(수집기, 지표 엔진 등)의 활성 상태를 조회합니다. -### `POST /markets/{market_id}/enable` +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/modules +``` -시장 활성화 +--- -예시: +### 3. 시장 관리 + +#### `GET /markets` + +현재 설정된 시장 목록과 활성 상태를 반환합니다. + +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/markets +``` + +**응답 예시:** +```json +[ + {"market_id": "binance", "active": true, "mode": "paper"}, + {"market_id": "upbit", "active": false, "mode": "paper"} +] +``` + +#### `POST /markets/{market_id}/enable` + +시장을 활성화합니다. ```bash curl -X POST \ - -H "X-HYDRA-KEY: my-local-demo-key" \ + -H "X-HYDRA-KEY: my-key" \ http://127.0.0.1:8000/markets/binance/enable ``` -### `POST /markets/{market_id}/disable` +#### `POST /markets/{market_id}/disable` -시장 비활성화 +시장을 비활성화합니다. -## 4. 데이터 +```bash +curl -X POST \ + -H "X-HYDRA-KEY: my-key" \ + http://127.0.0.1:8000/markets/binance/disable +``` -### `GET /data/symbols` +--- + +### 4. 데이터 + +#### `GET /data/symbols` 수집 중이거나 저장된 시장/심볼/타임프레임 목록을 반환합니다. -### `GET /data/candles` +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/data/symbols +``` -쿼리 파라미터: +**응답 예시:** +```json +[ + {"market": "binance", "symbol": "BTC/USDT", "timeframe": "1h"}, + {"market": "binance", "symbol": "ETH/USDT", "timeframe": "1h"} +] +``` -- `market` -- `symbol` -- `timeframe` -- `limit` (기본 200, 최대 1000) -- `since` (선택) +#### `GET /data/candles` -예시: +OHLCV 캔들 데이터를 조회합니다. + +**쿼리 파라미터:** + +| 파라미터 | 필수 | 설명 | 예시 | +|---------|------|------|------| +| `market` | 필수 | 거래소 ID | `binance` | +| `symbol` | 필수 | 심볼 | `BTC/USDT` | +| `timeframe` | 필수 | 타임프레임 | `1h`, `4h`, `1d` | +| `limit` | 선택 | 캔들 수 (기본 200, 최대 1000) | `100` | +| `since` | 선택 | 시작 시간 (Unix ms) | `1704067200000` | ```bash curl -G http://127.0.0.1:8000/data/candles \ - -H "X-HYDRA-KEY: my-local-demo-key" \ + -H "X-HYDRA-KEY: my-key" \ --data-urlencode "market=binance" \ --data-urlencode "symbol=BTC/USDT" \ --data-urlencode "timeframe=1h" \ --data-urlencode "limit=100" ``` -## 5. 지표 / 레짐 / 시그널 - -### `GET /indicators` -### `GET /indicators/list` -### `GET /regime` -### `GET /regime/list` -### `GET /signal` -### `GET /signal/list` - -이 엔드포인트들은 최신 계산 결과를 확인할 때 사용합니다. - -## 6. 포지션 / 손익 / 리스크 - -### `GET /positions` -### `GET /pnl` -### `POST /pnl/reset-daily` -### `GET /risk` -### `POST /killswitch` - -`POST /killswitch`는 매우 위험한 명령이므로 테스트 목적이 아니라면 호출하지 마세요. - -예시: - -```bash -curl -X POST "http://127.0.0.1:8000/killswitch?reason=manual_test" \ - -H "X-HYDRA-KEY: my-local-demo-key" +**응답 예시:** +```json +[ + { + "timestamp": 1704067200000, + "open": 42000.0, + "high": 42500.0, + "low": 41800.0, + "close": 42300.0, + "volume": 1234.56 + } +] ``` -## 7. 백테스트 +--- -### `POST /backtest/run` +### 5. 지표 / 레짐 / 시그널 -요청 본문: +#### `GET /indicators` + +가장 최근 계산된 지표 값을 반환합니다. + +#### `GET /indicators/list` + +계산 가능한 지표 목록을 반환합니다. + +#### `GET /regime` + +현재 시장 레짐(상태) 분류 결과를 반환합니다. + +> 레짐 예시: `trending_up`, `trending_down`, `sideways`, `high_volatility` + +#### `GET /regime/list` + +레짐 히스토리 목록을 반환합니다. + +#### `GET /signal` + +가장 최근 전략 시그널을 반환합니다. + +> 시그널 예시: `{"signal": "buy", "confidence": 0.72}` + +#### `GET /signal/list` + +시그널 히스토리 목록을 반환합니다. + +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/indicators +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/regime +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/signal +``` + +--- + +### 6. 포지션 / 손익 + +#### `GET /positions` + +현재 보유 포지션 목록을 반환합니다. + +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/positions +``` + +**응답 예시:** +```json +[ + { + "symbol": "BTC/USDT", + "side": "long", + "size": 0.01, + "entry_price": 42000.0, + "unrealized_pnl": 30.0 + } +] +``` + +#### `GET /pnl` + +누적 손익 정보를 반환합니다. + +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/pnl +``` + +#### `POST /pnl/reset-daily` + +일일 손익을 초기화합니다. + +```bash +curl -X POST -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/pnl/reset-daily +``` + +--- + +### 7. 리스크 엔진 + +#### `GET /risk` + +현재 리스크 상태(포지션 한도, 사용률 등)를 반환합니다. + +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/risk +``` + +#### `POST /killswitch` + +> **경고: 이 엔드포인트는 모든 포지션을 즉시 청산을 시도합니다. 신중하게 사용하세요.** + +긴급 상황에서 전 포지션 청산을 트리거합니다. + +```bash +curl -X POST "http://127.0.0.1:8000/killswitch?reason=emergency" \ + -H "X-HYDRA-KEY: my-key" +``` + +**파라미터:** +- `reason` (선택): 청산 사유 메모 (로그에 기록됨) + +--- + +### 8. 백테스트 + +#### `POST /backtest/run` + +수집된 캔들 데이터를 기반으로 전략을 백테스트합니다. + +**요청 본문:** ```json { @@ -122,33 +280,103 @@ curl -X POST "http://127.0.0.1:8000/killswitch?reason=manual_test" \ } ``` -응답에는 아래 항목이 포함됩니다. +| 필드 | 필수 | 설명 | +|------|------|------| +| `market` | 필수 | 거래소 ID | +| `symbol` | 필수 | 심볼 | +| `timeframe` | 필수 | 타임프레임 | +| `since` | 필수 | 시작 시간 (Unix ms) | +| `until` | 필수 | 종료 시간 (Unix ms) | +| `initial_capital` | 선택 | 초기 자본 (기본 10000 USD) | +| `trade_amount_usd` | 선택 | 1회 거래 금액 (기본 100 USD) | +| `commission_pct` | 선택 | 수수료율 (기본 0.001 = 0.1%) | -- 시장 / 심볼 / 타임프레임 -- 초기 자본 / 최종 자본 -- 체결 트레이드 목록 -- equity curve -- 성과 지표(`total_return_pct`, `total_trades`, `win_rate`, `max_drawdown_pct`, `sharpe_ratio`, `avg_pnl_usd`) +```bash +curl -X POST http://127.0.0.1:8000/backtest/run \ + -H "Content-Type: application/json" \ + -H "X-HYDRA-KEY: my-key" \ + -d '{ + "market": "binance", + "symbol": "BTC/USDT", + "timeframe": "1h", + "since": 1704067200000, + "until": 1706745600000, + "initial_capital": 10000, + "trade_amount_usd": 100, + "commission_pct": 0.001 + }' +``` -## 8. 보조 데이터 +**응답 예시:** +```json +{ + "market": "binance", + "symbol": "BTC/USDT", + "timeframe": "1h", + "initial_capital": 10000, + "final_capital": 10850.0, + "total_return_pct": 8.5, + "total_trades": 24, + "win_rate": 0.583, + "max_drawdown_pct": -4.2, + "sharpe_ratio": 1.35, + "avg_pnl_usd": 35.4, + "trades": [...], + "equity_curve": [...] +} +``` -### `GET /orderbook` -### `GET /events` -### `GET /sentiment` +> **Unix timestamp 변환 팁:** +> - 2024-01-01 00:00:00 UTC → `1704067200000` +> - 2024-02-01 00:00:00 UTC → `1706745600000` -각 엔드포인트는 최근 오더북, 이벤트 일정, 감성 점수를 조회하는 데 사용합니다. +--- -## 9. 인증 실패 시 +### 9. 보조 데이터 -- 잘못된 API 키: `403 Invalid API key` -- 내부 초기화 전 호출: `503 Store not initialized` 등 +#### `GET /orderbook` -## 10. 권장 호출 순서 +최근 수집된 오더북 스냅샷을 반환합니다. -1. `/health` -2. `/markets` -3. `/data/symbols` -4. `/data/candles` -5. `/backtest/run` +#### `GET /events` -실거래 관련 동작은 충분한 검증 이후에만 진행하세요. +수집된 크립토 이벤트 일정(상장, 하드포크 등)을 반환합니다. + +#### `GET /sentiment` + +감성 분석 점수를 반환합니다. (-1.0 = 매우 부정, +1.0 = 매우 긍정) + +```bash +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/orderbook +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/events +curl -H "X-HYDRA-KEY: my-key" http://127.0.0.1:8000/sentiment +``` + +--- + +## 주요 HTTP 오류 코드 + +| 코드 | 의미 | 원인 | +|------|------|------| +| `403` | 인증 실패 | API 키 누락 또는 불일치 | +| `503` | 서비스 초기화 중 | 서버 기동 직후, 잠시 후 재시도 | +| `422` | 요청 형식 오류 | 필수 파라미터 누락 또는 타입 오류 | +| `500` | 서버 내부 오류 | 로그 확인 필요 | + +--- + +## 권장 호출 순서 + +처음 사용할 때는 아래 순서로 호출해 각 단계가 정상인지 확인합니다. + +``` +1. GET /health → 서버 정상 확인 +2. GET /markets → 시장 설정 확인 +3. GET /data/symbols → 수집 데이터 확인 +4. GET /data/candles → 캔들 데이터 조회 +5. POST /backtest/run → 백테스트 실행 +6. GET /positions → 포지션 확인 +7. GET /pnl → 손익 확인 +``` + +실거래 관련 동작은 충분한 검증(백테스트, paper 모드) 이후에만 진행하세요. diff --git a/docs/QUICKSTART_KO.md b/docs/QUICKSTART_KO.md index bd9e5f5..13cf71f 100644 --- a/docs/QUICKSTART_KO.md +++ b/docs/QUICKSTART_KO.md @@ -1,116 +1,190 @@ # HYDRA Engine 빠른 시작 가이드 -이 문서는 "처음 받은 사람이 10분 안에 테스트와 기본 실행까지 해보는 것"을 목표로 합니다. +**목표:** 이 문서를 따라하면 10~15분 안에 테스트 통과 및 서버 기동까지 완료할 수 있습니다. -## 1. 준비물 +--- -- Python 3.11 이상 -- Git -- Docker / Docker Compose - -## 2. 설치 +## 1단계: 저장소 다운로드 ```bash git clone https://github.com/sinmb79/Hydra-Engine.git cd Hydra-Engine +``` + +--- + +## 2단계: Python 가상환경 설정 + +```bash python -m venv .venv ``` -Windows PowerShell: - +**Windows (PowerShell):** ```powershell .venv\Scripts\Activate.ps1 ``` -패키지 설치: +**macOS / Linux:** +```bash +source .venv/bin/activate +``` + +터미널 앞에 `(.venv)` 가 표시되면 활성화 성공입니다. ```bash pip install -e .[dev] ``` -## 3. 환경 변수 +--- +## 3단계: 환경 변수 설정 + +**macOS / Linux:** ```bash cp .env.example .env ``` -최소 예시: +**Windows (PowerShell):** +```powershell +Copy-Item .env.example .env +``` + +`.env` 파일을 열고 `HYDRA_API_KEY` 를 변경합니다: ```env -HYDRA_API_KEY=my-local-demo-key +HYDRA_API_KEY=my-secret-key-2024 HYDRA_PROFILE=lite REDIS_URL=redis://localhost:6379 ``` -## 4. 정상 동작 확인 +> `HYDRA_API_KEY` 는 API 호출 시 사용하는 비밀번호입니다. 아무 문자열이나 가능합니다. + +--- + +## 4단계: 테스트 실행 ```bash pytest -q ``` -테스트가 모두 통과하면 기본 코드 상태는 정상입니다. +전체 테스트가 통과하면 코드 상태가 정상입니다. -## 5. Lite 프로필 실행 +실패하는 테스트가 있으면: +- 가상환경이 활성화되어 있는지 확인 +- `pip install -e .[dev]` 를 다시 실행 + +--- + +## 5단계: Docker로 서버 실행 + +Docker Desktop이 실행 중인지 먼저 확인합니다. ```bash docker compose -f docker-compose.lite.yml up --build ``` -다른 터미널에서 헬스체크: +새 터미널 창을 열고 헬스체크: ```bash curl http://127.0.0.1:8000/health ``` -## 6. 필수 API 예제 - -### 6.1 활성 시장 확인 - -```bash -curl -H "X-HYDRA-KEY: my-local-demo-key" http://127.0.0.1:8000/markets +```json +{"status": "ok"} ``` -### 6.2 저장된 심볼 목록 확인 +이 응답이 오면 서버가 정상 실행 중입니다. + +--- + +## 6단계: 기본 API 호출 테스트 + +이후 모든 API 호출에는 `X-HYDRA-KEY` 헤더를 붙입니다. + +### 시장 확인 ```bash -curl -H "X-HYDRA-KEY: my-local-demo-key" http://127.0.0.1:8000/data/symbols +curl -H "X-HYDRA-KEY: my-secret-key-2024" \ + http://127.0.0.1:8000/markets ``` -### 6.3 백테스트 실행 +### 저장된 심볼 목록 + +```bash +curl -H "X-HYDRA-KEY: my-secret-key-2024" \ + http://127.0.0.1:8000/data/symbols +``` + +### 캔들 데이터 조회 + +```bash +curl -G http://127.0.0.1:8000/data/candles \ + -H "X-HYDRA-KEY: my-secret-key-2024" \ + --data-urlencode "market=binance" \ + --data-urlencode "symbol=BTC/USDT" \ + --data-urlencode "timeframe=1h" \ + --data-urlencode "limit=50" +``` + +### 백테스트 실행 ```bash curl -X POST http://127.0.0.1:8000/backtest/run \ -H "Content-Type: application/json" \ - -H "X-HYDRA-KEY: my-local-demo-key" \ + -H "X-HYDRA-KEY: my-secret-key-2024" \ -d '{ "market": "binance", "symbol": "BTC/USDT", "timeframe": "1h", "since": 1704067200000, - "until": 1706745600000 + "until": 1706745600000, + "initial_capital": 10000, + "trade_amount_usd": 100, + "commission_pct": 0.001 }' ``` -## 7. CLI 예제 +--- -```bash -python -m hydra.cli.app status -python -m hydra.cli.app market list-markets -python -m hydra.cli.app market enable binance --mode paper -python -m hydra.cli.app kill +## 7단계: 권장 사용 순서 + +``` +테스트 통과 확인 + ↓ +시장 설정 확인 (GET /markets) + ↓ +데이터 수집 상태 확인 (GET /data/symbols) + ↓ +캔들 데이터 조회 (GET /data/candles) + ↓ +백테스트 실행 (POST /backtest/run) + ↓ +전략 성과 분석 + ↓ +(충분한 검증 후) 실거래 연결 ``` -## 8. 추천 사용 순서 +--- -1. 테스트 통과 확인 -2. Lite 프로필 실행 -3. 시장 설정 확인 -4. 데이터 조회 -5. 백테스트 실행 -6. 전략/실거래 확장 여부 판단 +## CLI 빠른 참조 -## 9. 주의사항 +```bash +python -m hydra.cli.app --help # 전체 도움말 +python -m hydra.cli.app setup # 초기 설정 마법사 +python -m hydra.cli.app status # 현재 상태 +python -m hydra.cli.app market list-markets # 시장 목록 +python -m hydra.cli.app market enable binance --mode paper # 모의거래 활성화 +``` -- 실거래 키를 넣기 전에 먼저 paper 모드로 확인하세요. -- API 키, 계정번호, 개인 설정은 `.env` 또는 로컬 전용 파일에만 저장하세요. -- FastAPI Swagger UI는 기본 비활성화 상태입니다. API 사용법은 `docs/API_REFERENCE_KO.md`를 참고하세요. +--- + +## 문제가 생겼을 때 + +| 증상 | 확인할 것 | +|------|----------| +| `ModuleNotFoundError` | 가상환경 활성화 여부, `pip install -e .[dev]` 재실행 | +| `403 Invalid API key` | `.env`의 `HYDRA_API_KEY`와 헤더 값 일치 여부 | +| Redis 연결 오류 | Docker Desktop 실행 여부, `REDIS_URL` 설정 | +| 포트 8000 이미 사용 중 | 다른 프로세스 확인 후 종료 | + +더 자세한 내용은 [README.md](../README.md) 의 FAQ 섹션을 참고하세요. diff --git a/hydra/config/settings.py b/hydra/config/settings.py index c725844..c8fb629 100644 --- a/hydra/config/settings.py +++ b/hydra/config/settings.py @@ -1,4 +1,6 @@ +import warnings from functools import lru_cache +from pydantic import field_validator from pydantic_settings import BaseSettings @@ -13,6 +15,17 @@ class Settings(BaseSettings): model_config = {"env_file": ".env", "env_file_encoding": "utf-8"} + @field_validator("hydra_api_key") + @classmethod + def api_key_must_not_be_default(cls, v: str) -> str: + if v == "change-me": + warnings.warn( + "[HYDRA] HYDRA_API_KEY가 기본값 'change-me'로 설정되어 있습니다. " + ".env 파일에서 안전한 값으로 변경하세요.", + stacklevel=2, + ) + return v + @lru_cache def get_settings() -> Settings: diff --git a/hydra/main.py b/hydra/main.py index ac139b7..71dafcf 100644 --- a/hydra/main.py +++ b/hydra/main.py @@ -48,53 +48,60 @@ async def lifespan(app: FastAPI): configure_logging(settings.log_level) logger.info("hydra_starting", profile=settings.hydra_profile) - r = redis_lib.Redis.from_url(settings.redis_url, decode_responses=True) - set_redis(r) + ohlcv_store = None + try: + r = redis_lib.Redis.from_url(settings.redis_url, decode_responses=True) + set_redis(r) - market_manager = MarketManager() - key_manager = KeyManager() - telegram = TelegramNotifier(settings.telegram_bot_token, settings.telegram_chat_id) - position_tracker = PositionTracker(r) - state_manager = StateManager(r) - risk_engine = RiskEngine(r, position_tracker) - pnl_tracker = PnlTracker(r) - ohlcv_store = create_store() - await ohlcv_store.init() - exchanges = create_exchanges(market_manager, key_manager) + market_manager = MarketManager() + key_manager = KeyManager() + telegram = TelegramNotifier(settings.telegram_bot_token, settings.telegram_chat_id) + position_tracker = PositionTracker(r) + state_manager = StateManager(r) + risk_engine = RiskEngine(r, position_tracker) + pnl_tracker = PnlTracker(r) + ohlcv_store = create_store() + await ohlcv_store.init() + exchanges = create_exchanges(market_manager, key_manager) - kill_switch = KillSwitch( - exchanges=exchanges, - position_tracker=position_tracker, - telegram=telegram, - redis_client=r, - ) - order_queue = OrderQueue( - redis_client=r, - risk_engine=risk_engine, - position_tracker=position_tracker, - exchanges=exchanges, - ) - graceful = GracefulManager(order_queue, position_tracker, r) - graceful.register_signals() + kill_switch = KillSwitch( + exchanges=exchanges, + position_tracker=position_tracker, + telegram=telegram, + redis_client=r, + ) + order_queue = OrderQueue( + redis_client=r, + risk_engine=risk_engine, + position_tracker=position_tracker, + exchanges=exchanges, + ) + graceful = GracefulManager(order_queue, position_tracker, r) + graceful.register_signals() - set_order_queue(order_queue) - set_position_tracker(position_tracker) - set_risk_deps(kill_switch, risk_engine) - set_market_manager(market_manager) - set_pnl_dependencies(pnl_tracker, position_tracker) - set_store(ohlcv_store) - set_redis_for_indicators(r) - set_redis_for_regime(r) - set_redis_for_signals(r) - set_redis_for_supplemental(r) - set_store_for_backtest(ohlcv_store) + set_order_queue(order_queue) + set_position_tracker(position_tracker) + set_risk_deps(kill_switch, risk_engine) + set_market_manager(market_manager) + set_pnl_dependencies(pnl_tracker, position_tracker) + set_store(ohlcv_store) + set_redis_for_indicators(r) + set_redis_for_regime(r) + set_redis_for_signals(r) + set_redis_for_supplemental(r) + set_store_for_backtest(ohlcv_store) + + logger.info("hydra_started") + except Exception as exc: + logger.error("hydra_startup_failed", error=str(exc)) + raise - logger.info("hydra_started") try: yield finally: logger.info("hydra_stopping") - await ohlcv_store.close() + if ohlcv_store is not None: + await ohlcv_store.close() def create_app() -> FastAPI: @@ -104,6 +111,13 @@ def create_app() -> FastAPI: async def auth_guard(request: Request, call_next): if request.url.path == "/health": return await call_next(request) + from fastapi.responses import JSONResponse + api_key = request.headers.get("X-HYDRA-KEY", "") + if not api_key or api_key != get_settings().hydra_api_key: + return JSONResponse( + status_code=403, + content={"detail": "Invalid or missing API key. Set X-HYDRA-KEY header."}, + ) return await call_next(request) app.include_router(health.router)