Commit Graph

16 Commits

Author SHA1 Message Date
6207d13487 feat: 외부 유입 포지션 ActiveTrade 자동 등록 — 손절·분할익절 관리 편입
다른 인스턴스/증권사 앱에서 매수돼 동기화로 들어온 포지션은 ActiveTrade 행이 없어
손절·분할익절·트레일링 관리를 전혀 받지 못했다(2026-09-22 카카오뱅크가 -13%까지
방치되다 청산). 동기화 시 보유 중인데 active 행이 없으면 평균단가를 진입가로 등록하고
손절가를 STOP_LOSS_PERCENT 기준으로 설정한다. 데이트레이딩 태깅 종목은 제외
(DT 엔진이 당일 청산 대상으로 복원해버리므로).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 10:42:40 +09:00
ee4f8afa8b fix: ActiveTrade 잔량 자동 정합 + PATCH 수량 교정 지원
수동/분할 매도 누락으로 ActiveTrade 잔량이 실제 보유량과 어긋나면 다음 청산이
보유량보다 많이 매도한다. 동기화 시 종목당 active 행이 1개뿐일 때 실제 보유량으로
교정하고, 보유가 없으면 closed 처리(스윙+DT 혼재 종목은 자동 교정 제외).
운영 교정용으로 PATCH /portfolio/active-trades/{code}/status 에 quantity 필드 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 10:38:24 +09:00
b933e23777 fix: 분할매도 잔량 미갱신 — 스윙·국내 executor·미국 경로 동일 패턴 + 수동매도 ActiveTrade 정리
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>
2026-09-23 10:36:00 +09:00
f32bf412f3 fix: 로그 분석으로 찾은 버그 4건 (과다매도·수량 0 오염·LSTM 무력화·sync 충돌)
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>
2026-09-23 10:24:45 +09:00
d8550a2241 fix: 스케줄러 단계별 타임아웃 — KIS 무응답 시 EOD 청산 누락 방지
로그 분석(2026-09-22): 15:03:46 진입 스캔 이후 데이트레이딩 스케줄러가 16:52 재배포까지
1시간 49분간 아무 로그도 남기지 않음 = KIS API 무응답(500/Server disconnected 연속)으로
await가 반환되지 않아 루프 정지 → 15:20 EOD 강제청산 미실행 → 포지션 익일 보유.
- _guard(): 각 단계를 asyncio.wait_for로 감싸 초과 시 취소 후 다음 사이클 진행
- 단계별 상한: MDD 30s / watchlist 120s / ORB·EOD청산 300s / 청산·진입 180s
- MDD 판단 불가 시 보수적으로 신규 진입 차단
- 테스트 3건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 10:18:00 +09:00
a659de09e3 feat: 전일 미청산 데이트레이딩 포지션 즉시 청산 안전장치
15:20 EOD 강제청산이 누락/실패하면 포지션이 하룻밤 갭 리스크에 노출된 채 다음 날
일반 청산 로직을 탄다(2026-09-22 LG씨엔에스 7주 → 익일 09:30 분할매도).
- exit_service.close_stale_positions(): 진입일이 오늘이 아닌 포지션을 장중 시장가 전량 청산,
  현재가 조회 실패 시 진입가 폴백, 실패 시 다음 30초 사이클에서 재시도
- 청산 사이클(check_and_exit_positions) 및 스케줄러 기동 직후 양쪽에서 호출
- 테스트 5건, CLAUDE.md §7.3 반영

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 10:01:00 +09:00
fd8a0f1188 fix: 데이트레이딩 보유 종목이 화면에 안 보이던 문제 — 엔진 포지션 직접 표시
Portfolio 테이블은 stock_code가 unique라 같은 종목을 스윙+데이트레이딩으로 동시 보유하면
한 행에 합쳐지고 strategy_type도 하나만 남는다(LG씨엔에스 스윙 8 + DT 4 = 12주 'swing').
- 프론트: /daytrading/positions(엔진 인메모리)를 직접 조회해 '데이트레이딩' 그룹으로 표시하고,
  스윙 행에서는 그 수량을 차감
- 백엔드 동기화: 전량이 DT 포지션일 때만 'daytrading' 태깅 (부분 혼재 시 스윙 청산 대상 유지)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 09:33:14 +09:00
9fd02932fa fix: 개장 시 추천 종목 지연 — 배치 분석 개장 전 선행 실행 + 스케줄러 개장 전 기상
모든 스케줄러가 장 마감 중 고정 1800초를 자서 09:00 개장을 최대 30분 건너뛰었고,
배치 분석은 개장 후에야 시작돼 추천 종목이 09:00에 비어 있었음.
- market_schedule.is_pre_market_window() 추가 (08:30~09:00, 거래일만)
- batch_analysis_scheduler: 개장 전 준비 구간에도 분석 실행 → stock_analysis·Redis 추천
  캐시를 미리 채워 09:00에 추천 즉시 표시
- batch/auto_trade/swing 스케줄러: 마감 중 sleep = min(1800, 개장까지 남은 시간)
- 테스트 1건 추가 (총 5건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 09:07:57 +09:00
546cf17edb fix: 장 마감 중 30분 sleep이 09:00 개장을 건너뛰어 ORB 수집 누락
데이트레이딩 스케줄러는 장 마감 시 무조건 1800초를 자서, 08:31~09:00 사이에 잠들면
09:01~09:30에 깨어나 ORB 수집 구간(09:00~09:30)을 통째로 놓쳤음(2026-09-23 감시종목 0 확인).
- market_schedule.seconds_until_market_open() 추가 (주말·공휴일 건너뜀)
- 스케줄러: 마감 중 sleep = min(1800, 개장까지 남은 시간), 개장 3분 전 watchlist 선구성
- 회귀 테스트 4건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 09:05:36 +09:00
a57c720559 feat: 데이트레이딩 포지션 화면 표시 + 모든 매도 즉시 화면 반영
- portfolio_cache_bridge 신설: 매매 엔진 체결 시 Portfolio(db_worker 큐) + 인메모리 캐시 즉시 갱신.
  DT 매수는 strategy_type='daytrading'으로 태깅되어 보유 종목 패널의 '데이트레이딩' 그룹에 표시되고
  스윙 청산 로직(strategy_type='swing' 대상)에서 제외됨. (기존엔 KIS 동기화로 'swing'으로 유입돼
  DT 포지션이 안 보이고 스윙 엔진이 같이 관리하는 문제)
- DT 매도·스윙 자동 매도도 캐시에서 즉시 제거/차감 + 최근매도 기록(동기화 되살림 방지).
- 동기화 시 DT 엔진 보유 종목은 'daytrading'으로 태깅.
- 프론트: 수동 매도 성공 시 낙관적 갱신으로 서버 재조회 전 즉시 목록에서 제거.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 16:49:46 +09:00
e0178aaf0d feat: 데이트레이딩 ORB 복구 + 스윙:DT 자본 50:50 + 시간대 제한 완화
- ORB: 09:00에 당일 분석이 없으면 최근 분석일 결과로 watchlist 선채움 → ORB 수집 가능.
  자동 목록은 30분마다 갱신(당일 분석 완료 시 교체), 수동 설정 목록은 덮어쓰지 않음.
- 자본 배분: DAY_TRADE_MAX_RATIO_DT 0.25→0.50, 종목당 4%→6%, 동시 3→8종목.
  SWING_MAX_CAPITAL_RATIO=0.50 신설 — 스윙 합산 투자액 초과 시 스윙 신규 매수 차단(trade_executor).
- 시간대: 점심(11:30~13:00) VWAP/RSI_BB 제한 제거, 하드코딩 14:30 마감 → 설정값 15:00.
- 회귀 테스트 3건, CLAUDE.md §6/§7.3/§8.2 갱신.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 13:29:02 +09:00
8ecedf65a8 fix: 스윙 부분매도 중복 실행 — ActiveTrade 미존재 포지션 처리
동기화로 유입된 포지션(ActiveTrade 행 없음)에 1차 익절(50%)이 매 사이클
반복 실행돼 전량 청산되는 문제 수정 (2026-09-22 두산에너빌리티 18→9→0주).

- exit_service: 부분매도 시 ActiveTrade 없으면 필수 키 포함해 생성, Portfolio 잔량 즉시 감소
- db_worker: 필수 키 없는 ActiveTrade 신규 upsert는 재시도 대신 경고 후 스킵
- portfolio.py sync 청산 경로 동일 수정
- 회귀 테스트 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 10:32:14 +09:00
b4a1fc79ab feat: 멀티테넌트 1단계 — 사용자별 KIS 계좌·포트폴리오·수동매매 (MULTI_TENANT_ENABLED 기본 OFF)
설계: docs/multi_tenant_design.md / 검수: docs/multi_tenant_phase1_review.md (High 0, MT=False 배포 가능)

데이터·인프라
- user_kis_credentials(Fernet 암호화, PBKDF2 키 파생, key_version), stock_bans_v2 신설,
  portfolio/trade_history/active_trades/trade_journals/trading_sessions 등 user_id nullable 추가
- alembic 0009~0011(idempotent, legacy owner 백필). main.py 기동 시 portfolio.user_id 스키마 검사(H1)
- Jenkinsfile: DB Migration 을 Deploy 앞으로, alembic 이력 없으면 stamp 0008 후 upgrade(N1)
- bootstrap: users 비어 있으면 BOOTSTRAP_ADMIN_* 로 관리자 시드 + .env KIS 자격증명 이관 + 백필(SAVEPOINT)

백엔드
- core/crypto.py, core/tenant_auth.py(get_current_user — 비활성 사용자 401, API 키→legacy owner,
  deny_non_owner_session_when_mt), core/dt_utils.py
- services/tenant: context, kis_pool, registry(UserContextRegistry, 락 최소화·복호화 to_thread), risk_factory
- KoreaInvestmentAPI.for_user(사용자별 인스턴스, 토큰캐시 users/{id}/, 시세는 공용 위임)
- trade_executor.safe_place_order_v2(사용자별 락/세마포어, legacy ctx 는 기존 키)
- mdd_manager/loss_tracker _v2 + ban_until tz-aware/naive 경계 정규화(레거시 경로 버그 포함 수정)
- db_worker: payload user_id 옵션 필터, upsert_stock_ban_v2, legacy ActiveTrade 조회 LIMIT 1
- API: /account/credentials(등록·마스킹조회·삭제·연결테스트·자동매매), /auth/admin/tenant/*,
  /portfolio/v2(조회·요약·sync·buy·sell), /trades/v2(+pending). PortfolioResponse Optional 수정

프론트
- /account 내 계좌 설정, useTenantMode(세션=v2 / API키=legacy, 미확정 시 쿼리·버튼 비활성),
  계좌 미등록 인라인 안내, v2 매수/매도/거래이력 분기

테스트: tests/integration(격리 Postgres, KIS 전면 mock) 20 passed / 1 xfailed(0012 이전 제약)
2단계(스케줄러 사용자화·legacy 라우터 격리) 전까지 MULTI_TENANT_ENABLED=True 전환 금지

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 10:26:51 +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
de7921d270 fix: CRITICAL/HIGH 버그 30건 수정 + 전체 코드 주석 추가 + 중복 정리
## CRITICAL 수정 (20건)
- day_trading: global 선언 누락, loss_tracker 연동, ban 체크 추가
- trade_executor: BUY 체결가 order_price로 수정, remaining_pct 누적 계산
- risk_validator: get_current_price dict 파싱, MAX_POSITION_SIZE 동기화, DB 세션 누수
- risk_management/recommendations: date.today() → KST 변환
- mdd_manager: Lock 밖 executed_key 참조 수정
- correlation_filter: output → output2 키 수정
- portfolio: 해외 종목 USD/KRW 환율 적용 분리
- Sharpe Ratio 거래빈도 기반 연간화
- telegram_notifier: send_message() 공개 래퍼 추가
- position_manager: 앱 재시작 시 DB 포지션 복원
- swing exit_service: remaining_pct 조건 범위 수정
- run_backtest: original_qty 기반 remaining_pct 계산
- us_market_schedule: 2027년 미국 공휴일 추가
- Login.tsx: res.ok 검증 추가
- mean_reversion_strategy: RSI 로그 하드코딩 수정

## HIGH 수정 (10건)
- db_worker: DLQ 파일 백업 메커니즘 추가
- korea_investment_api: 만료 토큰 임의 연장 제거
- market_data: chart_cache 최대 100개 + TTL 만료
- main.py: rate_limit_store 1시간 미접근 IP 정리
- recommendations: fire-and-forget try/except 추가
- swing/scheduler: DB 세션 3개 분리
- Dashboard: wsMessages 전체 순회
- Layout: /health 엔드포인트 + 30초 폴링
- ml_ensemble: POST /train require_api_key 추가
- day_trading: record_trade_result_safe() 전환

## 코드 정리
- 프론트엔드: isUsStock, formatTime 공통 유틸 추출
- 백엔드: dead code 제거, 중복 import 통합
- MCP: JSON 파싱 헬퍼 추출 (~60줄 감소)
- 전체 ~100개 파일 한국어 주석 추가
- 테스트 13건 코드 기준 수정 (468 passed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:05:41 +09:00
f6480407f2 test: 상관관계 필터 유닛 테스트 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 17:26:41 +09:00