""" 프로세스 간 통신 (IPC) - 파일 기반 텔레그램 봇과 메인 봇 간 데이터 공유 """ import os import json import time from datetime import datetime from modules.config import Config class BotIPC: """파일 기반 IPC (Inter-Process Communication)""" def __init__(self, ipc_file=None): self.ipc_file = ipc_file if ipc_file else Config.IPC_FILE self.last_update = 0 def write_status(self, data): """메인 봇이 상태를 파일에 기록""" try: with open(self.ipc_file, 'w', encoding='utf-8') as f: json.dump({ 'timestamp': time.time(), 'data': data }, f, ensure_ascii=False, indent=2) except Exception as e: print(f"⚠️ [IPC] Write failed: {e}") def read_status(self): """텔레그램 봇이 상태를 파일에서 읽기""" try: if not os.path.exists(self.ipc_file): print(f"⚠️ [IPC] File not found: {self.ipc_file}") return None with open(self.ipc_file, 'r', encoding='utf-8') as f: ipc_data = json.load(f) # 60초 이상 오래된 데이터는 무시 (10초 → 60초로 완화) timestamp = ipc_data.get('timestamp', 0) age = time.time() - timestamp if age > 60: print(f"⚠️ [IPC] Data too old: {age:.1f}s") return None print(f"✅ [IPC] Data loaded (age: {age:.1f}s)") return ipc_data.get('data') except Exception as e: print(f"⚠️ [IPC] Read failed: {e}") return None def get_bot_instance_data(self): """봇 인스턴스 데이터 가져오기 (호환성 유지)""" status = self.read_status() if not status: return None # 가짜 봇 인스턴스 객체 생성 (기존 코드 호환) class FakeBotInstance: def __init__(self, data): self.kis = FakeKIS(data.get('balance', {}), data.get('macro_indices', {})) self.ollama_monitor = FakeOllama(data.get('gpu', {})) self.theme_manager = FakeThemeManager(data.get('themes', {})) self.discovered_stocks = set(data.get('discovered_stocks', [])) self.is_macro_warning_sent = data.get('is_macro_warning', False) self.watchlist_manager = FakeWatchlistManager(data.get('watchlist', {})) self.load_watchlist = lambda: data.get('watchlist', {}) class FakeKIS: def __init__(self, balance_data, macro_indices): self._balance = balance_data if balance_data else { 'total_eval': 0, 'deposit': 0, 'holdings': [] } self._macro_indices = macro_indices if macro_indices else {} def get_balance(self): return self._balance def get_current_index(self, ticker): """지수 조회 - IPC에서 저장된 데이터 반환""" if ticker in self._macro_indices: return self._macro_indices[ticker] # 데이터 없으면 기본값 return { 'price': 2500.0, 'change': 0.0 } def get_daily_index_price(self, ticker, period="D"): """지수 일별 시세 조회 - IPC 모드에서는 더미 데이터 반환""" # MacroAnalyzer의 MSI 계산용 # 실제 데이터는 메인 봇에서만 조회 가능 # IPC 모드에서는 기본 더미 데이터 반환 (20일치) base_price = 2500.0 if ticker in self._macro_indices: base_price = self._macro_indices[ticker].get('price', 2500.0) # 20일치 더미 데이터 (약간의 변동) import random prices = [] for i in range(20): variation = random.uniform(-0.02, 0.02) # ±2% 변동 prices.append(base_price * (1 + variation)) return prices def get_current_price(self, ticker): """현재가 조회 - IPC 모드에서는 사용 불가""" return None def get_daily_price(self, ticker, period="D"): """일별 시세 조회 - IPC 모드에서는 사용 불가""" return [] def get_volume_rank(self, market="0"): """거래량 순위 조회 - IPC 모드에서는 사용 불가""" return [] def buy_stock(self, ticker, qty): """매수 주문 - IPC 모드에서는 사용 불가""" return {"success": False, "msg": "IPC mode: buy not available"} def sell_stock(self, ticker, qty): """매도 주문 - IPC 모드에서는 사용 불가""" return {"success": False, "msg": "IPC mode: sell not available"} class FakeOllama: def __init__(self, gpu_data): self._gpu = gpu_data if gpu_data else { 'name': 'N/A', 'temp': 0, 'vram_used': 0, 'vram_total': 0, 'load': 0 } def get_gpu_status(self): return self._gpu class FakeThemeManager: def __init__(self, themes_data): self._themes = themes_data if themes_data else {} def get_themes(self, ticker): return self._themes.get(ticker, []) class FakeWatchlistManager: def __init__(self, watchlist_data): self._watchlist = watchlist_data if watchlist_data else {} def update_watchlist_daily(self): return "⚠️ Watchlist update not available in IPC mode" return FakeBotInstance(status) def load_watchlist(self): """Watchlist 로드""" status = self.read_status() if status: return status.get('watchlist', {}) return {}