diff --git a/src/__pycache__/main_ml.cpython-310.pyc b/src/__pycache__/main_ml.cpython-310.pyc index 7387957..83b811a 100644 Binary files a/src/__pycache__/main_ml.cpython-310.pyc and b/src/__pycache__/main_ml.cpython-310.pyc differ diff --git a/src/__pycache__/web_dashboard.cpython-310.pyc b/src/__pycache__/web_dashboard.cpython-310.pyc index 988e2ef..16f0335 100644 Binary files a/src/__pycache__/web_dashboard.cpython-310.pyc and b/src/__pycache__/web_dashboard.cpython-310.pyc differ diff --git a/src/dashboard_pnl.html b/src/dashboard_pnl.html new file mode 100644 index 0000000..f620317 --- /dev/null +++ b/src/dashboard_pnl.html @@ -0,0 +1 @@ +Bot P&L
Läd…
diff --git a/src/main_ml.py b/src/main_ml.py index 3a24db3..d43e79f 100644 --- a/src/main_ml.py +++ b/src/main_ml.py @@ -56,6 +56,11 @@ class TradingBot: self.trades_today = 0 self.last_trade_reset = None # -5% max + # Profit tracking + self.entry_price_history = {} # symbol -> entry price + self.closed_trades = [] # list of {symbol, entry, exit, profit_pct, profit_usdt} + self.session_start_balance = None + self.active_trades = {} self.daily_pnl = 0 self.paused = False @@ -539,3 +544,39 @@ if __name__ == '__main__': return True return False + + + def record_entry(self, pair, price, quantity): + """Record entry price for profit calculation""" + self.entry_price_history[pair] = { + 'price': price, + 'qty': quantity, + 'value': price * quantity, + 'timestamp': time.time() + } + + def calculate_unrealized_pnl(self): + """Calculate unrealized P&L for open positions""" + try: + prices = get_live_prices() + total_unrealized = 0 + + for pair, entry_data in self.entry_price_history.items(): + asset = pair.replace('USDT', '') + current_price = prices.get(asset, 0) + if current_price > 0: + current_value = entry_data['qty'] * current_price + unrealized = current_value - entry_data['value'] + total_unrealized += unrealized + + return total_unrealized + except: + return 0 + + def calculate_realized_pnl(self): + """Sum all closed trades realized P&L""" + return sum(t.get('profit_usdt', 0) for t in self.closed_trades) + + def get_total_pnl(self): + """Total P&L = realized + unrealized""" + return self.calculate_realized_pnl() + self.calculate_unrealized_pnl() diff --git a/src/web_dashboard.py b/src/web_dashboard.py index 753b2d9..e2920ee 100644 --- a/src/web_dashboard.py +++ b/src/web_dashboard.py @@ -578,6 +578,55 @@ setInterval(function() {{ return Response(content=html, media_type='text/html') + +@app.get('/api/pnl') +async def get_pnl(): + """Get live Profit & Loss (P&L) calculation""" + try: + account = binance.get_account() + + # Get current account value + prices = get_live_prices() + current_value = 0 + + for asset_data in account['balances']: + asset = asset_data['asset'] + total = float(asset_data['free']) + float(asset_data['locked']) + + if total > 0.00001 and asset != 'LDDOGE' and asset != 'LDBTTC': + price = prices.get(asset, 1.0) + current_value += total * price + + # Benchmark: Initial capital was $137.79 (before trading) + # This should be stored, but for now use a reference + initial_capital = 137.79 + + pnl_usdt = current_value - initial_capital + pnl_pct = (pnl_usdt / initial_capital * 100) if initial_capital > 0 else 0 + + # Get open trades for unrealized portion + state_file = '/home/marc/bot-deploy/trades.json' + open_trades = {} + if os.path.exists(state_file): + try: + data = json.load(state_file) + open_trades = data.get('current', {}) + except: + pass + + return { + 'current_value': round(current_value, 2), + 'initial_capital': initial_capital, + 'total_pnl_usdt': round(pnl_usdt, 2), + 'total_pnl_percent': round(pnl_pct, 2), + 'status': '🟢 PROFIT' if pnl_usdt > 0 else ('🔴 LOSS' if pnl_usdt < 0 else '⚪ BREAK'), + 'open_positions': len(open_trades), + 'timestamp': datetime.now().isoformat() + } + except Exception as e: + return {'error': str(e)} + + if __name__ == '__main__': import uvicorn uvicorn.run(app, host='0.0.0.0', port=7000)