This commit is contained in:
dsyoon
2026-01-28 18:58:33 +09:00
commit c45ad151b6
24 changed files with 7599 additions and 0 deletions

110
monitor_stock.py Normal file
View File

@@ -0,0 +1,110 @@
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()