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
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)