Added basic paper-trader. Fix signals_health_client.py to support the multiple personalities.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Health Check Client for Signal Generator
|
||||
Health Check Client for Multi-Personality Signal Generator
|
||||
Query the running signal generator status
|
||||
"""
|
||||
|
||||
@@ -28,19 +28,61 @@ def check_health(socket_path="/tmp/signals_health.sock"):
|
||||
# Parse and display
|
||||
health = json.loads(response.decode('utf-8'))
|
||||
|
||||
print("=" * 60)
|
||||
print("SIGNAL GENERATOR HEALTH STATUS")
|
||||
print("=" * 60)
|
||||
print("=" * 70)
|
||||
print("MULTI-PERSONALITY SIGNAL GENERATOR HEALTH STATUS")
|
||||
print("=" * 70)
|
||||
print(f"Status: {health['status']}")
|
||||
print(f"Personality: {health['personality']}")
|
||||
print(f"Mode: {health.get('mode', 'single-personality')}")
|
||||
|
||||
# Handle both old single-personality and new multi-personality format
|
||||
if 'personalities' in health:
|
||||
print(f"Personalities: {', '.join(health['personalities'])}")
|
||||
elif 'personality' in health:
|
||||
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']}")
|
||||
print(f"Debug Mode: {'ON' if health.get('debug_mode') else 'OFF'}")
|
||||
|
||||
# Total stats (aggregated across all personalities)
|
||||
if 'total_stats' in health:
|
||||
total = health['total_stats']
|
||||
print(f"\nAGGREGATED STATISTICS:")
|
||||
print(f" Total Signals: {total['total_signals']}")
|
||||
print(f" - Buy: {total['buy_signals']}")
|
||||
print(f" - Sell: {total['sell_signals']}")
|
||||
print(f" Errors: {total['errors']}")
|
||||
else:
|
||||
# Fallback for old format
|
||||
print(f"\nSTATISTICS:")
|
||||
print(f" Total Signals: {health.get('total_signals', 0)}")
|
||||
print(f" - Buy: {health.get('buy_signals', 0)}")
|
||||
print(f" - Sell: {health.get('sell_signals', 0)}")
|
||||
print(f" Errors: {health.get('errors', 0)}")
|
||||
|
||||
# Per-personality breakdown (if available)
|
||||
if 'personality_stats' in health:
|
||||
print("\n" + "=" * 70)
|
||||
print("PER-PERSONALITY BREAKDOWN")
|
||||
print("=" * 70)
|
||||
|
||||
for personality, stats in health['personality_stats'].items():
|
||||
print(f"\n{personality.upper()}:")
|
||||
print(f" Total Signals: {stats['total_signals']}")
|
||||
print(f" - Buy: {stats['buy_signals']}")
|
||||
print(f" - Sell: {stats['sell_signals']}")
|
||||
print(f" Last Signal: {stats['last_signal'] or 'None'}")
|
||||
print(f" Errors: {stats['errors']}")
|
||||
|
||||
if stats.get('recent_signals'):
|
||||
print(f" Recent Signals:")
|
||||
for sig in stats['recent_signals'][:3]:
|
||||
print(f" [{sig['timeframe']}] {sig['signal']} @ ${sig['price']:.2f} "
|
||||
f"(conf: {sig['confidence']:.2f})")
|
||||
else:
|
||||
# Old format
|
||||
print(f" Last Signal: {health.get('last_signal') or 'None'}")
|
||||
|
||||
# Database Status
|
||||
print("\n" + "=" * 70)
|
||||
@@ -58,20 +100,22 @@ def check_health(socket_path="/tmp/signals_health.sock"):
|
||||
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}")
|
||||
age_str = f"{age}s ago" if age is not None else "N/A"
|
||||
status = "⚠ STALE" if age and age > 300 else ""
|
||||
print(f" [{tf}]: {info['count']} rows, latest: {age_str} {status}")
|
||||
|
||||
# Analysis DB
|
||||
analysis = db.get('analysis_db', {})
|
||||
print(f"Analysis DB: {'✓ OK' if analysis.get('accessible') else '✗ FAILED'}")
|
||||
print(f"\nAnalysis 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}")
|
||||
age_str = f"{age}s ago" if age is not None else "N/A"
|
||||
status = "⚠ STALE" if age and age > 300 else ""
|
||||
print(f" [{tf}]: {info['count']} rows, latest: {age_str} {status}")
|
||||
|
||||
# Configuration
|
||||
print("\n" + "=" * 70)
|
||||
@@ -81,21 +125,38 @@ def check_health(socket_path="/tmp/signals_health.sock"):
|
||||
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")
|
||||
print(f"Config Reloads: {cfg.get('reloads', 0)}")
|
||||
|
||||
if cfg.get('weights'):
|
||||
print(f"Weights:")
|
||||
for indicator, weight in cfg['weights'].items():
|
||||
print(f" {indicator:12s} {weight}")
|
||||
# Multi-personality format
|
||||
if isinstance(cfg['weights'], dict) and any(k in cfg['weights'] for k in ['scalping', 'swing']):
|
||||
for personality, weights in cfg['weights'].items():
|
||||
print(f"\n{personality.upper()} Weights:")
|
||||
for indicator, weight in weights.items():
|
||||
print(f" {indicator:12s} {weight}")
|
||||
else:
|
||||
# Single personality format
|
||||
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} "
|
||||
# Recent signals (all personalities combined)
|
||||
recent = health.get('recent_signals', [])
|
||||
if recent:
|
||||
print("\n" + "=" * 70)
|
||||
print("RECENT SIGNALS (ALL PERSONALITIES)")
|
||||
print("=" * 70)
|
||||
for sig in recent[:10]:
|
||||
personality_tag = f"[{sig.get('personality', '?').upper()}]"
|
||||
print(f" {personality_tag:12s} [{sig['timeframe']}] {sig['signal']} @ ${sig['price']:.2f} "
|
||||
f"(conf: {sig['confidence']:.2f})")
|
||||
print(f" Reasons: {', '.join(sig['reasons'])}")
|
||||
if sig.get('reasons'):
|
||||
reasons_str = ', '.join(sig['reasons'][:3])
|
||||
if len(sig['reasons']) > 3:
|
||||
reasons_str += f" (+{len(sig['reasons'])-3} more)"
|
||||
print(f" Reasons: {reasons_str}")
|
||||
|
||||
print("=" * 60)
|
||||
print("=" * 70)
|
||||
|
||||
return 0
|
||||
|
||||
@@ -106,8 +167,15 @@ def check_health(socket_path="/tmp/signals_health.sock"):
|
||||
except ConnectionRefusedError:
|
||||
print(f"Error: Connection refused at {socket_path}")
|
||||
return 1
|
||||
except KeyError as e:
|
||||
print(f"Error: Missing expected field in health response: {e}")
|
||||
print("\nRaw response:")
|
||||
print(json.dumps(health, indent=2))
|
||||
return 1
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user