#!/usr/bin/env python3 """ 3h Performance Report Generator Sammelt Metriken und sendet an Telegram (bizMark Trading Bot) + Obsidian """ import os import json import sys from datetime import datetime, timedelta from binance.client import Client from dotenv import load_dotenv import requests # Wechsel ins Arbeitsverzeichnis BEVOR load_dotenv() sys.path.insert(0, '/home/marc/bot-deploy') os.chdir('/home/marc/bot-deploy') # Lade .env load_dotenv('/home/marc/bot-deploy/.env') client = Client(os.getenv('BINANCE_API_KEY_LIVE'), os.getenv('BINANCE_API_SECRET_LIVE')) def get_performance_metrics(): """Sammelt alle Metriken für Report""" try: # 1. Portfolio-Status acc = client.get_account() balances = {b['asset']: float(b['free']) + float(b['locked']) for b in acc['balances'] if float(b['free']) + float(b['locked']) > 0} usdt_total = balances.get('USDT', 0) # 2. Bot-Status try: with open('/home/marc/bot-deploy/active_trades.json') as f: bot_state = json.load(f) active_trades = bot_state.get('active_trades', {}) trades_count = bot_state.get('count', 0) except: active_trades = {} trades_count = 0 # 3. Berechne Positionen holdings = len([k for k in balances.keys() if k not in ['USDT'] and balances[k] > 0.0001]) # 4. Berechne durchschnittlichen Entry Price if active_trades: total_locked = sum(float(t['qty']) * float(t['entry_price']) for t in active_trades.values()) avg_entry = total_locked / max(len(active_trades), 1) else: total_locked = 0 avg_entry = 0 # 5. Bot Logs lesen (letzte 3h) import subprocess try: logs_result = subprocess.run( ['journalctl', '-u', 'trading-bot.service', '--since', '3 hours ago', '--no-pager'], capture_output=True, text=True, timeout=5 ) logs = logs_result.stdout cycle_count = logs.count('CYCLE START') buy_count = logs.count('BUY') sell_count = logs.count('SELL') except: cycle_count = 0 buy_count = 0 sell_count = 0 # 6. Zusammenfassung return { 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S CET'), 'usdt_free': usdt_total, 'active_positions': trades_count, 'holdings_count': holdings, 'cycles_3h': cycle_count, 'buys_3h': buy_count, 'sells_3h': sell_count, 'active_trades': active_trades, 'total_portfolio_locked': total_locked } except Exception as e: return {'error': str(e)} def format_telegram_report(metrics): """Formatiert Report für Telegram""" if 'error' in metrics: return f"❌ Report-Fehler: {metrics['error']}" report = f"""📊 **3h Performance Report** Zeitstempel: {metrics['timestamp']} 💰 **Portfolio:** USDT verfügbar: ${metrics['usdt_free']:.2f} Portfolio gesperrt: ${metrics['total_portfolio_locked']:.2f} 📈 **Positionen:** Aktive Trades: {metrics['active_positions']} Holdings-Coins: {metrics['holdings_count']} 🔄 **Bot-Aktivität (letzte 3h):** Zyklen durchgeführt: {metrics['cycles_3h']} Käufe: {metrics['buys_3h']} Verkäufe: {metrics['sells_3h']} 🎯 **Aktive Trades:** """ if metrics['active_trades']: for symbol, trade in sorted(metrics['active_trades'].items()): report += f" • {symbol}: {trade['qty']:.8f} @ {trade['entry_price']:.2f}\n" else: report += " (keine)\n" return report def format_obsidian_report(metrics): """Formatiert Report für Obsidian""" if 'error' in metrics: return f"## Report-Fehler\n{metrics['error']}" report = f"""## {metrics['timestamp']} **Portfolio:** - USDT verfügbar: ${metrics['usdt_free']:.2f} - Portfolio gesperrt: ${metrics['total_portfolio_locked']:.2f} **Positionen:** - Aktive Trades: {metrics['active_positions']} - Holdings: {metrics['holdings_count']} **Bot-Aktivität (3h):** - Zyklen: {metrics['cycles_3h']} - Käufe: {metrics['buys_3h']} - Verkäufe: {metrics['sells_3h']} **Trades:** """ if metrics['active_trades']: for symbol, trade in sorted(metrics['active_trades'].items()): report += f"- {symbol}: {trade['qty']:.8f} @ {trade['entry_price']:.2f}\n" else: report += "- (keine)\n" return report def send_telegram_report(message): """Sendet Report an Telegram via bizMark Trading Bot""" try: bot_token = os.getenv('TELEGRAM_BOT_TOKEN') chat_id = os.getenv('TELEGRAM_CHAT_ID') if not bot_token or not chat_id: print("❌ Telegram Credentials nicht gefunden in .env") return False # Telegram Bot API url = f'https://api.telegram.org/bot{bot_token}/sendMessage' payload = { 'chat_id': chat_id, 'text': message, 'parse_mode': 'Markdown' } response = requests.post(url, json=payload, timeout=10) if response.status_code == 200: result = response.json() if result.get('ok'): print(f"✅ Telegram Report versendet (Message ID: {result['result']['message_id']})") return True else: print(f"❌ Telegram-API-Fehler: {result.get('description')}") return False else: print(f"❌ HTTP-Fehler: {response.status_code}") return False except Exception as e: print(f"❌ Telegram-Fehler: {e}") return False def append_obsidian_report(message): """Hängt Report an Obsidian Session-Datei an""" try: report_file = '/home/marc/bot-deploy/obsidian_3h_reports.md' # Erstelle Datei wenn nicht vorhanden if not os.path.exists(report_file): header = """--- tags: [3h-reports, performance, tracking] --- # 3h Performance Reports """ with open(report_file, 'w') as f: f.write(header) # Füge Report an with open(report_file, 'a') as f: f.write(message + '\n\n') print(f"✅ Obsidian Report geschrieben") return True except Exception as e: print(f"❌ Obsidian-Fehler: {e}") return False def main(): print("🔄 Sammle Performance-Metriken...") metrics = get_performance_metrics() if 'error' not in metrics: print(f" ✅ {metrics['active_positions']} aktive Trades") print(f" ✅ ${metrics['usdt_free']:.2f} USDT verfügbar") else: print(f" ❌ Fehler: {metrics['error']}") print("\n📤 Sende Reports...") # Telegram via bizMark Trading Bot tg_msg = format_telegram_report(metrics) send_telegram_report(tg_msg) # Obsidian obs_msg = format_obsidian_report(metrics) append_obsidian_report(obs_msg) print("\n✅ Reports versendet!") if __name__ == '__main__': main()