feat: add heartbeat and robust error handling to main loop (v1.3.5)

This commit is contained in:
Gemini CLI
2026-03-05 22:34:21 +01:00
parent fcfa2244f2
commit f1d7c7138c

View File

@ -69,7 +69,7 @@ class DatabaseManager:
class PingPongBot: class PingPongBot:
def __init__(self, config_path="config/ping_pong_config.yaml"): def __init__(self, config_path="config/ping_pong_config.yaml"):
self.version = "1.3.4" self.version = "1.3.5"
with open(config_path, 'r') as f: with open(config_path, 'r') as f:
self.config = yaml.safe_load(f) self.config = yaml.safe_load(f)
@ -108,6 +108,7 @@ class PingPongBot:
self.status_msg = "Initializing..." self.status_msg = "Initializing..."
self.last_signal = None self.last_signal = None
self.start_time = datetime.now() self.start_time = datetime.now()
self.last_refresh_time = datetime.now()
self.console = Console() self.console = Console()
# Parameters # Parameters
@ -236,13 +237,13 @@ class PingPongBot:
logger.error(f"Trade Error: {e}") logger.error(f"Trade Error: {e}")
def generate_dashboard(self): def generate_dashboard(self):
"""Generates the dashboard layout without printing directly""" """Generates the dashboard layout"""
layout = Layout() layout = Layout()
layout.split_column( layout.split_column(
Layout(name="header", size=3), Layout(name="header", size=3),
Layout(name="indicators", size=7), Layout(name="indicators", size=7),
Layout(name="position", size=6), Layout(name="position", size=6),
Layout(name="footer", size=2) Layout(name="footer", size=3)
) )
# Header # Header
@ -269,7 +270,8 @@ class PingPongBot:
layout["position"].update(Panel(pos_table, title="[bold green]PORTFOLIO STATUS[/]")) layout["position"].update(Panel(pos_table, title="[bold green]PORTFOLIO STATUS[/]"))
# Footer # Footer
footer_text = f"Status: [bold blue]{self.status_msg}[/] | Last Signal: [bold yellow]{self.last_signal or 'N/A'}[/] | Last Candle: {self.last_candle_time or 'N/A'}" refresh_str = self.last_refresh_time.strftime("%H:%M:%S")
footer_text = f"Status: [bold blue]{self.status_msg}[/]\nLast Signal: [bold yellow]{self.last_signal or 'N/A'}[/] | Last Candle: {self.last_candle_time or 'N/A'} | [dim italic]Heartbeat: {refresh_str}[/]"
layout["footer"].update(Panel(footer_text)) layout["footer"].update(Panel(footer_text))
return layout return layout
@ -278,32 +280,41 @@ class PingPongBot:
await self.db.connect() await self.db.connect()
last_exchange_update = 0 last_exchange_update = 0
with Live(self.generate_dashboard(), refresh_per_second=2) as live: with Live(self.generate_dashboard(), refresh_per_second=1) as live:
while True: while True:
now = time.time() try:
# 1. Exchange Sync (15s) now = time.time()
if now - last_exchange_update >= 15: self.last_refresh_time = datetime.now()
await self.update_exchange_data()
last_exchange_update = now
# 2. DB Sync (5s) # 1. Exchange Sync (15s)
candles = await self.db.get_candles(self.db_symbol, self.db_interval, limit=100) if now - last_exchange_update >= 15:
if candles: await self.update_exchange_data()
latest = candles[0] last_exchange_update = now
if latest['time'] != self.last_candle_time:
df = pd.DataFrame(candles[::-1]) # 2. DB Sync (5s)
df = df.astype({'open': float, 'high': float, 'low': float, 'close': float, 'volume': float}) candles = await self.db.get_candles(self.db_symbol, self.db_interval, limit=100)
df = self.calculate_indicators(df) if candles:
signal = self.check_signals(df) latest = candles[0]
if signal: await self.execute_trade(signal) if latest['time'] != self.last_candle_time:
self.last_candle_time = latest['time'] df = pd.DataFrame(candles[::-1])
self.last_candle_price = latest['close'] df = df.astype({'open': float, 'high': float, 'low': float, 'close': float, 'volume': float})
self.status_msg = f"New Candle processed: {latest['time']}" df = self.calculate_indicators(df)
else: signal = self.check_signals(df)
self.status_msg = f"No candles found for {self.db_symbol} / {self.db_interval}" if signal: await self.execute_trade(signal)
self.last_candle_time = latest['time']
self.last_candle_price = latest['close']
self.status_msg = f"New Candle processed: {latest['time']}"
else:
self.status_msg = f"No candles found for {self.db_symbol} / {self.db_interval}"
# 3. Update Dashboard
live.update(self.generate_dashboard())
except Exception as e:
logger.exception(f"Loop Error: {e}")
self.status_msg = f"Error: {str(e)[:50]}"
live.update(self.generate_dashboard())
# 3. Update Dashboard
live.update(self.generate_dashboard())
await asyncio.sleep(5) await asyncio.sleep(5)
if __name__ == "__main__": if __name__ == "__main__":