feat: add heartbeat and robust error handling to main loop (v1.3.5)
This commit is contained in:
@ -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
|
# 1. Exchange Sync (15s)
|
||||||
|
if now - last_exchange_update >= 15:
|
||||||
|
await self.update_exchange_data()
|
||||||
|
last_exchange_update = now
|
||||||
|
|
||||||
|
# 2. DB Sync (5s)
|
||||||
|
candles = await self.db.get_candles(self.db_symbol, self.db_interval, limit=100)
|
||||||
|
if candles:
|
||||||
|
latest = candles[0]
|
||||||
|
if latest['time'] != self.last_candle_time:
|
||||||
|
df = pd.DataFrame(candles[::-1])
|
||||||
|
df = df.astype({'open': float, 'high': float, 'low': float, 'close': float, 'volume': float})
|
||||||
|
df = self.calculate_indicators(df)
|
||||||
|
signal = self.check_signals(df)
|
||||||
|
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())
|
||||||
|
|
||||||
# 2. DB Sync (5s)
|
|
||||||
candles = await self.db.get_candles(self.db_symbol, self.db_interval, limit=100)
|
|
||||||
if candles:
|
|
||||||
latest = candles[0]
|
|
||||||
if latest['time'] != self.last_candle_time:
|
|
||||||
df = pd.DataFrame(candles[::-1])
|
|
||||||
df = df.astype({'open': float, 'high': float, 'low': float, 'close': float, 'volume': float})
|
|
||||||
df = self.calculate_indicators(df)
|
|
||||||
signal = self.check_signals(df)
|
|
||||||
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())
|
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user