diff --git a/config.py b/config.py index 9c53d7a..0c9fcd7 100644 --- a/config.py +++ b/config.py @@ -111,4 +111,5 @@ KR_COINS = { # 볼린저 밴드 설정 BOLLINGER_PERIOD = 20 # 볼린저 밴드 기간 BOLLINGER_STD = 2 # 표준편차 승수 -ALERT_THRESHOLD = 0.20 # 하단 밴드 대비 10% 근접 시 알림 \ No newline at end of file +ALERT_THRESHOLD = 0.10 # 하단 밴드 대비 10% 근접 시 알림 +BUY_THRESHOLD = 0.15 \ No newline at end of file diff --git a/stock_monitor.py b/stock_monitor.py index 370c967..9e2e985 100644 --- a/stock_monitor.py +++ b/stock_monitor.py @@ -33,6 +33,19 @@ def calculate_bollinger_bands(data): def check_bollinger_bands(symbol, data): if len(data) < BOLLINGER_PERIOD: return None + + # 과거 10개 봉에서 ALERT_THRESHOLD 아래로 빠진 적이 있는지 체크 + check = False + for i in range(-1, -10, -1): + past = data.iloc[i] + upper_band = past['Upper'] + lower_band = past['Lower'] + price = past['Close'] + distance = (price - lower_band) / (upper_band - lower_band) + if distance < ALERT_THRESHOLD: + check = True + break + latest = data.iloc[-1] if isinstance(latest['Upper'], float): upper_band = latest['Upper'] @@ -43,11 +56,17 @@ def check_bollinger_bands(symbol, data): lower_band = latest['Lower'].iloc[0] current_price = latest['Close'].iloc[0] distance = (current_price - lower_band) / (upper_band - lower_band) + + buy = False + if check and BUY_THRESHOLD < distance: + buy = True + return { 'symbol': symbol, 'price': current_price, 'lower_band': lower_band, - 'distance': distance + 'distance': distance, + 'buy': buy } @@ -113,13 +132,7 @@ def get_stock_data(symbol, retries=3): return None -def sendAlertMsg(info, market="US", alert=False): - if alert: - message = "🔔" - else: - message = "" - - message += "[{}] {} ({}) 현재가: ${:.2f}, 근접도: {:.2f}%".format(market, info['name'], info['symbol'], info['price'], info['distance']) +def sendAlertMsg(message): try: send_telegram_message(message) except Exception as e: @@ -128,6 +141,8 @@ def sendAlertMsg(info, market="US", alert=False): def monitor_us_stocks(): + message = "" + # 미국 주식 모니터링 print("US Stocks {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) for symbol in US_STOCKS: @@ -139,22 +154,25 @@ def monitor_us_stocks(): info['name'] = US_STOCKS[symbol] print(" - {} ({}): {:.2f} ({:.2f})".format(info['name'], symbol, info['price'], info['distance'])) - if info['distance'] > ALERT_THRESHOLD: - sendAlertMsg(info, "US") - else: - sendAlertMsg(info, "US", alert=True) - print(f"Alert generated for {symbol}") - + if info['buy']: + message += '🛒' + if info['distance'] < ALERT_THRESHOLD: + message += "🔔" + message += "[{}] {} ({}) 현재가: ${:.2f}, 근접도: {:.2f}%\n".format('US', info['name'], info['symbol'], info['price'], info['distance'] * 100) except Exception as e: print(f"Error processing data for {symbol}: {str(e)}") else: print(f"Data for {symbol} is empty or None.") time.sleep(0.5) + sendAlertMsg(message) + return def monitor_kr_stocks(): + message = "" + # 한국 ETF 모니터링 print("KR ETFs {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) for symbol in KR_ETFS: @@ -166,11 +184,11 @@ def monitor_kr_stocks(): info['name'] = KR_ETFS[symbol] print(" - {} ({}): {:.2f} ({:.2f})".format(info['name'], symbol, info['price'], info['distance'])) - if info['distance'] > ALERT_THRESHOLD: - sendAlertMsg(info, "KR") - else: - sendAlertMsg(info, "KR", alert=True) - print(f"Alert generated for {symbol}") + if info['buy']: + message += '🛒' + if info['distance'] < ALERT_THRESHOLD: + message += "🔔" + message += "[{}] {} ({}) 현재가: ${:.2f}, 근접도: {:.2f}%\n".format('KR', info['name'], info['symbol'], info['price'], info['distance'] * 100) except Exception as e: print(f"Error processing data for {symbol}: {str(e)}") @@ -178,10 +196,13 @@ def monitor_kr_stocks(): print(f"Data for {symbol} is empty or None.") time.sleep(0.5) + sendAlertMsg(message) return def monitor_coins(): + message = "[KRW-Coin]\n" + # 코인 모니터링 print("KRW Coins {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) for symbol in KR_COINS: @@ -193,18 +214,19 @@ def monitor_coins(): info['name'] = KR_COINS[symbol] print(" - {} ({}): {:.2f} ({:.2f})".format(info['name'], symbol, info['price'], info['distance'])) - if info['distance'] > ALERT_THRESHOLD: - sendAlertMsg(info, "KRW") - else: - sendAlertMsg(info, "KRW", alert=True) - print(f"Alert generated for {symbol}") - + message += "· {} ({}) 현재가: ₩{}, 근접도: {:.2f}%".format(info['name'], info['symbol'], info['price'], info['distance'] * 100) + if info['buy']: + message += ' (🛒)' + if info['distance'] < ALERT_THRESHOLD: + message += "(🔔)" + message += '\n' except Exception as e: print(f"Error processing data for {symbol}: {str(e)}") else: print(f"Data for {symbol} is empty or None.") time.sleep(0.5) + sendAlertMsg(message) return