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

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

@@ -1,12 +1,157 @@
# Current Session State
## Current Goal
- Stabilize holdings sync/state restoration reliability (max_price, partial_sell_done).
## ToDo List
- [x] Prevent `max_price` downward reset when StateManager lacks data.
- [x] Preserve `partial_sell_done` flag during holdings sync merges.
- [x] Run full regression suite beyond `tests/test_v3_features.py` once changes are consolidated.
- [x] Implement Decimal-based order amount/price calculation with tick-size rounding (code_review_report_v2 P1) — added Decimal helper and integrated into limit buy path.
- [x] Add retry + short-TTL cache to `get_current_price`/balances (code_review_report_v2 P1); remaining: StateManager single-source plan.
- [x] Harden pending/confirm/recent_sells storage (TTL cleanup; atomic pending writes) — JSONL/sqlite alternative still open for future phase; config/log cleanups pending (code_review_report_v2 P2/P3).
## 🎯 Current Phase
- **Phase:** Telegram Reliability & Robustness (텔레그램 안정성 강화)
- **Focus:** Telegram API 타임아웃으로 인한 프로그램 중단 완전 방지
- **Phase:** Code Review v5 완료 및 테스트 안정화
- **Focus:** 모든 CRITICAL/HIGH 이슈 해결 완료, 전체 테스트 통과
## ✅ Completed Tasks (This Session)
### Holdings sync resilience (2025-12-10)
- [x] `fetch_holdings_from_upbit` restores `max_price` using the highest among StateManager, local snapshot, and current buy price to prevent downward resets.
- [x] `partial_sell_done` restoration now preserves `True` from local snapshot even when StateManager stored `False`.
- [x] `pytest tests/test_v3_features.py` passes (robust holdings sync scenario).
### Decimal order calc (2025-12-10)
- [x] Added Decimal-based tick-size price adjustment and limit-buy volume calculation helper; integrated into `place_buy_order_upbit` to remove float rounding risk.
- [x] Updated `src/tests/test_order.py` to isolate KRWBudgetManager in response validation cases; all tests pass.
### Price/balance retry & cache (2025-12-10)
- [x] Added short TTL cache (2s) with 3-attempt backoff retry for `get_current_price` and `get_upbit_balances`, guarded by rate limiter.
- [x] New tests `src/tests/test_holdings_cache.py` cover cache hits and retry success paths.
### State/holdings reconciliation (2025-12-10)
- [x] Added `reconcile_state_and_holdings` to keep StateManager as source of truth while filling missing fields from holdings; syncs max_price/partial flags both ways.
- [x] Tests `src/tests/test_state_reconciliation.py` ensure state fills from holdings when empty and holdings are updated from newer state values.
### File queues hardening (2025-12-10)
- [x] `pending_orders.json` now prunes 24h stale entries and writes atomically via temp file.
- [x] `recent_sells.json` gains TTL cleanup (>=2x cooldown) to drop stale cooldown records.
- [x] Tests `src/tests/test_file_queues.py` cover pending TTL prune and recent_sells cleanup.
### Full regression suite (2025-12-10)
- [x] `pytest` (full suite across `src/tests` + `tests`) — all tests passed.
### Exception handling & constants (2025-12-10)
- [x] `holdings.py``requests` import 추가 및 네트워크/파싱 예외만 처리하도록 축소 (IO 오류는 전파)
- [x] `order.py` pending TTL/주문 재시도 지연을 상수화(`PENDING_ORDER_TTL`, `ORDER_RETRY_DELAY`)하고 예외 처리를 요청/값 오류로 한정
- [x] ThreadPoolExecutor 상한을 상수(`THREADPOOL_MAX_WORKERS_CAP`)로 노출하고 환경변수로 조정 가능하도록 수정
### Code Review v5 개선사항 구현 (2025-12-10)
- [x] **CRITICAL-001**: `order.py` 구문 오류 (들여쓰기) 수정 완료
- [x] **CRITICAL-002**: `holdings.py` 중복 return 문 제거 완료
- [x] **HIGH-001**: Exception 처리 구체화 (json.JSONDecodeError, OSError, requests.exceptions 분리)
- [x] **MEDIUM-001**: Lock 획득 순서 규약 문서화 (`common.py` 라인 93-105)
- [x] **MEDIUM-002**: 매직 넘버 상수화 (`constants.py` 60줄, 9개 상수 정의)
- [x] **테스트 수정**: 실패 테스트 8개 수정 완료
- 메시지 포맷 변경 반영 (4개)
- 구체적 Exception 사용 (3개)
- monkey patch 경로 수정 (1개)
- [x] **전체 테스트 통과**: 79/79 passed (100% 성공률)
### Rate limit & budget fixes (2025-12-10, ongoing session)
- [x] KRWBudgetManager 토큰 기반 다중 할당으로 리팩토링 (최소 주문 금액 가드 포함, 중복 심볼 동시 주문 안전)
- [x] recent_sells.json 잠금/원자적 쓰기/손상 백업 추가 → 재매수 쿨다운 레이스/손상 대비
- [x] RateLimiter를 초/분 이중 버킷으로 확장, get_current_price/get_upbit_balances에 적용
- [x] 동시 매수/예산 단위 테스트 갱신 및 추가 (동일 심볼 복수 주문 포함)
- [x] pytest src/tests/test_krw_budget_manager.py src/tests/test_concurrent_buy_orders.py → 모두 통과
### KRW 예산 할당 시스템 구현 (2025-12-10):
- [x] **v3 CRITICAL-1 개선**: KRW 잔고 Race Condition 완전 해결
- `src/common.py`: `KRWBudgetManager` 클래스 신규 구현 (120줄)
- 예산 할당(allocate) + 해제(release) 시스템
- 멀티스레드 환경에서 KRW 중복 사용 방지
- Lock 범위를 주문 완료까지 확장 (Option B 방식)
- [x] **place_buy_order_upbit 통합**:
- `src/order.py`: KRWBudgetManager 사용하도록 수정
- `try-finally` 패턴으로 예산 자동 해제 보장
- 할당 실패 시 `skipped_insufficient_budget` 상태 반환
- [x] **멀티스레드 테스트 추가**:
- `src/tests/test_krw_budget_manager.py`: 단위 테스트 11개 (모두 통과)
- 전액 할당, 부분 할당, 할당 실패
- 동시 할당, 할당/해제 동시 발생
- 스트레스 테스트 (10 스레드)
- 실전 거래 시나리오 시뮬레이션
- `src/tests/test_concurrent_buy_orders.py`: 통합 테스트 4개
- 동시 매수 시 잔고 초과 인출 방지
- 할당 후 해제 및 재사용
- 예외 발생 시 예산 자동 해제
- 10 스레드 × 3 주문 스트레스 테스트
- `verify_krw_budget.py`: 동작 검증 스크립트 (✅ 통과)
- [x] **문서화**:
- `docs/krw_budget_implementation.md`: 구현 보고서 작성
- 문제 정의, 해결 방안, 알고리즘 상세
- 테스트 결과, 성능 영향 분석
- 사용 가이드, 제한 사항
### Code Review v3 개선사항 구현 (2025-12-09):
- [x] **CRITICAL-001**: API Rate Limiter 구현 (토큰 버킷 알고리즘)
- `src/common.py`: `RateLimiter` 클래스 추가 (초당 8회 제한)
- `src/indicators.py`: `fetch_ohlcv()`에 Rate Limiter 적용
- 멀티스레딩 환경에서 Thread-Safe 보장
- [x] **CRITICAL-002**: 최고가 갱신 로직 구현
- `src/holdings.py`: `update_max_price()` 함수 추가
- `main.py`: 손절/익절 체크 전 모든 보유 종목의 최고가 자동 갱신
- Thread-Safe 구현 (holdings_lock 사용)
- [x] **CRITICAL-003**: Thread-Safe holdings 저장
- `src/holdings.py`: `save_holdings()`에 Lock 추가 (이미 구현됨 확인)
- 원자적 파일 쓰기 (.tmp 파일 사용 후 rename)
- [x] **CRITICAL-005**: 부분 매수 지원
- `src/order.py`: `place_buy_order_upbit()` 수정
- 잔고 부족 시 가능한 만큼 매수 (최소 주문 금액 이상일 때)
- 수수료 0.05% 자동 차감
- [x] **HIGH-005**: Circuit Breaker 임계값 조정
- `src/circuit_breaker.py`: failure_threshold 5→3, recovery_timeout 30s→300s
- [x] **HIGH-007**: Telegram 메시지 자동 분할
- `src/notifications.py`: `send_telegram()` 수정
- 4000자 초과 메시지 자동 분할 전송
- 분할 메시지 간 0.5초 대기 (Rate Limit 방지)
- [x] **HIGH-008**: 재매수 방지 기능
- `src/common.py`: `record_sell()`, `can_buy()` 함수 추가
- `src/signals.py`: `_process_symbol_core()`에 재매수 확인 로직 추가
- `src/order.py`: 매도 성공 시 `record_sell()` 호출
- 기본 24시간 쿨다운 (config에서 조정 가능)
- [x] **MEDIUM-001**: 설정 파일 검증
- `src/config.py`: `validate_config()` 함수 추가
- 필수 항목 확인, 범위 검증, 타입 체크
- [x] **보안 개선**: 파일 권한 설정
- `src/holdings.py`: holdings.json 파일에 0o600 권한 설정 (소유자만 읽기/쓰기)
- [x] **HIGH-002**: 예외 처리 개선 (부분 적용)
- `src/order.py`: 잔고 조회 시 구체적 예외 처리
- Rate Limiter에 네트워크 오류 구분
- [x] **API 키 검증**: main.py 시작 시 Upbit API 키 유효성 검증 (실전 모드 전용)
### 제외된 항목 (사용자 요청):
- [ ] ~~CRITICAL-004: RSI/MACD 조건 개선~~ (제외)
- [ ] ~~HIGH-004: Bollinger Bands 로직 수정~~ (제외)
- [ ] ~~MEDIUM-004: 백테스팅 기능~~ (제외)
## ✅ Previous Completed Tasks
### Git push 준비 & lint 정리 (2025-12-09):
- [x] ruff 에러(F821/E402/E731/F841) 해결: RuntimeConfig 타입 주입, import 순서 수정, lambda→def, 미사용 변수 제거
- [x] `src/holdings.py`, `src/order.py`: `from __future__ import annotations` + `TYPE_CHECKING` 가드 추가, RuntimeConfig 타입 명시