import pandas as pd from datetime import datetime, timedelta import time import schedule from config import * import FinanceDataReader as fdr from monitor_min import Monitor class MonitorStock (Monitor): """자산(코인/주식/ETF) 모니터링 및 매수 실행 클래스""" def __init__(self) -> None: super().__init__(None) def get_kr_stock_data(self, symbol: str, retries: int = 3) -> pd.DataFrame | None: for attempt in range(retries): try: end = datetime.now() start = end - timedelta(days=300) data = fdr.DataReader(symbol, start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d')) if not data.empty: 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(2) except Exception as e: print(f"Attempt {attempt + 1} failed for {symbol}: {str(e)}") if attempt < retries - 1: time.sleep(5) continue return None # ------------- Monitors ------------- def monitor_us_stocks(self) -> None: message_list: list[str] = [] print("US Stocks {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) for symbol in US_STOCKS: data = self.get_kr_stock_data(symbol) if data is not None and not data.empty: try: data = self.calculate_technical_indicators(data) recent_data = self.check_point(symbol, data) if recent_data['point'].iloc[-1] != 1: continue print(f" - {US_STOCKS[symbol]} ({symbol}): {recent_data['Close'].iloc[-1]:.2f}") message_list.append( self.format_message('US', symbol, US_STOCKS[symbol], recent_data['Close'].iloc[-1], recent_data['signal'].iloc[-1]) ) except Exception as e: print(f"Error processing data for {symbol}: {str(e)}") time.sleep(0.5) if len(message_list) > 0: try: self.send_stock_telegram_message(message_list, header="[US-STOCK]") except Exception as e: print(f"Error sending Telegram message: {str(e)}") def monitor_kr_stocks(self) -> None: message_list: list[str] = [] print("KR ETFs {}".format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) for symbol in KR_ETFS: try: clean_symbol = symbol.replace('.KS', '') data = self.get_kr_stock_data(clean_symbol) if data is not None and not data.empty: try: data = self.calculate_technical_indicators(data) recent_data = self.check_point(symbol, data) if recent_data['point'].iloc[-1] != 1: continue print(f" - {KR_ETFS[symbol]} ({symbol}): {recent_data['Close'].iloc[-1]:.2f}") message_list.append( self.format_message('KR', symbol, KR_ETFS[symbol], recent_data['Close'].iloc[-1], recent_data['signal'].iloc[-1]) ) 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(1) except Exception as e: print(f"Unexpected error processing {symbol}: {str(e)}") continue if len(message_list) > 0: try: self.send_stock_telegram_message(message_list, header="[KR-STOCK]") except Exception as e: print(f"Error sending Telegram message: {str(e)}") # ------------- Scheduler ------------- def run_schedule(self) -> None: schedule.every().day.at("16:30").do(self.monitor_us_stocks) schedule.every().day.at("23:30").do(self.monitor_us_stocks) schedule.every().day.at("08:10").do(self.monitor_kr_stocks) schedule.every().day.at("18:20").do(self.monitor_kr_stocks) print("Scheduler started. Stock Monitoring will run at specified times.") while True: schedule.run_pending() time.sleep(1) if __name__ == "__main__": MonitorStock().run_schedule()