diff --git a/requirements.txt b/requirements.txt index 73751ac..6f2f0e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ pycurl schedule python-dateutil python-telegram-bot +finance-datareader \ No newline at end of file diff --git a/stock_monitor.py b/stock_monitor.py index 4a62ee9..61d937e 100644 --- a/stock_monitor.py +++ b/stock_monitor.py @@ -9,6 +9,7 @@ import asyncio from multiprocessing import Pool import schedule from config import * +import FinanceDataReader as fdr def send_coin_msg(text): @@ -144,7 +145,7 @@ def check_buy_signals(symbol, data): 'signal_line': latest['Signal'].iloc[0], 'buy_signals': buy_signals, 'signal_count': signal_count, - 'buy': (bb_signal and rsi_signal) or (signal_count >= 3 and (bb_signal or rsi_signal)) + 'buy': (bb_signal and rsi_signal) or (signal_count >= 2 and (bb_signal or rsi_signal)) } else: rsi_signal = latest['RSI'] < 30 @@ -180,7 +181,7 @@ def check_buy_signals(symbol, data): 'signal_line': latest['Signal'], 'buy_signals': buy_signals, 'signal_count': signal_count, - 'buy': (bb_signal and rsi_signal) or (signal_count >= 3 and (bb_signal or rsi_signal)) + 'buy': (bb_signal and rsi_signal) or (signal_count >= 2 and (bb_signal or rsi_signal)) } def format_message(info, market_type): @@ -252,24 +253,28 @@ def get_coin_data(symbol, retries=3): return None -def get_stock_data(symbol, retries=3): +def get_kr_stock_data(symbol, retries=3): for attempt in range(retries): try: end = datetime.now() start = end - timedelta(days=300) - data = yf.download( - symbol, - start=start.strftime('%Y-%m-%d'), - end=end.strftime('%Y-%m-%d'), - interval='1d', - auto_adjust=True, - progress=False - ) + + # FinanceDataReader를 사용하여 한국 주식 데이터 가져오기 + data = fdr.DataReader(symbol, start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d')) + if not data.empty: + # FinanceDataReader의 컬럼명을 yfinance 형식으로 변환 + data = data.rename(columns={ + 'Open': 'Open', + 'High': 'High', + 'Low': 'Low', + 'Close': 'Close', + 'Volume': 'Volume' + }) return data print(f"No data received for {symbol}, attempt {attempt + 1}") - time.sleep(0.5) + time.sleep(2) except Exception as e: print(f"Attempt {attempt + 1} failed for {symbol}: {str(e)}") if attempt < retries - 1: @@ -282,7 +287,7 @@ def monitor_us_stocks(): print("US Stocks {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) for symbol in US_STOCKS: - data = get_stock_data(symbol) + data = get_kr_stock_data(symbol) if data is not None and not data.empty: try: data = calculate_technical_indicators(data) @@ -311,23 +316,32 @@ def monitor_kr_stocks(): print("KR ETFs {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) for symbol in KR_ETFS: - data = get_stock_data(symbol) - if data is not None and not data.empty: - try: - data = calculate_technical_indicators(data) - info = check_buy_signals(symbol, data) - info['name'] = KR_ETFS[symbol] - print(f" - {info['name']} ({symbol}): {info['price']:.2f} -> {info['signal_count']}") + try: + # .KS 접미사 제거 + clean_symbol = symbol.replace('.KS', '') + data = get_kr_stock_data(clean_symbol) + + if data is not None and not data.empty: + try: + data = calculate_technical_indicators(data) + info = check_buy_signals(symbol, data) + info['name'] = KR_ETFS[symbol] + print(f" - {info['name']} ({symbol}): {info['price']:.2f} -> {info['signal_count']}") - if info['buy']: - #if info['buy'] or any(info['buy_signals'].values()): - message_list.append(format_message(info, 'KR')) + if info['buy']: + message_list.append(format_message(info, 'KR')) - 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) + except Exception as e: + print(f"Error processing data for {symbol}: {str(e)}") + else: + print(f"Data for {symbol} is empty or None.") + + # 각 심볼 처리 후 1초 대기 + time.sleep(1) + + except Exception as e: + print(f"Unexpected error processing {symbol}: {str(e)}") + continue if len(message_list) > 0: try: