diff --git a/src/api_verifier.py b/src/api_verifier.py new file mode 100755 index 0000000..fcff3d1 --- /dev/null +++ b/src/api_verifier.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +""" +REAL-TIME API Verification Dashboard +Polls Binance every 30 seconds, compares bot state vs actual portfolio. +Alerts on discrepancies IMMEDIATELY. +""" +import os +import json +import time +from datetime import datetime +from binance.client import Client +from dotenv import load_dotenv + +os.chdir('/home/marc/bot-deploy') +load_dotenv() + +client = Client(os.getenv('BINANCE_API_KEY_LIVE'), os.getenv('BINANCE_API_SECRET_LIVE')) +TRACKED_ASSETS = {'USDT', 'BTC', 'ETH', 'BNB', 'XRP', 'SOL'} +POLL_INTERVAL = 30 # seconds + +def verify_state(): + """Compare bot state vs Binance reality""" + try: + # Get Binance truth + acc = client.get_account() + binance_balances = {b['asset']: float(b['free']) + float(b['locked']) for b in acc['balances'] if float(b['free']) + float(b['locked']) > 0} + tracked_binance = {k: v for k, v in binance_balances.items() if k in TRACKED_ASSETS} + + # Get bot state + try: + with open('/home/marc/bot-deploy/active_trades.json') as f: + bot_state = json.load(f) + bot_trades = bot_state.get('active_trades', {}) + except: + bot_trades = {} + + # Compare + timestamp = datetime.now().strftime("%H:%M:%S") + + # Check 1: Trade count match + holdings_count = len({k: v for k, v in tracked_binance.items() if k != 'USDT' and v > 0.0001}) + bot_count = len(bot_trades) + + if holdings_count != bot_count: + print(f"šŸ”“ {timestamp} MISMATCH: Holdings={holdings_count} vs Bot={bot_count}") + return False + + # Check 2: USDT consistency + usdt_binance = tracked_binance.get('USDT', 0) + print(f"āœ… {timestamp} Synced: {holdings_count} trades | USDT: ${usdt_binance:.2f}") + return True + + except Exception as e: + print(f"šŸ”“ {datetime.now().strftime('%H:%M:%S')} ERROR: {e}") + return False + +def main(): + print("🟢 Real-Time API Verification Dashboard (updating every 30s)") + print("="*70) + + while True: + verify_state() + time.sleep(POLL_INTERVAL) + +if __name__ == '__main__': + main() diff --git a/src/live_status.py b/src/live_status.py new file mode 100755 index 0000000..8553aee --- /dev/null +++ b/src/live_status.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +""" +Live Status Reporter — Always fresh data from Binance API + Bot State +No caching, no stale data. Real-time updates. +""" +import os +import json +import time +from datetime import datetime +from binance.client import Client +from dotenv import load_dotenv + +os.chdir('/home/marc/bot-deploy') +load_dotenv() + +client = Client(os.getenv('BINANCE_API_KEY_LIVE'), os.getenv('BINANCE_API_SECRET_LIVE')) + +# Bot's tracked symbols +TRACKED_ASSETS = {'USDT', 'BTC', 'ETH', 'BNB', 'XRP', 'SOL'} + +def get_live_data(): + """Fetch ALWAYS FRESH data from Binance""" + try: + print(f'\nšŸ“Š LIVE DATA @ {datetime.now().strftime("%H:%M:%S CET")}') + print('='*70) + + # 1. Account balance (FRESH from API) + acc = client.get_account() + balances = {b['asset']: float(b['free']) + float(b['locked']) for b in acc['balances'] if float(b['free']) + float(b['locked']) > 0} + + # Filter to ONLY tracked assets + tracked_balances = {asset: qty for asset, qty in balances.items() if asset in TRACKED_ASSETS and qty > 0.0001} + + usdt = tracked_balances.get('USDT', 0) + usdt_free = sum(float(b['free']) for b in acc['balances'] if b['asset'] == 'USDT') + usdt_locked = sum(float(b['locked']) for b in acc['balances'] if b['asset'] == 'USDT') + + print(f'USDT Total: ${usdt:.2f} (Free: ${usdt_free:.2f} | Locked: ${usdt_locked:.2f})') + + # 2. Holdings (ONLY tracked coins) + holdings = {k: v for k, v in tracked_balances.items() if k != 'USDT'} + + if holdings: + print(f'\nActive Holdings:') + for asset, qty in sorted(holdings.items()): + print(f' {asset}: {qty:.8f}') + else: + print('Active Holdings: NONE') + + # 3. Open orders (FRESH) + orders = client.get_open_orders() + print(f'\nOpen Orders (Pending): {len(orders)}') + for o in orders: + print(f' - {o["symbol"]}: {o["side"]} {o["origQty"]} @ {o["price"]}') + + # 4. Bot state (active_trades.json) + try: + with open('/home/marc/bot-deploy/active_trades.json') as f: + bot_state = json.load(f) + print(f'\nBot Active Trades: {bot_state.get("count", 0)}') + for symbol, trade in bot_state.get('active_trades', {}).items(): + print(f' - {symbol}: {trade["qty"]:.8f} @ {trade["entry_price"]:.2f}') + except Exception as e: + print(f'Bot State: ERROR - {e}') + bot_state = {} + + # 5. Verification + print('\nāœ… VERIFICATION:') + if len(holdings) == bot_state.get('count', 0): + print(f' āœ… Holdings ({len(holdings)}) matches Bot ({bot_state.get("count")}) āœ…') + else: + print(f' āš ļø MISMATCH: Holdings={len(holdings)} vs Bot={bot_state.get("count")}') + + # 6. Check for garbage/orphaned coins + garbage = {k: v for k, v in balances.items() if k not in TRACKED_ASSETS and v > 0.0001} + if garbage: + print(f'\nāš ļø GARBAGE/ORPHANED COINS:') + for asset, qty in sorted(garbage.items()): + print(f' {asset}: {qty:.8f} (not tracked by bot)') + + print('='*70) + + except Exception as e: + print(f'ERROR: {e}') + +if __name__ == '__main__': + get_live_data()