테스트 강화 및 코드 품질 개선

This commit is contained in:
2025-12-17 00:01:46 +09:00
parent 37a150bd0d
commit 00c57ddd32
51 changed files with 10670 additions and 217 deletions

View File

@@ -0,0 +1,922 @@
# AutoCoinTrader Code Review Report (v6)
## 📋 Executive Summary
**분석 일자**: 2025-12-10
**최종 갱신**: 2025-12-10 (검토의견 반영)
**리뷰 범위**: 전체 코드베이스 (14개 핵심 모듈, 15개 테스트 파일, ~6,000줄)
**분석 방법론**: 다층 심층 분석 (아키텍처/코드품질/성능/트레이딩로직/리스크관리)
**리뷰 관점**: Python 전문가 + 전문 암호화폐 트레이더 이중 시각
**종합 평가**: ⭐⭐⭐⭐⭐ (4.7/5.0)
| 항목 | 평가 | 변화 (v5 대비) |
|------|------|---------------|
| 아키텍처 설계 | ⭐⭐⭐⭐⭐ | 유지 |
| 코드 품질 | ⭐⭐⭐⭐⭐ | ⬆️ (구문 오류 수정) |
| 동시성 안전성 | ⭐⭐⭐⭐⭐ | 유지 |
| 예외 처리 | ⭐⭐⭐⭐⭐ | ⬆️ (구체화 완료) |
| 테스트 커버리지 | ⭐⭐⭐⭐⭐ | ⬆️ (79/79 통과) |
| 트레이딩 로직 | ⭐⭐⭐⭐ | 유지 |
| 리스크 관리 | ⭐⭐⭐⭐⭐ | 유지 |
**주요 개선점 (v5 대비)**:
- ✅ CRITICAL 구문 오류 2개 해결
- ✅ Exception 처리 구체화 완료
- ✅ Lock 순서 규약 문서화
- ✅ 매직 넘버 상수화 완료
- ✅ 테스트 100% 통과 달성
**v6 갱신 사항 (검토의견 반영)**:
- ⬆️ CRITICAL-003: 중복 주문 검증 Timestamp 누락 → Critical 등급 상향 (실거래 영향 크므로 최우선 수정 필요)
- ⬆️ HIGH-001: 순환 import → High 등급 (장기 유지보수성 확보)
- ⬆️ HIGH-002: 설정 검증 부족 → High 등급 (운영 사고 예방)
- ⬆️ MEDIUM-004: ThreadPoolExecutor 종료 → Medium 등급 (운영 안정성)
- ✅ OHLCV 캐시 이미 구현 확인 → LOW-004 항목 삭제, 구현 완료로 업데이트
---
## 🎯 분석 방법론
### 다층 분석 프레임워크
```
┌─────────────────────────────────────────────────┐
│ Layer 1: 아키텍처 & 디자인 패턴 │
├─────────────────────────────────────────────────┤
│ Layer 2: 코드 품질 & 스타일 │
├─────────────────────────────────────────────────┤
│ Layer 3: 동시성 & 스레드 안전성 │
├─────────────────────────────────────────────────┤
│ Layer 4: 예외 처리 & 회복력 │
├─────────────────────────────────────────────────┤
│ Layer 5: 성능 & 최적화 │
├─────────────────────────────────────────────────┤
│ Layer 6: 트레이딩 로직 & 전략 │
├─────────────────────────────────────────────────┤
│ Layer 7: 리스크 관리 & 안전장치 │
└─────────────────────────────────────────────────┘
```
---
## 1. 아키텍처 & 디자인 패턴 분석
### ✅ 1.1 우수한 설계 (Excellent Design)
#### **모듈 분리 원칙 (SRP) 준수**
```
main.py → 진입점 및 루프 제어
signals.py → 매수/매도 신호 생성 및 조건 평가
order.py → 주문 실행 및 모니터링
holdings.py → 보유 현황 관리
common.py → 공통 유틸리티 (Rate Limiter, Budget Manager)
config.py → 설정 관리 및 검증
state_manager.py → 영구 상태 저장 (bot_state.json)
```
**평가**: 각 모듈이 명확한 단일 책임을 가지며, 응집도가 높고 결합도가 낮음.
---
#### **데이터 흐름 아키텍처**
```mermaid
graph TD
A[main.py] -->|매수 신호 체크| B[signals.py]
B -->|신호 발생| C[order.py]
C -->|주문 실행| D[holdings.py]
D -->|상태 저장| E[state_manager.py]
A -->|매도 조건 체크| B
B -->|조건 충족| C
F[common.py] -.->|Rate Limit| C
F -.->|Budget Mgmt| C
G[notifications.py] -.->|알림| B
G -.->|알림| C
```
**평가**: 단방향 데이터 흐름이 명확하며, 의존성이 잘 관리됨.
---
### ⚠️ 1.2 개선 필요 영역
#### **HIGH-001: 순환 import 잠재 위험**
**위치**: `signals.py``order.py`
```python
# signals.py
from .order import execute_buy_order_with_confirmation # 동적 import
from .order import execute_sell_order_with_confirmation
# order.py
from .holdings import get_current_price # 정적 import
# order.py는 signals.py를 직접 import하지 않지만, 간접 참조 가능
```
**문제점**:
- `_handle_buy_signal()` 함수 내에서 동적 import 사용 중
- 모듈 리팩토링 시 순환 의존성 발생 가능
- 코드 확장 시 유지보수 복잡도 증가
**권장 해결 방안**:
```python
# 옵션 1: 의존성 역전 (Dependency Inversion)
# order.py에서 콜백 패턴 사용
# order.py
def execute_buy_order_with_confirmation(
symbol: str,
amount_krw: float,
cfg: RuntimeConfig,
on_success: Optional[Callable] = None # 콜백 추가
) -> dict:
# ... 주문 실행 로직
if on_success:
on_success(result)
return result
# signals.py에서는 콜백 제공
from .order import execute_buy_order_with_confirmation
buy_result = execute_buy_order_with_confirmation(
symbol, amount_krw, cfg,
on_success=lambda r: record_trade(...)
)
```
**우선순위**: 🔴 High (장기 유지보수성 확보)
---
#### **HIGH-002: 설정 검증 부족**
**위치**: `config.py``validate_config()`
**현재 검증 항목**:
- 필수 키 존재 여부
- 타입 검증 (일부)
- 범위 검증 (최소값만)
**누락된 검증**:
```python
# 누락 1: 상호 의존성 검증
# 예: auto_trade.enabled=True인데 API 키 없음
# 누락 2: 논리적 모순 검증
# 예: stop_loss_interval > profit_taking_interval (손절이 익절보다 느림)
# 누락 3: 위험한 설정 경고
# 예: max_threads > 10 (과도한 스레드)
```
**실제 발생 가능한 운영 사고**:
```
시나리오 1: stop_loss_interval=300 (5시간), profit_taking_interval=60 (1시간)
→ 손실은 5시간마다 체크, 익절은 1시간마다 체크
→ 급락 시 손절이 늦어져 큰 손실 발생 가능
시나리오 2: auto_trade.enabled=true, API 키 없음
→ 봇 실행 후 첫 매수 시점에 런타임 에러 발생
→ 사전 검증 부재로 소중한 매수 기회 놓침
```
**권장 추가 검증**:
```python
def validate_config(cfg: dict) -> tuple[bool, str]:
# ... (기존 검증)
# 추가 1: Auto Trade 설정 일관성
auto_trade = cfg.get("auto_trade", {})
if auto_trade.get("enabled") and auto_trade.get("buy_enabled"):
if not cfg.get("upbit_access_key") or not cfg.get("upbit_secret_key"):
return False, "auto_trade 활성화 시 Upbit API 키 필수"
# 추가 2: 간격 논리 검증
stop_loss_min = cfg.get("stop_loss_check_interval_minutes", 60)
profit_min = cfg.get("profit_taking_check_interval_minutes", 240)
if stop_loss_min > profit_min:
logger.warning(
"경고: 손절 주기(%d분)가 익절 주기(%d분)보다 김. "
"손절은 더 자주 체크하는 것이 안전합니다.",
stop_loss_min, profit_min
)
# 추가 3: 스레드 수 검증
max_threads = cfg.get("max_threads", 3)
if max_threads > 10:
logger.warning(
"경고: max_threads=%d는 과도할 수 있음. "
"Upbit API Rate Limit(초당 8회, 분당 590회) 고려 필요",
max_threads
)
return True, ""
```
**우선순위**: 🔴 High (운영 사고 예방)
---
## 2. 코드 품질 & 스타일 분석
### ✅ 2.1 우수한 점
#### **타입 힌팅 (Type Hinting) - 98%+ 커버리지**
```python
# 모든 공개 함수에 타입 힌팅 적용
def evaluate_sell_conditions(
current_price: float,
buy_price: float,
max_price: float,
holding_info: dict,
config: dict = None
) -> dict:
```
**평가**: 산업 표준 수준의 타입 안전성 확보.
---
#### **Docstring 품질 (Google Style)**
```python
def get_upbit_balances(cfg: RuntimeConfig) -> dict | None:
"""
Upbit API를 통해 현재 잔고를 조회합니다.
Args:
cfg: RuntimeConfig 객체 (Upbit API 키 포함)
Returns:
심볼별 잔고 딕셔너리 (예: {"BTC": 0.5, "ETH": 10.0})
- MIN_TRADE_AMOUNT (1e-8) 이하의 자산은 제외됨
- API 키 미설정 시 빈 딕셔너리 {} 반환
- 네트워크 오류 시 None 반환
Raises:
Exception: Upbit API 호출 중 발생한 예외는 로깅되고 None 반환
"""
```
**평가**: 명확한 문서화로 유지보수성 우수.
---
### ⚠️ 2.2 개선 필요 영역
#### **LOW-001: 일관성 없는 로그 레벨 사용**
**문제점**: 동일한 유형의 이벤트에 다른 로그 레벨 사용
```python
# signals.py
logger.info("[%s] 매수 신호 발생", symbol) # INFO
logger.debug("[%s] 재매수 대기 중", symbol) # DEBUG
# order.py
logger.warning("[매수 건너뜀] %s", reason) # WARNING
logger.info("[매수 성공] %s", symbol) # INFO
```
**권장 로그 레벨 가이드라인**:
```python
"""
DEBUG : 개발자용 상세 흐름 추적
INFO : 정상 작동 중요 이벤트 (매수/매도 성공)
WARNING : 주의 필요 (잔고 부족, 재매수 쿨다운)
ERROR : 오류 발생 (API 실패, 설정 오류)
CRITICAL: 시스템 중단 위험 (Circuit Breaker Open)
"""
# 권장 수정
logger.warning("[%s] 재매수 대기 중 (%d시간 쿨다운)", symbol, hours)
logger.error("[매수 실패] %s: API 오류", symbol)
```
**우선순위**: 🟢 Low
---
#### **LOW-002: f-string vs % 포매팅 혼재**
```python
# 혼재 사용
logger.info(f"[{symbol}] 매수 금액: {amount}") # f-string
logger.info("[%s] 매도 금액: %d", symbol, amount) # % 포매팅
```
**권장**: logging 라이브러리는 % 포매팅을 권장 (lazy evaluation)
```python
# 권장: % 포매팅 (로그가 출력되지 않으면 포매팅 생략)
logger.debug("[%s] 상세 정보: 가격=%f, 수량=%f", symbol, price, volume)
# f-string은 조건부 로그에만 사용
if condition:
msg = f"복잡한 {계산} 포함된 {메시지}"
logger.info(msg)
```
**우선순위**: 🟢 Low
---
## 3. 동시성 & 스레드 안전성 분석
### ✅ 3.1 우수한 점 (Best in Class)
#### **리소스별 Lock 분리**
```python
# 완벽한 Lock 분리로 경합 최소화
holdings_lock # holdings.json 보호
_state_lock # bot_state.json 보호
_cache_lock # 가격/잔고 캐시 보호
_pending_order_lock # 대기 주문 보호
krw_balance_lock # KRW 잔고 조회 직렬화
recent_sells_lock # recent_sells.json 보호
```
**평가**: 산업 표준을 초과하는 설계. 각 리소스가 독립적인 Lock으로 보호됨.
---
#### **Lock 획득 순서 규약 문서화**
```python
# common.py (라인 93-105)
# ============================================================================
# Lock 획득 순서 규약 (데드락 방지)
# ============================================================================
# 1. holdings_lock (최우선)
# 2. _state_lock
# 3. krw_balance_lock
# 4. recent_sells_lock
# 5. _cache_lock, _pending_order_lock (개별 리소스, 독립적)
```
**평가**: 데드락 방지를 위한 명확한 규약 문서화. 엔터프라이즈급 품질.
---
#### **KRWBudgetManager - 토큰 기반 예산 관리**
```python
class KRWBudgetManager:
"""
- 고유 토큰으로 각 주문 구분
- 동일 심볼 다중 주문 안전 지원
- Race Condition 완벽 차단
"""
def allocate(self, symbol, amount_krw, upbit=None, ...) -> tuple[bool, float, str]:
token = secrets.token_hex(8) # 고유 토큰 생성
# ...
```
**평가**: 복잡한 동시성 문제를 우아하게 해결. Google/Meta 수준의 설계.
---
### ⚠️ 3.2 개선 여지
#### **MEDIUM-004: ThreadPoolExecutor 종료 처리**
**위치**: `threading_utils.py`
**현재 코드**:
```python
def run_with_threads(symbols, cfg, aggregate_enabled=False):
with ThreadPoolExecutor(max_workers=workers) as executor:
# ... 작업 실행
# with 블록 종료 시 자동 shutdown(wait=True)
```
**잠재적 문제**:
- SIGTERM 수신 시 진행 중인 스레드가 완료될 때까지 대기
- 최악의 경우 5분 이상 종료 지연 가능 (fetch_ohlcv 타임아웃 × 스레드 수)
- Docker 컨테이너 재시작 시 종료 지연으로 인한 불편함
**실제 시나리오**:
```
1. 사용자가 docker stop 실행 (SIGTERM 전송)
2. 8개 스레드가 각각 API 호출 중 (최대 300초 타임아웃)
3. 모든 스레드 완료까지 최대 5분 대기
4. Docker가 10초 후 SIGKILL 전송 → 강제 종료
5. 진행 중인 주문 데이터 손실 가능성
```
**권장 개선**:
```python
# 전역 종료 플래그 활용
_shutdown_requested = False
def run_with_threads(symbols, cfg, aggregate_enabled=False):
with ThreadPoolExecutor(max_workers=workers) as executor:
futures = []
for symbol in symbols:
if _shutdown_requested: # 조기 종료
break
future = executor.submit(process_symbol, symbol, cfg=cfg)
futures.append(future)
# 타임아웃 기반 종료
for future in as_completed(futures, timeout=60):
if _shutdown_requested:
break
try:
future.result(timeout=10)
except TimeoutError:
logger.warning("스레드 타임아웃, 강제 종료")
```
**우선순위**: 🟡 Medium (운영 환경 안정성)
---
## 4. 예외 처리 & 회복력 분석
### ✅ 4.1 우수한 점
#### **구체적 예외 처리 (v5 개선 완료)**
```python
# holdings.py (v5 개선)
except json.JSONDecodeError as e:
logger.error("[ERROR] JSON 디코드 실패: %s", e)
except OSError as e:
logger.exception("[ERROR] 입출력 예외: %s", e)
raise
# order.py (v5 개선)
except (requests.exceptions.RequestException, ValueError, TypeError, OSError) as e:
logger.error("[매도 실패] 예외 발생: %s", e)
```
**평가**: 구체적 예외 처리로 버그 은폐 방지. 엔터프라이즈급 품질.
---
#### **Circuit Breaker 패턴**
```python
class CircuitBreaker:
STATES = ["closed", "open", "half_open"]
# 연속 3회 실패 → 5분 차단 → 점진적 복구
```
**평가**: 마이크로서비스 아키텍처 수준의 회복력 메커니즘.
---
#### **ReadTimeout 복구 로직**
```python
# order.py
except requests.exceptions.ReadTimeout:
# 1단계: 중복 주문 확인
is_dup, dup_order = _has_duplicate_pending_order(...)
if is_dup:
return dup_order
# 2단계: 최근 주문 조회
found = _find_recent_order(...)
if found:
return found
```
**평가**: 네트워크 불안정 환경에서도 안정적 작동. 실전 경험 기반 설계.
---
### ⚠️ 4.2 개선 필요 영역
#### **CRITICAL-003: 중복 주문 검증의 Timestamp 누락 (매우 중요)**
**위치**: `order.py``_has_duplicate_pending_order()`
**현재 로직**:
```python
# 수량/가격만으로 중복 판단
if abs(order_vol - volume) < 1e-8:
if price is None or abs(order_price - price) < 1e-4:
return True, order
```
**문제점**:
1. **동일 수량/가격의 서로 다른 주문** 구분 불가
- 예: 10초 간격으로 동일 금액 매수 시 두 번째 주문이 중복으로 오판
2. **Timestamp 기반 검증 없음**
- 과거 완료된 주문(done)을 현재 진행 중인 주문으로 오판
- 1분 전 주문과 방금 주문을 구분 못함
**심각도 평가**:
- 🔴 **실거래 영향**: 정상적인 재매수 기회를 차단하여 수익 기회 손실
- 🔴 **발생 빈도**: 동일 금액 매수 설정 시 높은 확률로 발생
- 🔴 **디버깅 난이도**: 로그에서 "중복 주문 감지"로만 표시되어 원인 파악 어려움
**실제 발생 가능 시나리오**:
```
1. 14:00:00 - BTC 50,000원 매수 주문 (타임아웃)
2. 14:00:05 - 재시도 로직으로 동일 주문 발견 → 중복 판단 (✅ 정상)
3. 14:00:10 - 주문 체결 완료 (state="done")
4. 14:05:00 - 매수 신호 재발생, 동일 금액 매수 시도
5. 14:05:01 - 5분 전 "완료된 주문"을 중복으로 오판 → 매수 차단 (❌ 치명적 버그)
```
**권장 해결 방안**:
```python
def _has_duplicate_pending_order(
upbit, market, side, volume, price=None,
lookback_sec=120 # 2분 이내만 검사
):
"""중복 주문 확인 (시간 제한 추가)"""
now = time.time()
try:
orders = upbit.get_orders(ticker=market, state="wait")
if orders:
for order in orders:
# 시간 필터 추가
order_time = order.get("created_at") # ISO 8601 형식
if order_time:
order_ts = datetime.fromisoformat(order_time.replace('Z', '+00:00')).timestamp()
if (now - order_ts) > lookback_sec:
continue # 오래된 주문은 건너뜀
# 기존 수량/가격 검증
if order.get("side") != side:
continue
if abs(float(order.get("volume")) - volume) < 1e-8:
if price is None or abs(float(order.get("price")) - price) < 1e-4:
logger.info(
"[중복 감지] %.1f초 전 주문: %s",
now - order_ts, order.get("uuid")
)
return True, order
# Done orders도 시간 제한 적용
dones = upbit.get_orders(ticker=market, state="done", limit=5)
# ... (동일한 시간 필터 적용)
except Exception as e:
logger.warning("[중복 검사] 오류: %s", e)
return False, None
```
**우선순위**: 🔴 Critical (즉시 수정 필요, 실거래 수익 손실 직결)
---
## 5. 성능 & 최적화 분석
### ✅ 5.1 우수한 점
#### **캐시 전략**
```python
# 2초 TTL 캐시로 API 호출 최소화
_price_cache: dict[str, tuple[float, float]] = {}
_balance_cache: tuple[dict | None, float] = ({}, 0.0)
PRICE_CACHE_TTL = 2.0
BALANCE_CACHE_TTL = 2.0
```
**효과**:
- API 호출 80% 감소 (추정)
- Rate Limit 여유 확보
---
#### **Rate Limiter (Token Bucket)**
```python
api_rate_limiter = RateLimiter(
max_calls=8, # 초당 8회
period=1.0,
additional_limits=[(590, 60.0)] # 분당 590회
)
```
**평가**: Upbit API 제한(초당 10회, 분당 600회)을 완벽하게 준수.
---
### ⚠️ 5.2 개선 여지
#### **✅ 캐시 전략 검증 결과**
**위치**: `indicators.py``fetch_ohlcv()`
**검증 결과**: ✅ **OHLCV 캐싱 이미 구현됨**
```python
# src/indicators.py 라인 21-66
_ohlcv_cache = {} # 이미 존재
CACHE_TTL = 240.0 # 4분 TTL
def fetch_ohlcv(ticker, interval, count, use_cache=True):
cache_key = f"{ticker}_{interval}_{count}"
# 캐시 확인
if use_cache and cache_key in _ohlcv_cache:
cached_df, cached_time = _ohlcv_cache[cache_key]
if time.time() - cached_time < CACHE_TTL:
return cached_df.copy()
# API 호출 및 캐시 저장
# ...
```
**평가**:
- ✅ 캐시 키 설계 우수 (ticker + interval + count)
- ✅ TTL 설정 적절 (4분)
- ✅ 복사본 반환으로 원본 보호
- ✅ 만료된 캐시 자동 정리 (`_cleanup_ohlcv_cache()`)
**결론**: 이 항목은 이미 적용되어 있으므로 추가 작업 불필요
---
## 8. 테스트 분석
### ✅ 8.1 우수한 점
**테스트 커버리지**: 79/79 통과 (100%)
| 테스트 종류 | 파일 수 | 커버리지 |
|-----------|---------|---------|
| 단위 테스트 | 15개 | 핵심 기능 |
| 통합 테스트 | 3개 | 동시성, 상태 동기화 |
| 경계값 테스트 | 1개 | 손익 경계 |
| 스트레스 테스트 | 2개 | 10 스레드 |
**평가**: 산업 표준을 초과하는 테스트 품질.
---
### ⚠️ 8.2 개선 여지
#### **MEDIUM-006: End-to-End 테스트 부재**
**누락된 시나리오**:
```python
# 전체 플로우 테스트 (매수 → 보유 → 매도)
def test_full_trading_cycle():
"""
1. 매수 신호 발생
2. 매수 주문 실행
3. holdings.json 업데이트
4. max_price 추적
5. 익절 조건 발생
6. 부분 매도 (50%)
7. 트레일링 스탑 발동
8. 전량 매도
9. recent_sells 기록
10. 재매수 방지 확인
"""
# Mock을 최소화하고 실제 플로우 검증
```
**우선순위**: 🟡 Medium
---
## 9. 보안 분석
### ✅ 9.1 우수한 점
```python
# 1. API 키 환경변수 관리
upbit_access_key = os.getenv("UPBIT_ACCESS_KEY")
# 2. 파일 권한 설정 (rw-------)
os.chmod(holdings_file, stat.S_IRUSR | stat.S_IWUSR)
# 3. 민감 정보 로그 제외
logger.info("API 키 유효성 확인 완료") # 키 값 노출 안 함
# 4. 토큰 기반 주문 확인
token = secrets.token_hex(16) # 추측 불가능한 토큰
```
**평가**: 기본적인 보안 수준 충족.
---
### ⚠️ 9.2 개선 필요 영역
#### **LOW-005: API 키 검증 강화**
**현재**:
```python
# 단순 잔고 조회로 검증
balances = upbit.get_balances()
```
**권장**:
```python
def validate_upbit_api_keys_enhanced(access_key, secret_key):
"""강화된 API 키 검증"""
try:
upbit = pyupbit.Upbit(access_key, secret_key)
# 1. 잔고 조회 (읽기 권한)
balances = upbit.get_balances()
# 2. 주문 가능 여부 확인 (쓰기 권한)
# Dry run 주문 시도 (실제 주문 안 됨)
try:
# 최소 금액으로 테스트 주문 (실패해도 OK)
upbit.buy_limit_order("KRW-BTC", 1000000, 0.00000001)
except Exception as e:
error_msg = str(e)
if "insufficient" in error_msg.lower():
# 잔고 부족 = 주문 권한 있음
pass
elif "invalid" in error_msg.lower():
return False, "주문 권한 없는 API 키"
# 3. IP 화이트리스트 확인 (선택)
# ...
return True, "OK"
except Exception as e:
return False, str(e)
```
**우선순위**: 🟢 Low
---
## 10. 문서화 분석
### ✅ 10.1 우수한 점
```
docs/
├── project_requirements.md # 기획서
├── implementation_plan.md # 구현 체크리스트
├── user_guide.md # 사용자 가이드
├── project_state.md # 현재 상태
└── code_review_report_v*.md # 리뷰 기록 (v1~v6)
```
**평가**: 포괄적인 문서화로 유지보수성 우수.
---
### ⚠️ 10.2 개선 필요 영역
#### **LOW-006: API 문서 부재**
**권장 추가**:
```markdown
# docs/api_reference.md
## 핵심 함수 레퍼런스
### order.py
#### place_buy_order_upbit()
**목적**: 매수 주문 실행
**파라미터**:
- market (str): 마켓 코드 (예: "KRW-BTC")
- amount_krw (float): 매수 금액 (KRW)
- cfg (RuntimeConfig): 설정 객체
**반환값**: dict
- status: "filled" | "partial" | "failed" | ...
- uuid: 주문 ID
- ...
**예외**:
- ValueError: 금액이 최소 주문 금액 미만
- ...
**예제**:
```python
result = place_buy_order_upbit("KRW-BTC", 50000, cfg)
if result["status"] == "filled":
print("매수 성공")
```
```
**우선순위**: 🟢 Low
---
# code_review_report_v6 최종 ?<3F><20>??<3F>선?<3F>위 로드<EBA19C>?
## ?<3F><> 개선 권고?<3F>항 ?<3F>선?<3F>
### ?<3F><> CRITICAL (즉시 ?<3F>정 ?<3F>요)
| ID | ??<3F><> | ?<3F>향??| ?<3F>상 ?<3F>업 ?<3F>간 |
|----|------|--------|---------------|
| **CRITICAL-003** | 중복 주문 검<>?Timestamp ?<3F>락 | ?<3F>거???<3F>익 ?<3F>실 | 2?<3F>간 |
**권장 ?<3F>업 ?<3F>서**:
1. `order.py`??`_has_duplicate_pending_order()` ?<3F>수??`lookback_sec=120` ?<3F>라미터 추<>?
2. Timestamp 비교 로직 구현 (created_at ?<3F>드 ?<3F>싱)
3. ?<3F>스??케?<3F>스 추<>? (?<3F>간 경계 케?<3F>스)
4. ?<3F>제 거래 ??Dry-run 검<>?
---
### ?<3F><> HIGH (?<3F>기 ??개선 권장)
| ID | ??<3F><> | ?<3F>향??| ?<3F>상 ?<3F>업 ?<3F>간 |
|----|------|--------|---------------|
| **HIGH-001** | ?<3F>환 import ?<3F>재 ?<3F>험 | ?<3F>기 ?<3F><>?보수??| 4?<3F>간 |
| **HIGH-002** | ?<3F>정 검<>?부<>?| ?<3F>영 ?<3F>고 ?<3F>방 | 2?<3F>간 |
**권장 ?<3F>근**:
- HIGH-001: ?<3F>존????<3F><> ?<3F>턴 ?<3F>용, 콜백 기반 ?<3F><EFBFBD>?리팩?<3F>
- HIGH-002: `validate_config()` 강화, ?<3F>호 ?<3F>존???<3F>리??모순 검<>?추<>?
---
### ?<3F><> MEDIUM (중기 개선 ??<3F><>)
| ID | ??<3F><> | ?<3F>향??| ?<3F>상 ?<3F>업 ?<3F>간 |
|----|------|--------|---------------|
| **MEDIUM-004** | ThreadPoolExecutor 종료 처리 | ?<3F>영 ?<3F>정??| 3?<3F>간 |
| **MEDIUM-006** | End-to-End ?<3F>스??부??| ?<3F><>? ?<3F>스??| 6?<3F>간 |
**권장 ?<3F>근**:
- MEDIUM-004: Signal handler 추<>?, graceful shutdown 구현
- MEDIUM-006: ?<3F>체 거래 ?<3F>로???<3F>합 ?<3F>스???<3F>
---
### ?<3F><> LOW (?<3F>기 개선 ??<3F><>)
| ID | ??<3F><> | ?<3F>향??| ?<3F>상 ?<3F>업 ?<3F>간 |
|----|------|--------|---------------|
| **LOW-001** | 로그 ?<3F>벨 ?<3F><>???| ?<3F><EFBFBD>??<3F>율 | 1?<3F>간 |
| **LOW-002** | f-string vs % ?<3F>매???<3F>일 | 코드 ?<3F><>???| 1?<3F>간 |
| **LOW-005** | API ??검<>?강화 | 보안 | 2?<3F>간 |
| **LOW-006** | API 문서 ?<3F>성 | 개발 ?<3F>산??| 4?<3F>간 |
---
## ?<3F><><>??<3F>료 ??<3F><>
| ??<3F><> | ?<3F>태 | 비고 |
|------|------|------|
| **OHLCV 캐시** | ??구현 ?<3F>료 | `indicators.py`???<3F><>? ?<3F>용??(TTL 240<34>? |
| **v5 개선?<3F>항** | ??모두 ?<3F>용 | CRITICAL-001, CRITICAL-002, HIGH-001, MEDIUM-001, MEDIUM-002 |
---
## ?? 3?<3F>계 ?<3F>행 계획
### Phase 1: 긴급 (1주일)
```
1. CRITICAL-003 ?<3F>정 (2h)
2. HIGH-002 구현 (2h)
3. ?<3F><>? ?<3F>스??(1h)
<EFBFBD>??<3F>요: 5?<3F>
```
### Phase 2: ?<3F>기 (2주일)
```
1. HIGH-001 리팩?<3F>링 (4h)
2. MEDIUM-004 개선 (3h)
3. ?<3F>합 ?<3F>스??(2h)
<EFBFBD>??<3F>요: 9?<3F>
```
### Phase 3: 중장<ECA491>?(1개월)
```
1. MEDIUM-006 E2E ?<3F>스??(6h)
2. LOW ??<3F><> ?<3F>괄 처리 (8h)
3. 문서??(4h)
<EFBFBD>??<3F>요: 18?<3F>
```
---
## ?<3F><> ?<3F>심 ?<3F>
1. **?<3F>키?<3F>처 ?<3F>수??*: 모듈 분리, ?<3F>시???<3F>계??Google/Meta ?<3F><>?
2. **?<3F>전 검<>??<3F>요**: CRITICAL-003?<3F> ?<3F>거??직전 반드???<3F>
3. **기술 부<>?관<>?*: HIGH/MEDIUM ??<3F><>?<3F> 코드 ?<3F>장 ???<3F>결 권장
4. **지?<3F>적 개선**: ??? ?<3F>선?<3F>위 ??<3F><>???<3F>진??개선?<3F>로 ?<3F>질 ?<3F>
---
## 변<>??<3F>
**v6.1 (2025-12-10)**:
- 검?<3F><EFBFBD>?반영: CRITICAL-003 ?<3F>급 ?<3F>향 (Medium ??Critical)
- HIGH-001, HIGH-002 ?<3F>급 ?<3F>향 (Medium ??High)
- MEDIUM-004 ?<3F>급 ?<3F>향 (Low ??Medium)
- OHLCV 캐시 구현 ?<3F>인 ?<3F>료, LOW-004 ??<3F><>
- ?<3F>선?<3F>위 로드<EBA19C>?<3F>?3?<3F>계 ?<3F>행 계획 추<>?
**v6.0 (2025-12-10)**:
- 최초 ?<3F>성: 7계층 ?<3F>층 분석 ?<3F>레?<3F>워???<3F>
- 11<31>?개선 ??<3F><> ?<3F>출 (CRITICAL 1, HIGH 2, MEDIUM 2, LOW 6)
- v5 개선?<3F>항 검<>??<3F>료 (5/5 ??<3F><>)