From 78ab3d7d4e97d9aa6d10db2cb10abe435f3c8702 Mon Sep 17 00:00:00 2001 From: shuim Date: Wed, 23 Sep 2026 14:48:34 +0900 Subject: [PATCH] =?UTF-8?q?chore:=20=EC=8A=A4=EC=9C=99=20=EC=9E=90?= =?UTF-8?q?=EB=B3=B8=20=EC=83=81=ED=95=9C=2070%=EB=A1=9C=20=EC=83=81?= =?UTF-8?q?=ED=96=A5=20(=EC=8A=A4=EC=9C=99:DT=20=3D=2070:30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 스윙이 이미 47%라 신규 매수가 swing_capital_cap 에 막혀(오늘 60건) 표본이 쌓이지 않았다. - SWING_MAX_CAPITAL_RATIO 0.50 → 0.70 - DAY_TRADE_MAX_RATIO_DT 0.50 → 0.30, DAY_TRADE_MAX_POSITIONS 8 → 5 (5×6%=30%) - 두 상한의 합이 100%를 넘지 않는지 테스트로 고정 Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 10 +++++----- backend/app/core/config.py | 8 ++++---- ...t_daytrading_orb_watchlist_and_capital_split.py | 14 +++++++++----- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 9fd8f8a..4b6d5e9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,7 +51,7 @@ - **-20%**: 전 포지션 50% 강제 축소, 레버리지/인버스 ETF 우선 청산 (FORCE_REDUCE) - 잔고가 peak 갱신 시 모든 MDD 플래그 리셋. -## 6. 전략 A: RSI+BB 평균 회귀 v2 (`mean_reversion_strategy`, `swing/`) — 스윙 자본 최대 50%(`SWING_MAX_CAPITAL_RATIO`) +## 6. 전략 A: RSI+BB 평균 회귀 v2 (`mean_reversion_strategy`, `swing/`) — 스윙 자본 최대 70%(`SWING_MAX_CAPITAL_RATIO`) - **시장 국면(일봉)**: BULL = 코스피200>MA200 & MA200 기울기>0 / BEAR = 코스피20020MA / BEAR: RSI<35 + 가격1.5×20MA + 반전캔들 필수 / 선제: 일봉 RSI<46 & 60분봉 RSI<30 & MA5 상향돌파 - **청산**: 50% 부분매도: RSI≥55 or 가격>BB중앙 or 수익>2×ATR / 전량: RSI≥70 or 가격>BB상단(99%) or 트레일링(고점−1.5×ATR) @@ -64,7 +64,7 @@ - 타겟: 일봉 RSI<40 / 진입: 15분 RSI<30 + BB하단 부근 + 종가>MA5(상향돌파) + 거래량>1.3×20MA(`SHORT_TERM_VOLUME_MULTIPLIER`) + ATR/close≥0.8%(`SHORT_TERM_MIN_ATR_RATIO`, 거래비용 커버) - 청산: 15분 RSI>55 or 수익>1.5×ATR(15분) / SL: `min(진입가−1.0×ATR, -2% 하드스탑)` — 타이트한(stop가 높은) 쪽. *§5.2 ATR 2.5×는 일봉/스윙 전용* -### 7.3 데이트레이딩 5분봉 (`day_trading_strategy`, `daytrading/`) — 자본 최대 **50%**(`DAY_TRADE_MAX_RATIO_DT`, 스윙:DT = 50:50, 스윙은 `SWING_MAX_CAPITAL_RATIO=0.50`로 상한), **MDD -10% 시 비활성** +### 7.3 데이트레이딩 5분봉 (`day_trading_strategy`, `daytrading/`) — 자본 최대 **30%**(`DAY_TRADE_MAX_RATIO_DT`, 스윙:DT = 70:30, 스윙은 `SWING_MAX_CAPITAL_RATIO=0.70`로 상한), **MDD -10% 시 비활성** | 전략 | 진입 | SL | |------|------|-----| @@ -72,7 +72,7 @@ | VWAP | VWAP 지지 반등 + RSI(14)<40 + 거래량≥1.3× + 양봉 | `min(ATR×1.5, -2.5% 하드)` + 최소 1원 | | RSI_BB | RSI≤30 + 종가≤BB하단 + 거래량≥1.3× + 양봉 | `min(ATR×1.5, -2.5% 하드)` + 최소 1원 | -- 사이징: 종목당 6%(`DAY_TRADE_MAX_CAPITAL_RATIO`), 동시 8종목(`DAY_TRADE_MAX_POSITIONS`), confidence 조정 `예산×(confidence/0.7)` +- 사이징: 종목당 6%(`DAY_TRADE_MAX_CAPITAL_RATIO`), 동시 5종목(`DAY_TRADE_MAX_POSITIONS`), confidence 조정 `예산×(confidence/0.7)` - 청산: +2R 시 50% 분할→잔량 트레일링(ATR×1.0) / 진입 30분(6봉)간 +0.3% 미달 시 시간손절 / 5분 RSI≥70 & 수수료 이상 수익 시 / **15:20 EOD 전량 청산**(`DAY_TRADE_EOD_FLAT_*`) / **전일 미청산 포지션은 장중 발견 즉시 전량 청산**(`close_stale_positions`, EOD 누락 안전장치) - 제한: CRASH/HALTED 국면 차단 / **15:00 이후 신규 마감**(`DAY_TRADE_ENTRY_CUTOFF_*`, 점심 제한은 2026-09-22 제거) / 일일 -3% 손실 시 당일 중단(`DAY_TRADE_DAILY_LOSS_LIMIT`) / 당일 3연패 쿨다운(position_manager) / 전량 매도 시 loss_tracker 기록 + `save_to_db()` - 감시종목: 09:00에 당일 분석이 없으면 **최근 분석일 결과로 선채움**(ORB 수집 보장), 자동 목록은 30분마다 갱신(수동 설정 목록은 유지) @@ -102,9 +102,9 @@ | `MEAN_REVERSION_BEAR_RSI_THRESHOLD` | 35.0 | 30→35 | | `MEAN_REVERSION_RSI_EXIT_THRESHOLD` | 55.0 | 1차 익절, 50→55 | | `MEAN_REVERSION_RSI_FULL_EXIT` | 70.0 | 전량 청산, 65→70 | -| `DAY_TRADE_MAX_POSITIONS` | 8 | 3→8 (50:50 배분) | +| `DAY_TRADE_MAX_POSITIONS` | 5 | 8→5 (70:30 배분) | | `DAY_TRADE_ENTRY_CUTOFF` | 15:00 | 14:30→15:00 (시간대 완화) | -| `DAY_TRADE_MAX_RATIO_DT` / `SWING_MAX_CAPITAL_RATIO` | 0.50 / 0.50 | 스윙:DT 50:50 (2026-09-22) | +| `DAY_TRADE_MAX_RATIO_DT` / `SWING_MAX_CAPITAL_RATIO` | 0.30 / 0.70 | 스윙:DT 70:30 (2026-09-23) | | `CONSECUTIVE_LOSS_BAN_COUNT` | 3 | | ### 8.3 스윙 듀얼 전략 (3종 병행) diff --git a/backend/app/core/config.py b/backend/app/core/config.py index b3db768..559f443 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -219,12 +219,12 @@ class Settings(BaseSettings): # 데이트레이딩(5분봉) 전략 (섹션 7.3) # ═════════════════════════════════════════════════════════════════════════════ DAY_TRADE_ENABLED: bool = True # 데이트레이딩 활성화 - DAY_TRADE_MAX_POSITIONS: int = 8 # 동시 최대 종목 수 (3→8, 2026-09-22 50:50 배분: 8×6%≈50%) - DAY_TRADE_CAPITAL_RATIO: float = 0.50 # 전체 자본 대비 최대 50% (0.25→0.50, 2026-09-22) + DAY_TRADE_MAX_POSITIONS: int = 5 # 동시 최대 종목 수 (8→5, 2026-09-23 30% 배분: 5×6%=30%) + DAY_TRADE_CAPITAL_RATIO: float = 0.30 # 전체 자본 대비 최대 30% (0.50→0.30, 2026-09-23 스윙 70%) DAY_TRADE_PER_STOCK_RATIO: float = 0.06 # 종목당 최대 6% (0.04→0.06, MAX_POSITION_SIZE 상한과 동일) DAY_TRADE_MAX_CAPITAL_RATIO: float = 0.06 # 종목당 최대 6% 자본 (0.04→0.06, 2026-09-22) - DAY_TRADE_MAX_RATIO_DT: float = 0.50 # 전체 데이트레이딩 최대 50% (0.25→0.50, 2026-09-22 스윙:DT = 50:50) - SWING_MAX_CAPITAL_RATIO: float = 0.50 # 스윙 전략 합산 최대 50% (신규, 2026-09-22 — 초과 시 스윙 신규 매수 차단) + DAY_TRADE_MAX_RATIO_DT: float = 0.30 # 전체 데이트레이딩 최대 30% (스윙:DT = 70:30, 2026-09-23) + SWING_MAX_CAPITAL_RATIO: float = 0.70 # 스윙 전략 합산 최대 70% (0.50→0.70, 2026-09-23 — 표본 확보) DAY_TRADE_STOP_LOSS_PCT: float = 0.02 # 종목 손절 -2% DAY_TRADE_DAILY_LOSS_LIMIT: float = -0.03 # 일일 손실 한도 -3% DAY_TRADE_EOD_FLAT_HOUR: int = 15 # EOD 강제 청산 시간 (15시) diff --git a/backend/tests/test_daytrading_orb_watchlist_and_capital_split.py b/backend/tests/test_daytrading_orb_watchlist_and_capital_split.py index d054c7e..a5c969b 100644 --- a/backend/tests/test_daytrading_orb_watchlist_and_capital_split.py +++ b/backend/tests/test_daytrading_orb_watchlist_and_capital_split.py @@ -101,11 +101,15 @@ async def test_entry_no_lunch_block_and_cutoff_from_settings(): def test_capital_split_settings(): - assert settings.DAY_TRADE_MAX_RATIO_DT == 0.50 - assert settings.SWING_MAX_CAPITAL_RATIO == 0.50 - assert settings.DAY_TRADE_MAX_POSITIONS * settings.DAY_TRADE_MAX_CAPITAL_RATIO >= 0.48 + # 2026-09-23: 스윙:DT = 70:30 (스윙 표본 확보) + assert settings.DAY_TRADE_MAX_RATIO_DT == 0.30 + assert settings.SWING_MAX_CAPITAL_RATIO == 0.70 + # 두 전략 합이 100%를 넘지 않아야 현금 여력이 남는다 + assert settings.SWING_MAX_CAPITAL_RATIO + settings.DAY_TRADE_MAX_RATIO_DT <= 1.0 + # 동시 보유 한도 × 종목당 비중이 전체 한도를 채울 수 있어야 한다 + assert settings.DAY_TRADE_MAX_POSITIONS * settings.DAY_TRADE_MAX_CAPITAL_RATIO >= settings.DAY_TRADE_MAX_RATIO_DT assert (settings.DAY_TRADE_ENTRY_CUTOFF_HOUR, settings.DAY_TRADE_ENTRY_CUTOFF_MIN) == (15, 0) from app.services.day_trading_strategy import calculate_day_trade_position_size - # 총자산 1,000만: 종목당 60만, DT 합산 500만 + # 총자산 1,000만: 종목당 60만, DT 합산 300만 assert calculate_day_trade_position_size(10_000_000, 5_000_000, 0) == 600_000 - assert calculate_day_trade_position_size(10_000_000, 5_000_000, 4_800_000) == 200_000 + assert calculate_day_trade_position_size(10_000_000, 5_000_000, 2_800_000) == 200_000