from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse, FileResponse import uvicorn import logging import json import os import time from datetime import datetime from hype_bot import handle_signal, get_balance, get_position, telegram from hype_config import EXPECTED_TIMEFRAME app = FastAPI() # Logging logging.basicConfig( filename='/root/mpmbot/bot.log', level=logging.INFO, format='%(asctime)s - %(message)s' ) # Status Datei STATUS_FILE = '/root/mpmbot/hype_status.json' def read_status(): if os.path.exists(STATUS_FILE): with open(STATUS_FILE) as f: return json.load(f) return {"running": False, "paused": False, "position": None, "entry": None, "balance": 0, "heartbeat": None, "log": []} def write_status(data): with open(STATUS_FILE, 'w') as f: json.dump(data, f) def add_log(msg, type=''): s = read_status() s['log'] = [{"time": datetime.now().strftime('%H:%M:%S'), "msg": msg, "type": type}] + s.get('log', []) if len(s['log']) > 30: s['log'] = s['log'][:30] write_status(s) logging.info(msg) # Initialer Status if not os.path.exists(STATUS_FILE): write_status({"running": True, "paused": False, "position": None, "entry": None, "balance": 0, "heartbeat": datetime.now().isoformat(), "log": []}) else: s = read_status() s['running'] = True s['heartbeat'] = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S') + 'Z' from hype_bot import telegram telegram("HYPE Bot gestartet ✅") s['log'] = [] write_status(s) # ─── HEARTBEAT (alle 30s) ──────────────────────────────────── import threading def heartbeat_loop(): while True: try: s = read_status() if s.get('running'): s['heartbeat'] = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S') + 'Z' try: bal = get_balance() s['balance'] = bal except: pass try: pos = get_position() if pos: raw_side = pos.get('side', 'UNKNOWN').upper() if raw_side == 'BUY': s['position'] = 'LONG' elif raw_side == 'SELL': s['position'] = 'SHORT' else: s['position'] = raw_side s['entry'] = pos.get('avgOpenPrice', None) s['size'] = pos.get('qty', None) s['sl_price'] = pos.get('liqPrice', None) s['current_price'] = None entry = float(pos.get('avgOpenPrice', 0) or 0) size = float(pos.get('qty', 0) or 0) unr_pnl = float(pos.get('unrealizedPNL', 0) or 0) liq = pos.get('liqPrice', None) if entry > 0 and size > 0: s['pnl_usdt'] = round(unr_pnl, 4) margin = float(pos.get('margin', 1) or 1) s['pnl_pct'] = round((unr_pnl / margin) * 100, 2) if margin > 0 else 0 else: s['pnl_usdt'] = 0 s['pnl_pct'] = 0 s['liq_price'] = liq else: s['position'] = 'KEIN TRADE' s['entry'] = None s['size'] = None s['sl_price'] = None s['current_price'] = None s['pnl_usdt'] = 0 s['pnl_pct'] = 0 except: pass write_status(s) except: pass time.sleep(30) t = threading.Thread(target=heartbeat_loop, daemon=True) t.start() # ─── WEBHOOK ───────────────────────────────────────────────── @app.post("/hype") async def webhook(request: Request): data = await request.json() signal = data.get("signal", "UNKNOWN") symbol = data.get("symbol", "UNKNOWN") timeframe = data.get("timeframe", "UNKNOWN") price = data.get("price", "UNKNOWN") add_log(f"Signal: {signal} | {symbol} | TF: {timeframe} | Preis: {price}", "info") s = read_status() if not s.get('running') or s.get('paused'): add_log(f"Signal ignoriert (Bot gestoppt/pausiert)", "warn") return {"status": "ignored"} if timeframe == EXPECTED_TIMEFRAME and symbol == "HYPEUSDT": add_log(f"Signal wird ausgeführt: {signal}", "ok") telegram(f"Signal empfangen: {signal} | Timeframe: {timeframe}") handle_signal(signal) else: add_log(f"Signal ignoriert (TF: {timeframe}, Symbol: {symbol})", "warn") return {"status": "ok"} # ─── STATUS ────────────────────────────────────────────────── @app.get("/hype/status") async def status(): return read_status() # ─── CONTROL ───────────────────────────────────────────────── @app.post("/hype/control") async def control(request: Request): data = await request.json() action = data.get("action", "") s = read_status() if action == "stop": s['running'] = False s['paused'] = False write_status(s) add_log("Bot gestoppt", "warn") return {"status": "Bot gestoppt"} elif action == "start": s['running'] = True s['paused'] = False write_status(s) add_log("Bot gestartet", "ok") return {"status": "Bot gestartet"} elif action == "pause": s['paused'] = not s.get('paused', False) write_status(s) msg = "Bot pausiert" if s['paused'] else "Bot fortgesetzt" add_log(msg, "warn") return {"status": msg} return {"status": "Unbekannte Aktion"} # ─── PANEL ─────────────────────────────────────────────────── @app.get("/") async def panel(): panel_path = '/root/mpmbot/control_panel.html' if os.path.exists(panel_path): with open(panel_path) as f: return HTMLResponse(f.read()) return {"status": "Panel nicht gefunden"} if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=80)