diff --git a/src/web_dashboard.py b/src/web_dashboard.py index 87e4a96..7091fd3 100644 --- a/src/web_dashboard.py +++ b/src/web_dashboard.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 +"""Trading Bot Dashboard v0.5.1 (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 datetime import datetime -import json, os, time, sqlite3 +import json, os, time app = FastAPI() @@ -16,49 +18,318 @@ with open('/home/marc/bot-deploy/.env') as f: binance = Client(env.get('BINANCE_API_KEY_LIVE'), env.get('BINANCE_API_SECRET_LIVE')) DB = '/home/marc/bot-deploy/pnl_charts.db' -def get_chart_data(days=1): - conn = sqlite3.connect(DB) - rows = conn.execute(f"""SELECT ts, pv, pp FROM history WHERE ts > {int(time.time()) - days*86400} ORDER BY ts""").fetchall() - conn.close() - return [(datetime.fromtimestamp(r[0]).strftime('%H:%M'), r[2]) for r in rows] +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() -@app.get('/') -async def root(): - chart_1d = get_chart_data(1) - chart_7d = get_chart_data(7) - chart_30d = get_chart_data(30) - - html = f''' -Trading Bot v0.6 - -
-

🤖 Trading Bot v0.6

Contrarian Mean Reversion Strategy

- -

Analytics

-

1-Day Chart: {len(chart_1d)} points

-

7-Day Chart: {len(chart_7d)} points

-

30-Day Chart: {len(chart_30d)} points

-
- -
-
-
1D Performance
+{chart_1d[-1][1] if chart_1d else 0:.2f}%
-
7D Performance
+{chart_7d[-1][1] if chart_7d else 0:.2f}%
-
30D Performance
+{chart_30d[-1][1] if chart_30d else 0:.2f}%
-
-
- -
''' - return HTMLResponse(html) +init_db() @app.get('/api/state') async def state(): try: acc = binance.get_account() - portfolio = sum(float(b['free']) * (1.0 if b['asset']=='USDT' else 0) for b in acc['balances']) - return {'portfolio': portfolio, 'status': 'ok'} - except: - return {'error': 'failed'} + 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} + + 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() + + 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) + + 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.5.1 + + + + +
+ +
+

🤖 Trading Bot v0.5.1

P&L Analytics

+
● LOADING
+
+ +
+ + +
+ +
+
+
Portfolio
-
+
P&L
-
-
+
USDT
-
+
Trades
-
+
+ +
+

Holdings

+ +
+
+
+ +
+
+
📈 P&L Performance (Live)
+
+ + + +
+ +
+
+
Current
+- +- +
+
+
Min
+- +- +
+
+
Max
+- +- +
+
+
Avg
+- +- +
+
+
+
+ +
+ + + +""" + return HTMLResponse(content=html) if __name__ == '__main__': import uvicorn