164 lines
6.4 KiB
Python
164 lines
6.4 KiB
Python
"""
|
|
프로세스 간 통신 (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 {}
|