From 7251826f387f5644e53c319cdd6349381c65886f Mon Sep 17 00:00:00 2001 From: dsyoon Date: Sun, 27 Jul 2025 20:40:16 +0900 Subject: [PATCH] init --- config.py | 4 ++++ stock_monitor.py | 23 +++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/config.py b/config.py index 8f6e43e..34aa8ae 100644 --- a/config.py +++ b/config.py @@ -16,6 +16,10 @@ BREAKOUT_LOOKBACK = 30 # U자 반등 후 돌파 판단에 사용할 과거 캔 BREAKOUT_WEEK_LOOKBACK = 42 # 4시간봉 1주일 ≒ 42개 BREAKOUT_WEEK_LIMIT = 0.05 # 1주일 대비 5% 미만 상승 조건 +# 장기간 저항선 돌파 감지 설정 +RESISTANCE_LOOKBACK = 120 # 저항선 판단을 위한 과거 캔들 수 (예: 120개) +RESISTANCE_BREAK_THRESHOLD = 0.01 # 저항선 대비 1% 이상 돌파 시 신호 + KR_COINS = { "ADA": "ADA", "APE": "ApeCoin", diff --git a/stock_monitor.py b/stock_monitor.py index 0e421b6..574a444 100644 --- a/stock_monitor.py +++ b/stock_monitor.py @@ -131,6 +131,16 @@ def check_buy_signals(symbol, data): and week_change <= BREAKOUT_WEEK_LIMIT ): breakout_signal = True + + # 장기간 저항선 돌파 여부 계산 (LONG RESISTANCE BREAKOUT) + long_breakout_signal = False + if len(data) >= RESISTANCE_LOOKBACK + 1: + resistance_level = data['Close'].iloc[-RESISTANCE_LOOKBACK-1:-1].max() + previous_closes = data['Close'].iloc[-RESISTANCE_LOOKBACK-1:-1] + # 과거 구간에서 저항선 이상으로 종가가 한번도 올라가지 않은 경우 + 현재 가격이 저항선 돌파 + if (previous_closes <= resistance_level * (1 + RESISTANCE_BREAK_THRESHOLD)).all() and \ + current_price > resistance_level * (1 + RESISTANCE_BREAK_THRESHOLD): + long_breakout_signal = True # RSI 과매도 신호 (RSI < 30) if not isinstance(latest['Upper'], float): @@ -152,7 +162,8 @@ def check_buy_signals(symbol, data): 'macd_signal': macd_signal, 'ma_signal': ma_signal, 'volume_signal': volume_signal, - 'breakout_signal': breakout_signal + 'breakout_signal': breakout_signal, + 'long_breakout_signal': long_breakout_signal } # 최소 3개 이상의 신호가 동시에 발생할 때 매수 신호로 간주 @@ -168,7 +179,7 @@ def check_buy_signals(symbol, data): 'signal_line': latest['Signal'].iloc[0], 'buy_signals': buy_signals, 'signal_count': signal_count, - 'buy': breakout_signal or ((bb_signal and rsi_signal) or (signal_count >= 2 and (bb_signal or rsi_signal))) + 'buy': long_breakout_signal or breakout_signal or ((bb_signal and rsi_signal) or (signal_count >= 2 and (bb_signal or rsi_signal))) } else: rsi_signal = latest['RSI'] < 30 @@ -189,7 +200,8 @@ def check_buy_signals(symbol, data): 'macd_signal': macd_signal, 'ma_signal': ma_signal, 'volume_signal': volume_signal, - 'breakout_signal': breakout_signal + 'breakout_signal': breakout_signal, + 'long_breakout_signal': long_breakout_signal } # 최소 3개 이상의 신호가 동시에 발생할 때 매수 신호로 간주 @@ -205,7 +217,7 @@ def check_buy_signals(symbol, data): 'signal_line': latest['Signal'], 'buy_signals': buy_signals, 'signal_count': signal_count, - 'buy': breakout_signal or ((bb_signal and rsi_signal) or (signal_count >= 2 and (bb_signal or rsi_signal))) + 'buy': long_breakout_signal or breakout_signal or ((bb_signal and rsi_signal) or (signal_count >= 2 and (bb_signal or rsi_signal))) } def format_message(info, market_type): @@ -238,6 +250,9 @@ def format_message(info, market_type): if info['buy_signals'].get('breakout_signal'): message += "- U자 반등 돌파" count += 1 + if info['buy_signals'].get('long_breakout_signal'): + message += "- 장기 저항 돌파" + count += 1 message += "\n" message = message.replace("{count}", str(count)) return message