커서가 망쳐놓은 듯
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user