20 KiB
AutoCoinTrader Code Review Report (v5)
1. 개요 (Overview)
본 보고서는 AutoCoinTrader 프로젝트의 전체 코드베이스에 대한 v5 종합 심층 분석입니다. v4 리포트 이후의 변경사항을 반영하고, Python 전문가 및 전문 암호화폐 트레이더 관점에서 단계별로 꼼꼼하게 검토하였습니다.
분석 범위:
- 14개 핵심 소스 모듈 (총 ~5,500줄)
- 15개 테스트 파일
- 아키텍처, 코드 품질, 성능, 안정성, 트레이딩 로직, 리스크 관리
분석 방법론:
- 정적 코드 분석 (Static Analysis)
- 논리 흐름 추적 (Control Flow Analysis)
- 동시성 패턴 검토 (Concurrency Review)
- 트레이딩 전략 유효성 검토 (Strategy Validation)
2. 🚨 긴급 수정 필요 사항 (CRITICAL Issues)
CRITICAL-001: order.py 구문 오류 (Syntax Error)
파일: src/order.py (라인 789-792)
문제점:
# 현재 코드 (오류)
if attempt == max_retries:
raise
time.sleep(ORDER_RETRY_DELAY)
continue # ← IndentationError: 들여쓰기 오류
except (requests.exceptions.RequestException, ValueError, TypeError, OSError) as e:
영향:
- Python 인터프리터 오류: 이 파일을 import하면
IndentationError발생 - 전체 시스템 작동 불가: 매도 주문 기능 완전 실패
수정 방안:
# 수정된 코드
if attempt == max_retries:
raise
time.sleep(ORDER_RETRY_DELAY)
continue
except (requests.exceptions.RequestException, ValueError, TypeError, OSError) as e:
우선순위: 🔴 즉시 수정 필수 (P0)
CRITICAL-002: holdings.py 중복 return 문
파일: src/holdings.py (라인 510-513)
문제점:
if not new_holdings_map:
return {}
return {} # ← 접근 불가능한 코드 (dead code)
영향:
- 코드는 실행되지만, 죽은 코드(dead code)가 존재
- 유지보수 혼란 및 코드 품질 저하
수정 방안: 중복 return {} 제거
우선순위: 🟡 빠른 수정 권장 (P1)
3. Python 전문가 관점 분석 (Technical Review)
3.1 아키텍처 및 디자인 패턴 ⭐⭐⭐⭐⭐
✅ 우수한 점
| 패턴 | 적용 내용 | 평가 |
|---|---|---|
| 단일 책임 원칙 (SRP) | 각 모듈이 명확한 역할 수행 (order.py=주문, signals.py=신호, holdings.py=보유관리) |
Excellent |
| 불변 설정 객체 | RuntimeConfig dataclass (frozen=True)로 설정 불변성 보장 |
Best Practice |
| 상태 분리 | StateManager로 봇 상태와 거래소 캐시 분리 |
v4 대비 개선 |
| 원자적 파일 쓰기 | 임시 파일 → os.replace() → os.fsync() 패턴 일관 적용 |
Production Ready |
⚠️ 개선 필요 영역
1. 순환 의존성 잠재 리스크 (Medium)
graph TD
A[order.py] --> B[holdings.py]
A --> C[signals.py]
A --> D[common.py]
B --> E[state_manager.py]
C --> A
C --> B
order.py↔signals.py간 상호 참조 존재TYPE_CHECKING으로 런타임 순환 회피 중이나, 리팩토링 시 주의 필요
2. 모듈 크기 불균형 (Low)
| 모듈 | 라인 수 | 권장 |
|---|---|---|
order.py |
1,289 | ⚠️ 500~700 권장 (분할 고려) |
signals.py |
960 | ⚠️ 분할 고려 |
holdings.py |
700 | ✅ 적정 |
common.py |
413 | ✅ 적정 |
권장: order.py를 order_buy.py, order_sell.py, order_monitor.py로 분할
3.2 코드 품질 및 스타일 ⭐⭐⭐⭐
✅ 우수한 점
1. 타입 힌팅 (Type Hinting) - 95%+ 커버리지
def place_buy_order_upbit(market: str, amount_krw: float, cfg: RuntimeConfig) -> dict:
2. 정밀도 관리 (Precision Handling)
# Decimal 사용으로 부동소수점 오차 방지
getcontext().prec = 28
d_price = Decimal(str(price))
volume = (d_amount / d_price).quantize(Decimal("0.00000001"), rounding=ROUND_DOWN)
3. 방어적 프로그래밍 (Defensive Programming)
# None-safe 포매팅
def _safe_format(value, precision: int = 2, default: str = "N/A") -> str:
if value is None:
return default
if pd.isna(value):
return default
⚠️ 개선 필요 영역
1. 광범위한 Exception 처리 (High)
현재 여러 곳에서 Exception 전체를 catch하고 있음:
# 문제점: 예상치 못한 버그를 숨길 수 있음
except Exception as e:
logger.error("오류: %s", e)
return None
권장: 구체적 예외 타입 지정
except (requests.exceptions.RequestException, json.JSONDecodeError, ValueError) as e:
logger.error("알려진 오류: %s", e)
except Exception as e:
logger.exception("예상치 못한 오류 - 재발생: %s", e)
raise # 또는 특정 처리
영향 범위:
holdings.py: 9개소order.py: 12개소signals.py: 7개소
2. 매직 넘버 하드코딩 (Medium)
# 현재
time.sleep(0.5) # 무슨 의미?
if len(calls) >= 590: # 왜 590?
# 권장
TELEGRAM_RATE_LIMIT_DELAY = 0.5 # Telegram API 초당 제한 대응
UPBIT_MINUTE_RATE_LIMIT = 590 # Upbit 분당 600회 제한의 안전 마진
3. 일관성 없는 로그 포맷 (Low)
# 혼재된 스타일
logger.info("[INFO] [%s] 매수 성공", symbol) # [INFO] 중복
logger.info("[%s] 매수 성공", symbol) # 권장 스타일
logger.info(f"[{symbol}] 매수 성공") # f-string 스타일
3.3 동시성 및 스레드 안전성 ⭐⭐⭐⭐⭐
✅ 우수한 점
1. 리소스별 Lock 분리 (Best Practice)
# 각 리소스에 전용 Lock 할당 → 데드락 위험 최소화
holdings_lock = threading.RLock() # holdings.json 보호
_state_lock = threading.RLock() # bot_state.json 보호
_cache_lock = threading.Lock() # 가격/잔고 캐시 보호
_pending_order_lock = threading.Lock() # 대기 주문 보호
krw_balance_lock = threading.RLock() # KRW 잔고 조회 직렬화
recent_sells_lock = threading.RLock() # recent_sells.json 보호
2. KRW 예산 관리자 (Token 기반)
class KRWBudgetManager:
"""동일 심볼 다중 주문도 안전하게 지원"""
def allocate(self, symbol, amount_krw, ...) -> tuple[bool, float, str | None]:
# 고유 토큰으로 각 주문 구분
token = secrets.token_hex(8)
3. Rate Limiter (Token Bucket)
# 초당 8회 + 분당 590회 동시 제한
api_rate_limiter = RateLimiter(
max_calls=8,
period=1.0,
additional_limits=[(590, 60.0)]
)
⚠️ 개선 필요 영역
1. Lock 획득 순서 미문서화 (Medium)
여러 Lock을 동시에 획득하는 경우가 있으나, 획득 순서가 문서화되지 않음.
# 잠재적 데드락 시나리오
# Thread A: holdings_lock → _state_lock
# Thread B: _state_lock → holdings_lock
# 권장: Lock 획득 순서 규약 문서화
# 1. holdings_lock
# 2. _state_lock
# 3. _cache_lock
2. 캐시 만료 시 경합 (Low)
# 캐시 TTL 만료 시 여러 스레드가 동시에 API 호출 가능
if (now - ts) > PRICE_CACHE_TTL:
# 여러 스레드가 이 조건을 동시에 통과할 수 있음
price = pyupbit.get_current_price(market)
권장: Double-checked locking 또는 cache stampede prevention
3.4 예외 처리 및 회복력 ⭐⭐⭐⭐⭐
✅ 우수한 점
1. Circuit Breaker 패턴
class CircuitBreaker:
"""API 장애 시 자동 차단"""
STATES = ["closed", "open", "half_open"]
# 연속 3회 실패 → 5분 차단 → 점진적 복구
2. 지수 백오프 재시도 (Exponential Backoff with Jitter)
sleep_time = base_backoff * (2 ** (attempt - 1))
sleep_time += random.uniform(0, jitter_factor * sleep_time)
3. ReadTimeout 복구 로직
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 # 이미 체결된 주문 반환
⚠️ 개선 필요 영역
1. 중복 주문 검증 정확도 (Medium)
# 현재: 수량/가격만으로 중복 판단
if abs(order_vol - volume) < 1e-8:
if price is None or abs(order_price - price) < 1e-4:
return True, order
# 문제: 다른 사유로 동일 수량/가격 주문이 존재할 수 있음
# 권장: UUID 캐시 또는 client_order_id 사용
3.5 테스트 커버리지 분석 ⭐⭐⭐⭐
✅ 테스트 파일 현황 (15개)
| 테스트 파일 | 대상 모듈 | 커버리지 |
|---|---|---|
test_order.py |
order.py |
핵심 기능 |
test_evaluate_sell_conditions.py |
signals.py |
매도 조건 |
test_krw_budget_manager.py |
common.py |
예산 관리 |
test_concurrent_buy_orders.py |
동시성 로직 | 경합 조건 |
test_circuit_breaker.py |
circuit_breaker.py |
복구 로직 |
test_state_reconciliation.py |
holdings.py/state_manager.py |
상태 동기화 |
test_boundary_conditions.py |
다수 | 경계값 |
test_critical_fixes.py |
다수 | 주요 버그픽스 |
test_recent_sells.py |
common.py |
재매수 방지 |
test_holdings_cache.py |
holdings.py |
캐시 로직 |
| ... |
⚠️ 개선 필요 영역
1. 통합 테스트 부재 (High)
- 현재: 대부분 단위 테스트
- 권장: 매수→보유→매도 전체 플로우 통합 테스트
2. 엣지 케이스 미커버 (Medium)
- 네트워크 단절 중 여러 주문 동시 발생
- API Rate Limit 도달 시 동작
- 파일 시스템 권한 오류
3. 모킹 의존도 높음 (Low)
pyupbit모킹으로 실제 API 동작 검증 불가- 권장: 별도 샌드박스 환경 테스트
4. 전문 트레이더 관점 분석 (Trading Logic Review)
4.1 진입 전략 (Entry Strategy) ⭐⭐⭐⭐
✅ 복합 매수 조건 (Triple Confirmation)
graph TD
A[매수조건1] -->|MACD 상향 돌파| B{SMA5 > SMA200}
B -->|Yes| C{ADX > 25}
C -->|Yes| D[매수 신호]
E[매수조건2] -->|SMA 골든크로스| F{MACD > Signal}
F -->|Yes| G{ADX > 25}
G -->|Yes| D
H[매수조건3] -->|ADX 상향 돌파| I{SMA5 > SMA200}
I -->|Yes| J{MACD > Signal}
J -->|Yes| D
분석:
- ✅ 다중 확인으로 False Signal 감소
- ✅ ADX 필터로 추세 확인 (횡보장 회피)
- ⚠️ 보수적 접근으로 진입 기회 감소 가능
✅ 재매수 방지 (Rebuy Cooldown)
def can_buy(symbol: str, cooldown_hours: int = 24) -> bool:
"""매도 후 24시간 쿨다운"""
장점: 감정적 재진입 방지, Pump & Dump 피해 최소화
⚠️ 개선 필요 영역
1. 볼륨 확인 부재 (High)
현재 MACD/SMA/ADX만 확인하고 거래량 확인 없음:
# 현재
cross_macd_signal = prev_macd < prev_signal and curr_macd > curr_signal
# 권장: 거래량 동반 확인
volume_surge = curr_volume > sma_volume * 1.5 # 평균 대비 150%
valid_signal = cross_macd_signal and volume_surge
2. 시장 상태 필터 부재 (Medium)
# 권장: 비트코인 방향성 확인
def is_btc_bullish():
btc_data = fetch_ohlcv("KRW-BTC", "1d", 20)
return btc_data["close"].iloc[-1] > btc_data["close"].rolling(20).mean().iloc[-1]
3. 진입 가격 최적화 부재 (Low)
- 현재: 신호 발생 시 시장가/지정가 즉시 매수
- 권장: VWAP 또는 지지선 근처 지정가 대기
4.2 청산 전략 (Exit Strategy) ⭐⭐⭐⭐⭐
✅ 계층적 트레일링 스탑 (Tiered Trailing Stop)
# 구간별 차등 스탑 설정
저수익 구간 (< 10%): 최고점 대비 -5% → 전량 매도
중간 구간 (10~30%): 수익률 10% 이하 복귀 시 전량 매도
또는 최고점 대비 -5% → 전량 매도
고수익 구간 (> 30%): 수익률 30% 이하 복귀 시 전량 매도
또는 최고점 대비 -15% → 전량 매도
분석:
- ✅ 수익 구간별 차등 보호 (전문가 수준)
- ✅ 상승 여력 확보하면서 수익 보호
- ✅ max_price 영구 저장으로 재시작 시에도 유지
✅ 분할 매도 (Partial Profit Taking)
# 10% 달성 시 50% 부분 익절 (1회 제한)
if not partial_sell_done and profit_rate >= 10.0:
return {"status": "stop_loss", "sell_ratio": 0.5, "set_partial_sell_done": True}
분석:
- ✅ 리스크 감소 + 나머지로 큰 수익 추구
- ✅
partial_sell_done플래그로 중복 방지 - ✅ 최소 주문 금액 미만 시 자동 전량 매도 전환
✅ 손절 즉시 실행
# is_stop_loss 플래그로 확인 절차 건너뜀
bypass_confirmation = not confirm_via_file or (final_is_stop_loss and not confirm_stop_loss)
⚠️ 개선 필요 영역
1. ATR 기반 동적 스탑 미적용 (Medium)
# 현재: 고정 퍼센티지
drawdown_1 = 5.0 # 모든 코인에 동일
# 권장: ATR 기반 동적 스탑
def calculate_dynamic_stop(symbol, atr_multiplier=2.0):
atr = ta.atr(df["high"], df["low"], df["close"], length=14).iloc[-1]
current_price = df["close"].iloc[-1]
stop_distance = (atr / current_price) * atr_multiplier * 100
return max(3.0, min(stop_distance, 15.0)) # 3~15% 범위 제한
2. 시간 기반 청산 미적용 (Low)
- 현재: 가격 조건만 확인
- 권장: 장기 횡보 시 기회비용 고려 청산
4.3 리스크 관리 (Risk Management) ⭐⭐⭐⭐
✅ 우수한 점
| 리스크 관리 항목 | 구현 상태 | 평가 |
|---|---|---|
| API 장애 대응 (Circuit Breaker) | ✅ | Excellent |
| KRW 잔고 경쟁 방지 | ✅ | Excellent |
| 부분 매수 지원 | ✅ | Good |
| Rate Limiting | ✅ | Excellent |
| 슬리피지 관리 | ✅ | Good |
| 최소 주문 금액 검증 | ✅ | Excellent |
⚠️ 개선 필요 영역
1. 최대 보유 종목 수 제한 없음 (High)
# 현재: symbols.txt의 모든 심볼 매수 가능
# 문제: 과도한 분산 투자 → 관리 어려움
# 권장: 최대 보유 종목 수 제한
MAX_HOLDINGS = 5
def can_open_new_position(holdings):
return len(holdings) < MAX_HOLDINGS
2. 포트폴리오 손실 한도 부재 (High)
# 권장: 일일/주간 손실 한도 모니터링
def check_portfolio_drawdown(holdings, initial_balance):
current_value = calculate_portfolio_value(holdings)
drawdown = (current_value - initial_balance) / initial_balance * 100
if drawdown <= -20: # 20% 손실 시
logger.error("포트폴리오 손실 한도 도달: %.2f%%", drawdown)
# 신규 매수 차단 또는 전량 청산
3. 심볼별 상관관계 미고려 (Medium)
- 현재: 각 심볼 독립적으로 처리
- 문제: BTC 하락 시 대부분 알트코인 동반 하락
- 권장: 상관관계 높은 종목 그룹화하여 동시 보유 제한
4. 변동성 기반 포지션 사이징 미적용 (Medium)
# 현재: 고정 금액
buy_amount_krw = 50000
# 권장: 변동성 역비례 사이징
def calculate_position_size(symbol, base_amount, max_volatility=5.0):
volatility = calculate_volatility(symbol) # ATR 기반
if volatility > max_volatility:
return base_amount * (max_volatility / volatility)
return base_amount
5. v4 → v5 변경사항 및 신규 발견
🟢 v4 이후 확인된 개선사항
- StateManager 안정화:
max_price영구 저장 안정적 동작 - Stop-Loss 즉시 실행:
is_stop_loss플래그 정상 작동 - KRW 예산 관리: 토큰 기반 독립 할당으로 동시 주문 안전
- 테스트 커버리지 증가: 15개 테스트 파일
🔴 v5에서 새로 발견된 문제
| ID | 심각도 | 문제 | 영향 |
|---|---|---|---|
| CRITICAL-001 | 🔴 Critical | order.py 구문 오류 |
시스템 작동 불가 |
| CRITICAL-002 | 🟡 High | holdings.py 중복 return |
죽은 코드 |
| HIGH-001 | 🟡 High | 광범위한 Exception 처리 | 버그 은폐 가능 |
| HIGH-002 | 🟡 High | 최대 보유 종목 수 제한 없음 | 과도한 분산 |
| HIGH-003 | 🟡 High | 포트폴리오 손실 한도 부재 | 대손 리스크 |
| HIGH-004 | 🟡 High | 볼륨 확인 부재 (매수) | False Signal |
| MEDIUM-001 | 🟠 Medium | Lock 획득 순서 미문서화 | 잠재적 데드락 |
| MEDIUM-002 | 🟠 Medium | 매직 넘버 하드코딩 | 유지보수 어려움 |
| MEDIUM-003 | 🟠 Medium | ATR 동적 스탑 미적용 | 비최적 청산 |
6. 코드 품질 지표 요약
| 항목 | v4 평가 | v5 평가 | 변화 |
|---|---|---|---|
| 아키텍처 설계 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 유지 |
| 타입 안전성 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 유지 |
| 예외 처리 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 유지 (개선 필요) |
| 동시성 안전성 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 유지 |
| 테스트 커버리지 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 유지 (15개 파일) |
| 코드 품질 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⬇️ (구문 오류 발견) |
| 트레이딩 로직 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⬇️ (볼륨 미확인) |
| 리스크 관리 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⬇️ (포트폴리오 관리 부재) |
종합 평가: ⭐⭐⭐⭐ (4.2/5.0) - v4 대비 0.5점 하락 (구문 오류 발견으로 인한 감점)
7. 우선순위별 권장사항
🚨 즉시 수정 (P0 - 24시간 이내)
- CRITICAL-001 수정:
order.py구문 오류 해결 - CRITICAL-002 수정:
holdings.py중복 return 제거
🔴 긴급 개선 (P1 - 1주 이내)
- 최대 보유 종목 수 제한 추가 (
MAX_HOLDINGS = 5) - 포트폴리오 손실 한도 모니터링 추가
- 광범위한 Exception 처리 구체화
🟡 단기 개선 (P2 - 1개월 이내)
- 거래량 확인 로직 추가 (매수 신호)
- ATR 기반 동적 스탑 구현
- Lock 획득 순서 문서화
- 통합 테스트 추가
🟢 중장기 개선 (P3 - 분기 이내)
order.py모듈 분할 (1,289줄 → 3개 파일)- 백테스팅 프레임워크 구축
- 매직 넘버 상수화
- 심볼 상관관계 분석 추가
8. 파일별 상세 분석
핵심 모듈 (Critical Path)
| 파일 | 라인 수 | 역할 | 품질 | 주요 이슈 |
|---|---|---|---|---|
order.py |
1,289 | 주문 실행 | ⚠️ | 구문 오류, 크기 과대 |
signals.py |
960 | 신호 분석 | ✅ | 크기 적정 초과 |
holdings.py |
700 | 보유 관리 | ✅ | 중복 return 문 |
state_manager.py |
106 | 상태 관리 | ✅✅ | 없음 |
common.py |
413 | 공통 유틸 | ✅✅ | 없음 |
config.py |
328 | 설정 관리 | ✅✅ | 없음 |
보조 모듈
| 파일 | 라인 수 | 역할 | 품질 |
|---|---|---|---|
indicators.py |
172 | 기술 지표 | ✅✅ |
notifications.py |
183 | 알림 전송 | ✅ |
circuit_breaker.py |
79 | 장애 복구 | ✅✅ |
retry_utils.py |
62 | 재시도 유틸 | ✅✅ |
constants.py |
60 | 상수 정의 | ✅✅ |
threading_utils.py |
207 | 스레드 유틸 | ✅ |
metrics.py |
30 | 메트릭 수집 | ⚠️ (미사용) |
main.py |
388 | 엔트리포인트 | ✅ |
9. 결론
✅ 강점
- 아키텍처: 모듈화, 단일 책임 원칙, 상태 분리 우수
- 동시성: RLock, 토큰 기반 예산 관리, Rate Limiter 완비
- 정밀도: Decimal 기반 계산, 원자적 파일 쓰기
- 복구력: Circuit Breaker, 지수 백오프, ReadTimeout 복구
⚠️ 개선 필요
- 긴급: 구문 오류 수정 필수 (시스템 작동 불가)
- 리스크 관리: 포트폴리오 레벨 관리 부재
- 트레이딩: 거래량 확인 및 동적 스탑 미적용
- 코드 품질: 광범위한 Exception, 모듈 크기 과대
🎯 최종 권장사항
- 즉시: CRITICAL-001/002 수정 후 재배포
- 1주 내: 최대 보유 종목 및 손실 한도 추가
- 1개월 내: 거래량 확인 및 통합 테스트 추가
- 장기: 백테스팅으로 전략 검증 후 파라미터 최적화
보고서 작성일: 2025-12-10 작성자: AI Code Reviewer (Python Expert + Crypto Trader Perspective) 버전: v5.0