diff --git a/src/web_dashboard.py b/src/web_dashboard.py
index f897bff..6516272 100644
--- a/src/web_dashboard.py
+++ b/src/web_dashboard.py
@@ -1,141 +1,336 @@
-"""Trading Bot Dashboard v0.6 (Contrarian Mean Reversion) - Auto-load 1-Day chart on page load"""
-import os, json, logging, sqlite3
-from datetime import datetime, timedelta
-from flask import Flask, render_template_string, jsonify
+#!/usr/bin/env python3
+"""Trading Bot Dashboard v0.6 (RSI + Bollinger Bands HYBRID) - Auto-load 1-Day chart on page load"""
+import sqlite3
+from fastapi import FastAPI
+from fastapi.responses import HTMLResponse
from binance.client import Client
-from dotenv import load_dotenv
+from datetime import datetime
+import json, os, time
-load_dotenv()
-API_KEY = os.getenv('BINANCE_API_KEY_LIVE')
-API_SECRET = os.getenv('BINANCE_API_SECRET_LIVE')
-client = Client(API_KEY, API_SECRET)
+app = FastAPI()
-app = Flask(__name__)
+env = {}
+with open('/home/marc/bot-deploy/.env') as f:
+ for line in f:
+ k, _, v = line.partition('=')
+ env[k.strip()] = v.strip()
-@app.route('/')
-def dashboard():
- html = """
-
-
-
- Trading Bot v0.6
-
-
-
-
-
-
-
-
-
-
-
-
Active Trades
-
- | Symbol | Qty | Entry Price | Entry Time |
-
-
-
-
-
-
-
- """
- return render_template_string(html)
+binance = Client(env.get('BINANCE_API_KEY_LIVE'), env.get('BINANCE_API_SECRET_LIVE'))
+DB = '/home/marc/bot-deploy/pnl_charts.db'
-@app.route('/api/state')
-def api_state():
+def init_db():
+ c = sqlite3.connect(DB).cursor()
+ c.execute("""CREATE TABLE IF NOT EXISTS history (ts INTEGER PRIMARY KEY, pv REAL, pu REAL, pp REAL, uf REAL, ap INTEGER)""")
+ sqlite3.connect(DB).commit()
+
+init_db()
+
+@app.get('/api/state')
+async def state():
try:
- with open('/home/marc/bot-deploy/active_trades.json') as f:
- trades_data = json.load(f)
+ acc = binance.get_account()
+ bal = {}
+ for a in acc['balances']:
+ ast, free, locked = a['asset'], float(a['free']), float(a['locked'])
+ if free + locked > 1e-5:
+ bal[ast] = {'free': free, 'locked': locked, 'total': free + locked}
- return jsonify({
- 'active_trades': trades_data.get('active_trades', {}),
- 'active_positions': trades_data.get('count', 0),
- 'portfolio_value': trades_data.get('portfolio_value', 0),
- 'pnl_pct': 0, # Fetched from DB
- 'pnl_usdt': 0
- })
- except:
- return jsonify({'error': 'No data'}), 404
-
-@app.route('/api/pnl-history')
-def api_pnl_history():
- try:
- conn = sqlite3.connect('/home/marc/bot-deploy/pnl_charts.db')
- rows = conn.execute('SELECT pp FROM history ORDER BY ts DESC LIMIT 1').fetchall()
+ prices = {'USDT': 1.0}
+ for p in ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT']:
+ try:
+ t = binance.get_ticker(symbol=p)
+ prices[p.replace('USDT', '')] = float(t['lastPrice'])
+ except: pass
+
+ pv = sum(bal.get(a, {}).get('total', 0) * prices.get(a, 0) for a in ['BTC', 'ETH', 'SOL', 'BNB', 'XRP', 'USDT'])
+ uf = bal.get('USDT', {}).get('free', 0)
+ # Get latest P&L from database
+ try:
+ conn = sqlite3.connect('/home/marc/bot-deploy/pnl_charts.db')
+ row = conn.execute('SELECT pu, pp FROM history ORDER BY ts DESC LIMIT 1').fetchone()
+ conn.close()
+ if row:
+ pu, pp = row[0], row[1]
+ else:
+ pu, pp = 0.0, 0.0
+ except:
+ pu, pp = 0.0, 0.0
+
+ ap = 0
+ try:
+ with open('/home/marc/bot-deploy/active_trades.json') as f:
+ ap = json.load(f).get('count', 0)
+ except: pass
+
+ conn = sqlite3.connect(DB)
+ conn.execute("INSERT OR REPLACE INTO history VALUES (?, ?, ?, ?, ?, ?)", (int(time.time()), pv, pu, pp, uf, ap))
+ conn.commit()
conn.close()
- if rows:
- return jsonify({'current_pct': rows[0][0], 'current_usdt': 0, 'entries': []})
+ return {'portfolio_value': round(pv, 2), 'pnl_usdt': round(pu, 2), 'pnl_pct': round(pp, 2), 'usdt_free': round(uf, 2), 'active_positions': ap, 'balance': bal, 'prices': prices}
+ except Exception as e:
+ return {'error': str(e)}
+
+@app.get('/api/pnl-history')
+async def history(hours: int = 24):
+ conn = sqlite3.connect(DB)
+ cutoff = int(time.time()) - hours * 3600
+ rows = conn.execute("SELECT ts, pp, pu FROM history WHERE ts > ? ORDER BY ts", (cutoff,)).fetchall()
+ conn.close()
+
+ ts_list, pcts, usdts = [], [], []
+ seen_ts = set()
+
+ for t, p, u in rows:
+ dt = datetime.fromtimestamp(t)
- return jsonify({'current_pct': 0, 'current_usdt': 0, 'entries': []})
- except:
- return jsonify({'error': 'No data'}), 404
+ if hours <= 24:
+ ts = dt.strftime('%H:00')
+ else:
+ ts = dt.strftime('%d.%m.%y')
+
+ if ts in seen_ts:
+ continue
+
+ seen_ts.add(ts)
+ ts_list.append(ts)
+ pcts.append(round(p, 2))
+ usdts.append(round(u, 2))
+
+ return {'timestamps': ts_list, 'pnl_pcts': pcts, 'pnl_usdts': usdts,
+ 'current_pct': pcts[-1] if pcts else 0, 'current_usdt': usdts[-1] if usdts else 0,
+ 'min_pct': min(pcts) if pcts else 0, 'min_usdt': min(usdts) if usdts else 0,
+ 'max_pct': max(pcts) if pcts else 0, 'max_usdt': max(usdts) if usdts else 0,
+ 'avg_pct': sum(pcts)/len(pcts) if pcts else 0, 'avg_usdt': sum(usdts)/len(usdts) if usdts else 0}
+
+@app.get('/')
+async def dashboard():
+ html = """
+
+
+
+
+Trading Bot v0.6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
📈 P&L Performance (Live)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+ return HTMLResponse(content=html)
if __name__ == '__main__':
- app.run(host='0.0.0.0', port=7000, debug=False)
+ import uvicorn
+ uvicorn.run(app, host='0.0.0.0', port=7000)