feat: Enhance trading system with new e_min_chg_pct parameter and related logic

Changes:
- Introduced the `e_min_chg_pct` parameter to define the minimum price change percentage compared to the previous day's close, enhancing the momentum trading strategy.
- Updated various functions and classes to incorporate this new parameter, ensuring it is utilized in both backtesting and live trading scenarios.
- Improved documentation and comments to clarify the purpose and usage of the new parameter across the codebase.

Impact:
- This addition allows for more precise control over trading conditions, potentially increasing the effectiveness of the momentum strategy while maintaining system integrity and performance.
This commit is contained in:
Your Name
2026-08-01 16:19:24 +09:00
parent 7050f788c5
commit cb7e5037a0
30 changed files with 2206 additions and 253 deletions

View File

@@ -657,8 +657,10 @@ ENV_CONFIG_KEYS = (
"USE_KELLY_FORMULA",
# 켈리 공식 적용 배수 (0.25 = Full Kelly의 25%, 과도한 베팅 방지)
"KELLY_MULTIPLIER",
# 시장가 IOC 주문 사용 여부 (실전: true=IOC, false=일반 시장가)
# 시장가 IOC 주문 사용 여부 — 매수 (실전: true=IOC13, false=일반01 · 모의는 코드에서 01 고정)
"USE_MARKET_IOC",
# 시장가 IOC 주문 사용 여부 — 매도 (실전: true=IOC13, false=일반01 · 모의는 코드에서 01 고정)
"USE_MARKET_IOC_SELL",
# 체결 확인 엄격 모드: true=모의도 fill 없으면 가정 체결 금지 (실전 훈련)
"STRICT_FILL_VERIFY",
# 주문 직후 체결 조회 대기(초) — 시장가
@@ -1136,6 +1138,7 @@ ENV_CONFIG_KEYS = (
"MOMENTUM_TRIGGER_REQUIRE_BULL_BAR",
"MOMENTUM_USE_VOL_TRIGGER",
"MOMENTUM_USE_RSI_FILTER",
"MOMENTUM_E_MIN_CHG_PCT",
"MOMENTUM_CHASE_LOOKBACK_MIN",
"MOMENTUM_PULLBACK_LOOKBACK_MIN",
"MOMENTUM_PULLBACK_MIN_PCT",
@@ -2424,9 +2427,10 @@ class TradeDB:
size_class: str = None,
strategy: str = None,
realized_pnl_override: float = None,
sell_qty: int = None,
):
"""
매도 완료 처리: active_trades 삭제 -> trade_history 이동 (INSERT만, env 스냅샷 포함)
매도 완료 처리: active_trades trade_history (INSERT만, env 스냅샷 포함)
Args:
code: 종목코드
@@ -2437,6 +2441,10 @@ class TradeDB:
strategy: 봇 전략 ID (SHORT_ANT_SHAKING / SCALP_RSI_REVERSAL 등)
지정 시 해당 전략 row만 삭제 (다른 봇의 동일 종목 보호).
None이면 code 단독 조회 (단일 봇 운영 환경 호환).
realized_pnl_override: 수수료·세금 반영 순손익 (외부 주입)
sell_qty: 부분매도 수량. None/전량 이상이면 기존처럼 전량 청산.
0 < sell_qty < current_qty 이면 history 기록 후 잔량 유지
(시장가 IOC 부분체결 대비).
"""
try:
# 1. 활성 트레이드 정보 조회 (strategy 지정 시 정확히 해당 row만 조회)
@@ -2453,9 +2461,16 @@ class TradeDB:
logger.warning(f"⚠️ close_trade: {code} 종목이 active_trades에 없음")
return False
# 2. 손익 계산
# 2. 손익 계산 (부분매도면 체결분만)
buy_price = trade['avg_buy_price']
qty = trade['current_qty']
pos_qty = int(trade['current_qty'] or 0)
if sell_qty is None:
qty = pos_qty
else:
qty = min(max(0, int(sell_qty)), pos_qty)
if qty <= 0:
logger.warning("⚠️ close_trade: %s sell_qty<=0 (pos=%d)", code, pos_qty)
return False
# realized_pnl_override 가 있으면 수수료·세금 반영 순손익을 외부에서 주입
# 없으면 내부 계산 (수수료 미포함 gross)
if realized_pnl_override is not None:
@@ -2485,6 +2500,9 @@ class TradeDB:
if ML_ENTRY_FEATURE_COLUMNS:
cols_th += ", " + ", ".join(ML_ENTRY_FEATURE_COLUMNS)
placeholders = ", ".join(["?"] * (14 + len(ML_ENTRY_FEATURE_COLUMNS)))
remain_qty = pos_qty - qty
inv = float(trade["total_invested"] or 0) if "total_invested" in trade.keys() else 0.0
new_inv = (inv * remain_qty / pos_qty) if pos_qty > 0 and remain_qty > 0 else 0.0
with self.conn:
self.conn.execute(f"""
INSERT INTO trade_history (
@@ -2507,16 +2525,50 @@ class TradeDB:
size_class,
) + tuple(feat_vals))
# 5. active_trades에서 삭제 (strategy 지정 시 해당 봇 row만 삭제)
if strategy:
self.conn.execute(
"DELETE FROM active_trades WHERE code=%s AND strategy=%s",
(code, strategy),
)
# 5. 전량이면 삭제, 부분이면 잔량·투입금 축소
if remain_qty <= 0:
if strategy:
self.conn.execute(
"DELETE FROM active_trades WHERE code=%s AND strategy=%s",
(code, strategy),
)
else:
self.conn.execute("DELETE FROM active_trades WHERE code=%s", (code,))
else:
self.conn.execute("DELETE FROM active_trades WHERE code=%s", (code,))
logger.info(f"✅ [{trade['name']}] 매매 종료: 수익률 {profit_rate:.2f}% ({realized_pnl:+,.0f}원)")
if strategy:
self.conn.execute(
"UPDATE active_trades SET current_qty=%s, target_qty=%s, "
"total_invested=%s, updated_at=%s "
"WHERE code=%s AND strategy=%s",
(
remain_qty,
remain_qty,
new_inv,
sell_time.strftime("%Y-%m-%d %H:%M:%S"),
code,
strategy,
),
)
else:
self.conn.execute(
"UPDATE active_trades SET current_qty=%s, target_qty=%s, "
"total_invested=%s, updated_at=%s WHERE code=%s",
(
remain_qty,
remain_qty,
new_inv,
sell_time.strftime("%Y-%m-%d %H:%M:%S"),
code,
),
)
if remain_qty <= 0:
logger.info(f"✅ [{trade['name']}] 매매 종료: 수익률 {profit_rate:.2f}% ({realized_pnl:+,.0f}원)")
else:
logger.info(
"✅ [%s] 부분매도 %d/%d주: 수익률 %.2f%% (%+.0f원) · 잔량 %d",
trade["name"], qty, pos_qty, profit_rate, realized_pnl, remain_qty,
)
return True
except Exception as e: