Feature: 3h Performance Reports an Telegram + Obsidian (USDT, aktive Trades, Bot-Aktivität, Holdings)
This commit is contained in:
parent
503d2a8a0a
commit
3a65500c6b
|
|
@ -0,0 +1,213 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
3h Performance Report Generator
|
||||
Sammelt Metriken und sendet an Telegram + Obsidian
|
||||
"""
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
from binance.client import Client
|
||||
from dotenv import load_dotenv
|
||||
import requests
|
||||
|
||||
os.chdir('/home/marc/bot-deploy')
|
||||
load_dotenv()
|
||||
|
||||
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"""
|
||||
try:
|
||||
# Marc Telegram: 7646180954
|
||||
token = os.getenv('TELEGRAM_BOT_TOKEN')
|
||||
chat_id = 7646180954
|
||||
url = f'https://api.telegram.org/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:
|
||||
print(f"✅ Telegram Report versendet")
|
||||
return True
|
||||
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")
|
||||
|
||||
print("\n📤 Sende Reports...")
|
||||
|
||||
# Telegram
|
||||
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()
|
||||
Loading…
Reference in New Issue