116 lines
4.3 KiB
Python
Executable File
116 lines
4.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Health Check Client for Signal Generator
|
|
Query the running signal generator status
|
|
"""
|
|
|
|
import socket
|
|
import sys
|
|
import json
|
|
|
|
def check_health(socket_path="/tmp/signals_health.sock"):
|
|
"""Query signal generator health status"""
|
|
try:
|
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
sock.settimeout(5)
|
|
sock.connect(socket_path)
|
|
|
|
# Receive response
|
|
response = b""
|
|
while True:
|
|
chunk = sock.recv(4096)
|
|
if not chunk:
|
|
break
|
|
response += chunk
|
|
|
|
sock.close()
|
|
|
|
# Parse and display
|
|
health = json.loads(response.decode('utf-8'))
|
|
|
|
print("=" * 60)
|
|
print("SIGNAL GENERATOR HEALTH STATUS")
|
|
print("=" * 60)
|
|
print(f"Status: {health['status']}")
|
|
print(f"Personality: {health['personality']}")
|
|
print(f"Timeframes: {', '.join(health['timeframes'])}")
|
|
print(f"Uptime: {health['uptime_seconds']}s ({health['uptime_seconds']//60}m)")
|
|
print(f"Total Signals: {health['total_signals']}")
|
|
print(f" - Buy: {health['buy_signals']}")
|
|
print(f" - Sell: {health['sell_signals']}")
|
|
print(f"Last Signal: {health['last_signal'] or 'None'}")
|
|
print(f"Errors: {health['errors']}")
|
|
print(f"Connected Clients: {health['connected_clients']}")
|
|
|
|
# Database Status
|
|
print("\n" + "=" * 70)
|
|
print("DATABASE STATUS")
|
|
print("=" * 70)
|
|
|
|
db = health.get('databases', {})
|
|
|
|
# Candles DB
|
|
candles = db.get('candles_db', {})
|
|
print(f"Candles DB: {'✓ OK' if candles.get('accessible') else '✗ FAILED'}")
|
|
if candles.get('error'):
|
|
print(f" Error: {candles['error']}")
|
|
else:
|
|
print(f" Total Rows: {candles.get('row_count', 0)}")
|
|
for tf, info in candles.get('timeframes', {}).items():
|
|
age = info.get('age_seconds')
|
|
age_str = f"{age}s ago" if age else "N/A"
|
|
print(f" [{tf}]: {info['count']} rows, latest: {age_str}")
|
|
|
|
# Analysis DB
|
|
analysis = db.get('analysis_db', {})
|
|
print(f"Analysis DB: {'✓ OK' if analysis.get('accessible') else '✗ FAILED'}")
|
|
if analysis.get('error'):
|
|
print(f" Error: {analysis['error']}")
|
|
else:
|
|
print(f" Total Rows: {analysis.get('row_count', 0)}")
|
|
for tf, info in analysis.get('timeframes', {}).items():
|
|
age = info.get('age_seconds')
|
|
age_str = f"{age}s ago" if age else "N/A"
|
|
print(f" [{tf}]: {info['count']} rows, latest: {age_str}")
|
|
|
|
# Configuration
|
|
print("\n" + "=" * 70)
|
|
print("CONFIGURATION")
|
|
print("=" * 70)
|
|
cfg = health.get('config', {})
|
|
print(f"Min Confidence: {cfg.get('min_confidence', 'N/A')}")
|
|
print(f"Cooldown: {cfg.get('cooldown_seconds', 'N/A')}s")
|
|
print(f"Lookback: {cfg.get('lookback', 'N/A')} candles")
|
|
if cfg.get('weights'):
|
|
print(f"Weights:")
|
|
for indicator, weight in cfg['weights'].items():
|
|
print(f" {indicator:12s} {weight}")
|
|
|
|
if health['recent_signals']:
|
|
print("\n" + "=" * 60)
|
|
print("RECENT SIGNALS")
|
|
print("=" * 60)
|
|
for sig in health['recent_signals']:
|
|
print(f" [{sig['timeframe']}] {sig['signal']} @ ${sig['price']:.2f} "
|
|
f"(conf: {sig['confidence']:.2f})")
|
|
print(f" Reasons: {', '.join(sig['reasons'])}")
|
|
|
|
print("=" * 60)
|
|
|
|
return 0
|
|
|
|
except FileNotFoundError:
|
|
print(f"Error: Socket not found at {socket_path}")
|
|
print("Is the signal generator running?")
|
|
return 1
|
|
except ConnectionRefusedError:
|
|
print(f"Error: Connection refused at {socket_path}")
|
|
return 1
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
return 1
|
|
|
|
if __name__ == "__main__":
|
|
socket_path = sys.argv[1] if len(sys.argv) > 1 else "/tmp/signals_health.sock"
|
|
sys.exit(check_health(socket_path))
|