## 배경
"전략이 혼란스럽고 현재와 맞지 않는다"를 조사한 결과, 전략 설계가 아니라
전략을 검증했다는 도구와 파라미터 소스가 어긋나 있었다.
## 파라미터 소스 단일화
- 우선순위가 adaptive > strategy_cfg(DB) > config.py 인데 문서는 맨 마지막인
config.py 를 기술하고 있었다. 11곳이 불일치(BULL RSI 46 vs DB 30, SL -7% vs -6%).
- DEFAULT_PARAMS 를 config.py 에 정합 + alembic 0012 로 기존 DB 행 갱신
(운영자가 UI 로 바꾼 값은 보존, 옛 기본값과 같은 행만 갱신, 테이블 가드·멱등)
## 백테스트를 실전 로직에 정합
- calculate_adx_simple 이 정확히 period 배(14.0×) 발산 → Aggressive 게이트
`ADX>25` 가 전 레짐 100% 통과. 전환 빈도 5.6%→2.0%(-65%), 성과 상방 편향
- 백테스트 RSI 는 SMA, 실전은 Wilder → 진입 판정 10~11% 불일치
- us_backtest_engine RSI 1봉 지연 제거 (룩어헤드 없음을 절단 테스트로 증명)
- backend/backtest_results/ 25건은 폐기 대상 (§8.4)
## 리스크 가드 복원
- 4% 절대 상한이 try 블록 안에 있어 예외 시 적응형 6~7% 가 통과 → try 밖으로
- 청산을 매수보다 먼저 평가 (보유 종목이 추천에 들면 손절 대신 물타기가 나갔다)
- 리스크 가드 4개를 매수 전용화 → MDD -10%·보유한도 도달 시에도 손절 작동
- MDD 갱신 5회 연속 실패 시 신규 진입 차단 fail-safe (청산은 계속 허용)
- 스윙 청산이 DT 보유분까지 매도하던 문제, sell_pct 기준 혼재 정정
## 죽은 코드 제거 (2,695줄)
- short_term_strategy, kosdaq_scanner, app/strategy/ 패키지
- app/trading/ + korea_investment_api_adapter (real_market_api 정본은
korea_investment_api.py:1482, adapter 는 import 0건)
## 지표·사이징 단일화 (수치 무변경 증명)
- indicators_core.py: 3,274건 비교 최대 오차 0.000e+00
- sizing_core.py: 42,105건 비교 불일치 0
- 미국 전략 상수 13개 config 편입 (hex 까지 동일, 3,168 케이스 전수 비교)
## 테스트 안전 (실 KIS 호출 차단)
- 유닛 테스트가 실제 KIS 에 매도 주문을 2회 전송하고 있었다. 리팩터링이
close_stale_positions 의 대상을 _execute_exit → _execute_exit_stale 로
바꿨는데 목이 전자에 걸려 빗나갔다. test_api_endpoints 도 캡처된 싱글톤
참조 누수로 실제 잔고 조회를 타 141초를 소비했다.
- backend/tests/conftest.py 신설: 주문·토큰·시세·잔고를 호출 즉시 예외로 차단.
예외는 BaseException 파생(프로덕션 except Exception 폴백에 삼켜지지 않게),
클래스 메서드에 적용(캡처된 참조까지 덮음), DATABASE_URL `_test` 가드 강제
- 전체 유닛 스위트: 365초/6 failed → 11.8초/0 failed (소켓 차단 하 559 passed)
## 신규 (둘 다 플래그 OFF, 백테스트 미검증)
- range_trading_strategy.py — SIDEWAYS 담당 전략이 없던 빈 칸. 미배선
- check_bear_buy_signal_v2 — BEAR 4중 AND(발화율 2.3%) → 점수제(12.4%)
## 문서
- CLAUDE.md 를 실제 코드 기준으로 재작성. §0 파라미터 우선순위, §4.1 테스트 규약,
§6.4 문서화되지 않았던 진입 차단 게이트 9종, §8.4 백테스트 폐기 근거,
§8.5 미해결 19항목
- 루트 md 6개 → 2개(docs/ 이동), 중복 배치 문서 병합, 스테일 worktree 제거
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
다른 인스턴스/증권사 앱에서 매수돼 동기화로 들어온 포지션은 ActiveTrade 행이 없어
손절·분할익절·트레일링 관리를 전혀 받지 못했다(2026-09-22 카카오뱅크가 -13%까지
방치되다 청산). 동기화 시 보유 중인데 active 행이 없으면 평균단가를 진입가로 등록하고
손절가를 STOP_LOSS_PERCENT 기준으로 설정한다. 데이트레이딩 태깅 종목은 제외
(DT 엔진이 당일 청산 대상으로 복원해버리므로).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
수동/분할 매도 누락으로 ActiveTrade 잔량이 실제 보유량과 어긋나면 다음 청산이
보유량보다 많이 매도한다. 동기화 시 종목당 active 행이 1개뿐일 때 실제 보유량으로
교정하고, 보유가 없으면 closed 처리(스윙+DT 혼재 종목은 자동 교정 제외).
운영 교정용으로 PATCH /portfolio/active-trades/{code}/status 에 quantity 필드 추가.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DT에서 찾은 '분할매도 후 ActiveTrade.quantity 미갱신' 패턴이 3곳 더 있었음:
- us_market_scheduler: total_qty = trade.quantity 를 매도량 산정에 직접 사용 →
분할매도 후 다음 사이클이 원래 수량 기준으로 팔아 과다매도(US_TRADING_ENABLED=true 상태)
- swing/exit_service, trade_executor._execute_sell: remaining_pct만 갱신
또한 수동 매도(/portfolio/sell)가 ActiveTrade를 전혀 정리하지 않아 청산된 종목이 active로
잔존(삼아알미늄·LG 등) → 재매수 시 옛 remaining_pct가 살아나 1차 익절이 건너뛰어짐.
전량 매도 시 close, 분할 시 잔량 갱신으로 수정.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1) DT 분할매도가 ActiveTrade.quantity를 갱신하지 않아 재기동 복원 시 원래 수량이 되살아남
→ 잔량 4주인데 7주 매도되어 같은 종목 스윙 보유분 3주까지 청산됨(2026-09-23 LG씨엔에스).
2) reflect_sell이 '전략 포지션 잔량'을 Portfolio 행 잔량으로 사용 → DT 전량청산이 스윙
보유분까지 0으로 만듦. 행 잔량은 항상 (행 수량 - 매도 수량)으로 계산.
3) LSTM 체크포인트에 numpy 배열이 들어가 weights_only=True 로드가 매번 실패 → 앙상블에서
LSTM이 조용히 빠진 채 예측 중이었음. 저장을 list로 바꾸고, 기존 파일은 MODEL_DIR 내부일
때만 완화 재시도.
4) 수동 매도(행 삭제)와 sync 동시 실행 시 StaleDataError로 sync 전체 실패 → 전량 매도는
행 삭제 대신 수량 0, sync는 충돌 시 실패 기록 없이 다음 주기 재시도.
추가로 비강제 sync는 락 점유 중이면 30초 대기 없이 캐시 반환.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>