Commit Graph

5 Commits

Author SHA1 Message Date
b5e0d6a9bb fix: 매매일지 표시·중복·스케줄러 중단 + 전략 파라미터 자동적용 차단
매매일지는 정상 생성되고 있었다(205건, 커버리지 100%, 16:00 자동 생성도 동작).
"작성이 안 된다"의 실체는 아래 표시 계층 문제였다.

## 표시
- Dashboard journals 쿼리가 staleTime:Infinity + refetchInterval 없음이라
  페이지 로드 순간의 목록에서 영구 고정됐다 → 30s/60s 폴링
- WS journal_created 는 205건 중 13건(6%)만 발화하고(16:00 스케줄러와
  /analysis/generate-journals 는 브로드캐스트 없음) 그마저 커밋 전에 나간다
  → 이벤트 의존 제거, 수신 시 즉시+3초 재invalidate 로 레이스 보강
- 수동 버튼이 목록을 갱신하지 않고 안내가 "매매 로그"(없는 위치)를 가리켰다
  → invalidateQueries + 실제 위치·비동기 지연 명시

## 시각 +9h
- journals 가 KST naive 값에 UTC 라벨을 붙여 화면이 +9h 밀렸다
  (실측 KST 15:48 → 화면 09-30 00:48, 즉 당일 16:00 일지가 "다음날 01:00")
- _utc_iso → _kst_iso, +09:00 명시. 세 응답 지점 통일(기존엔 목록/상세가 달랐다)
- /trades 는 raw naive + 프론트 보정으로 짝이 맞아 있어 건드리지 않았다
  (회귀 테스트가 trades.py 에 +09:00 유입을 차단)
- JournalPanel 에 조건부 +09:00 정규화 추가(매매내역 경로와 동일 패턴)

## now_kst 섀도잉 4곳
- from timeutil import now_kst 해놓고 함수 내 now_kst = _dt.now(_KST) 로 대입해
  같은 함수의 now_kst() 가 TypeError. post_market 에서 실장애였고 나머지 3곳은
  무증상 잠재 → 전부 _now 로 리네임 (AST 전수, backend+mcp-server 잔존 0)
- TypeError 를 은폐하던 logger.debug → warning(exc_info=True), except: pass 1곳도

## trade_id=0 중복
- db_worker 에 _handle_insert_trade_journal 신설 — order_id 로 TradeHistory.id
  해소, 해소 실패 시 None(0 아님). 정상경로·종료 drain 공용
- 커버 판정 trade_id > 0 (id 는 PK라 0 은 애초에 아무 행도 커버하지 않음)
- order_id 추출이 raw KIS 응답에 없는 top-level "odno" 였다 → output.ODNO 우선

## 전략 파라미터 자동 적용 차단 (STRATEGY_AUTO_APPLY_ENABLED=False)
섀도잉 수정이 post_market 의 자동 최적화를 부활시킨다 — run_optimization 이
strategy_cfg.upsert() 로 실매매 파라미터(RSI 진입·손절·포지션 크기)를 덮어쓴다.
게이트가 "최근 7일 SELL>=5건"이라 5거래 표본 그리드 서치가 alembic 0012 로
정합시킨 값을 조용히 바꿀 수 있다 — §8.1-5·§8.4·§8.5-1 과 정면 충돌.
- 계산·분석·로그는 유지하고 upsert 만 차단. 가드 2단, 둘 다 try 밖
- 차단 시 키별 현재값→제안값 + IS/OOS Sharpe 를 warning + apply_reason 에 기록
- 켜기 전 §8.4 백테스트 요건 충족 필요(config 주석에 명시)

## 부수 발견
strategy_config_service.upsert 가 __import__("datetime").now_kst() 로 항상
AttributeError → 전략 파라미터 저장이 UI·일괄·optimizer 전 경로에서 500이었다.
역설적으로 이것이 자동적용의 2차 방어선이었다 — 고쳤으므로 플래그가 필수다.
⚠️ 배포 후 UI 파라미터 저장이 처음으로 실제 동작한다(§0 정합 주의).

테스트 677 → 715 passed / 0 failed. 전략 임계값 정적 변경 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-29 17:37:48 +09:00
1b9257c4d2 fix: 매매 파라미터 3중 소스 정합 + 리스크 가드 복원 + 죽은 코드 2,695줄 제거
## 배경
"전략이 혼란스럽고 현재와 맞지 않는다"를 조사한 결과, 전략 설계가 아니라
전략을 검증했다는 도구와 파라미터 소스가 어긋나 있었다.

## 파라미터 소스 단일화
- 우선순위가 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>
2026-09-28 08:58:18 +09:00
ec2fa2b423 fix: DB 타임스탬프 KST 통일 + KIS 토큰 캐시 영속화
시간대 혼재: 모델 기본값은 datetime.utcnow(UTC), 수동 매매 등 일부 경로는 _get_kst_now(KST)로
저장해 같은 테이블에 9시간 차가 섞였다(화면 매매시각 02:14 등). 조회 구간(utcnow - days)도
KST 저장분과 비교돼 어긋났고, 추가매수 쿨다운은 (UTC now - KST created_at)이 음수라 상시
발동했다. app.core.timeutil.now_kst() 도입 후 모델 기본값 27곳과 app/ 전역 utcnow() 호출을
모두 KST 기준으로 통일(잔존 0건, 테스트로 고정).

KIS 토큰 캐시(~/.cache/auto-stock)가 컨테이너에만 있어 배포마다 사라지고 토큰을 새로
발급받다 KIS가 EGW00103(유효하지 않은 AppKey)로 거부 → 502·잔고 0 유발. 볼륨 마운트로
재배포 후에도 재사용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 11:24:14 +09:00
c818810667 수정본
Some checks failed
CI/CD Pipeline / test-backend (push) Has been cancelled
CI/CD Pipeline / test-frontend (push) Has been cancelled
CI/CD Pipeline / build-and-push (push) Has been cancelled
2026-03-27 14:47:49 +09:00
2baf06a5fd feat: 매매일지 자동 생성 + 전략 자동 최적화 시스템 추가
- trade_analyzer.py: 거래 성과 분석(승률/손익비/전략별 패턴), 템플릿 기반 일지 자동 생성
- strategy_optimizer.py: 그리드 서치 기반 파라미터 최적화, Sharpe 10% 개선 시 자동 적용
- analysis.py: /performance /insights /generate-journals /optimize-strategy /optimization-history 엔드포인트
- journals.py: POST /generate/{trade_id}, GET /stats 엔드포인트 추가
- models.py: StrategyOptimizationLog 테이블 추가
- main.py: post_market_analyzer_scheduler (16:00 KST 자동 실행)
- frontend: Analysis 페이지 추가 (성과 요약/인사이트/일지 생성/최적화 이력)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 09:28:10 +09:00