커서가 망쳐놓은 듯

This commit is contained in:
2026-03-17 12:33:30 +09:00
parent 6fc179f598
commit c2b2b711e0
91 changed files with 45391 additions and 2244 deletions

View File

@@ -20,12 +20,21 @@ class RiskManager:
"""
def __init__(
self,
risk_pct_per_trade: float = 0.02, # 1회 거래 시 허용 손실 비율 (2%)
max_position_pct: float = 0.20, # 종목당 최대 비중 (20%)
min_position_amount: int = 50000, # 최소 매수 금액 (5만원)
use_kelly: bool = False, # 켈리 공식 사용 여부
kelly_multiplier: float = 0.5 # 켈리 배율 (0.5 = 하프 켈리)
self,
risk_pct_per_trade: float = 0.02, # 1회 거래 시 허용 손실 비율 (2%)
max_position_pct: float = 0.20, # 종목당 최대 비중 (20%)
min_position_amount: int = 50000, # 최소 매수 금액 (5만원)
use_kelly: bool = False, # 켈리 공식 사용 여부
kelly_multiplier: float = 0.5, # 켈리 배율 (0.5 = 하프 켈리)
slot_base_amount_cap: int = 0, # 종목당 원화 상한 (0=미적용)
# ── 반드시 적용되는 MAX_LOSS 기반 절대 상한 ─────────────────────
# max_loss_per_trade_krw / |stop_loss_pct| = 투자 상한 금액
# 0이면 미적용 (RiskManager 계산 결과를 그대로 사용)
max_loss_per_trade_krw: int = 0, # 1회 최대 손실 허용액(원), MAX_LOSS_PER_TRADE_KRW
stop_loss_pct: float = 0.0, # 손절 비율(음수 가능), STOP_LOSS_PCT
# ── 사이즈 클래스별 매수 비율 (env/DB에서 주입, 하드코딩 금지) ──
size_small_ratio: float = 0.70, # 소형주 투자 비율 (SIZE_CLASS_SMALL_RATIO)
size_mid_ratio: float = 0.85, # 중형주 투자 비율 (SIZE_CLASS_MID_RATIO)
):
"""
Args:
@@ -34,16 +43,31 @@ class RiskManager:
min_position_amount: 최소 매수 금액 (너무 작은 주문 방지)
use_kelly: 켈리 공식 활성화 여부
kelly_multiplier: 켈리 배율 (0.5 = 하프켈리, 0.25 = 쿼터켈리)
slot_base_amount_cap: 종목당 매수 금액 원화 상한 (0이면 미적용, SLOT_BASE_AMOUNT_CAP)
"""
self.risk_pct = risk_pct_per_trade
self.max_pos_pct = max_position_pct
self.min_amount = min_position_amount
self.use_kelly = use_kelly
self.kelly_mult = kelly_multiplier
self.slot_base_amount_cap = slot_base_amount_cap if slot_base_amount_cap and slot_base_amount_cap > 0 else 0
# ── MAX_LOSS 기반 절대 투자 상한 ─────────────────────────────────
# = MAX_LOSS_PER_TRADE_KRW / |STOP_LOSS_PCT|
# 0이면 미적용 (stop_loss_pct 가 0이면 계산 불가이므로 미적용)
self._max_loss_krw = max_loss_per_trade_krw
_stop_abs = abs(stop_loss_pct)
self._max_loss_cap = int(max_loss_per_trade_krw / _stop_abs) if (max_loss_per_trade_krw > 0 and _stop_abs > 0) else 0
# ── 사이즈 클래스 비율 (하드코딩 금지) ────────────────────────────
self.size_small_ratio = size_small_ratio # 소형주 (SIZE_CLASS_SMALL_RATIO)
self.size_mid_ratio = size_mid_ratio # 중형주 (SIZE_CLASS_MID_RATIO)
logger.info(
f"💰 RiskManager 초기화: 리스크{self.risk_pct*100}% | "
f"최대비중{self.max_pos_pct*100}% | 켈리{'ON' if use_kelly else 'OFF'}"
+ (f" | 슬롯상한{self.slot_base_amount_cap:,}" if self.slot_base_amount_cap else "")
+ (f" | MAX_LOSS상한{self._max_loss_cap:,}" if self._max_loss_cap else "")
)
def calculate_volatility_atr(self, df: pd.DataFrame, period: int = 14) -> float:
@@ -197,15 +221,28 @@ class RiskManager:
note = "(변동성기반)"
# 5-2. 대형/소형 구간별 조정 (소형주는 포지션 축소)
# → 비율은 하드코딩 금지: __init__ 시 SIZE_CLASS_SMALL/MID_RATIO 주입
if size_class == "":
final_amount = int(final_amount * 0.7)
note = "(소형주 70%)"
final_amount = int(final_amount * self.size_small_ratio)
note = f"(소형주 {self.size_small_ratio*100:.0f}%)"
elif size_class == "":
final_amount = int(final_amount * 0.85)
note = "(중형주 85%)"
final_amount = int(final_amount * self.size_mid_ratio)
note = f"(중형주 {self.size_mid_ratio*100:.0f}%)"
elif size_class == "":
pass # 대형주는 기존과 동일
# 5-3. 슬롯 원화 상한 (SLOT_BASE_AMOUNT_CAP, 0이면 미적용)
if self.slot_base_amount_cap > 0 and final_amount > self.slot_base_amount_cap:
final_amount = self.slot_base_amount_cap
note = f"(슬롯상한{self.slot_base_amount_cap:,}원)"
# ── 5-4. MAX_LOSS 기반 절대 투자 상한 ────────────────────────
# 어떤 전략이든 MAX_LOSS_PER_TRADE_KRW / |STOP_LOSS_PCT| 를 초과 불가
# 이 값을 넘으면 손절 시 의도한 금액 손실(원)을 초과하게 됨
if self._max_loss_cap > 0 and final_amount > self._max_loss_cap:
final_amount = self._max_loss_cap
note = f"(MAX_LOSS상한 {self._max_loss_cap:,}원)"
# 6. 하한선 체크 (너무 작은 금액은 거래 안함)
if final_amount < self.min_amount:
logger.info(