Spaces:
Running
Running
Deploy Aureon OS (deploy/selfhost stack: nginx edge + fusion API x2 + console + HNC organ + redis + postgres; paper mode) (part 19)
da0ce7b verified Download scripts/python/quick_profit_check.py from GaryLeckey/aureon-os: direct link, hf CLI and curl.
- Browser
- Download file 29.9 kB
-
https://huggingface.co/spaces/GaryLeckey/aureon-os/resolve/main/scripts/python/quick_profit_check.py
- Command line
-
hf download hf://spaces/GaryLeckey/aureon-os/scripts/python/quick_profit_check.py
-
curl -L -o quick_profit_check.py https://huggingface.co/spaces/GaryLeckey/aureon-os/resolve/main/scripts/python/quick_profit_check.py
29.9 kB
| #!/usr/bin/env python | |
| """Quick live position and profit monitor.""" | |
| import sys | |
| import json | |
| import time | |
| import tempfile | |
| import os | |
| from pathlib import Path | |
| from typing import Dict, Any | |
| sys.path.insert(0, '/workspaces/aureon-trading') | |
| from alpaca_client import AlpacaClient | |
| from kraken_client import KrakenClient, get_kraken_client | |
| from binance_client import BinanceClient, get_binance_client | |
| # Try to import Thought Bus for Queen integration | |
| try: | |
| from aureon_thought_bus import ThoughtBus, THOUGHT_BUS_AVAILABLE | |
| except: | |
| THOUGHT_BUS_AVAILABLE = False | |
| PROFIT_STATE_FILE = "live_profit_state.json" | |
| BALANCE_SNAPSHOT_FILE = "_pre_trade_balance_snapshot.json" | |
| def load_cost_basis(): | |
| """Load cost basis history.""" | |
| if Path('cost_basis_history.json').exists(): | |
| with open('cost_basis_history.json') as f: | |
| data = json.load(f) | |
| return data.get('positions', {}) | |
| return {} | |
| def get_current_price(exchange, symbol): | |
| """Get current price for a symbol.""" | |
| try: | |
| if exchange == 'kraken': | |
| client = get_kraken_client() | |
| ticker = client.get_ticker(symbol + 'USD') | |
| return float(ticker.get('last', 0)) | |
| elif exchange == 'binance': | |
| client = get_binance_client() | |
| ticker = client.get_ticker_price(symbol + 'USDT') | |
| return float(ticker.get('price', 0)) | |
| except: | |
| return 0 | |
| def save_balance_snapshot() -> Dict[str, Any]: | |
| """ | |
| Save a complete balance snapshot across ALL 3 exchanges. | |
| Uses atomic write (tmp + rename) to prevent corruption. | |
| Called before any trade cycle begins and after each cycle ends. | |
| """ | |
| snapshot = { | |
| "timestamp": time.time(), | |
| "datetime": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), | |
| "exchanges": {} | |
| } | |
| total_usd = 0.0 | |
| # ββ Kraken ββ | |
| try: | |
| kraken = get_kraken_client() | |
| balances = kraken.get_balance() | |
| kraken_bal = {} | |
| if balances: | |
| for asset, amount in balances.items(): | |
| if amount > 0.0: | |
| kraken_bal[asset] = amount | |
| snapshot["exchanges"]["kraken"] = {"balances": kraken_bal} | |
| except Exception as e: | |
| snapshot["exchanges"]["kraken"] = {"error": str(e)} | |
| # ββ Alpaca ββ | |
| try: | |
| alpaca = AlpacaClient() | |
| account = alpaca.get_account() | |
| positions = alpaca.get_positions() | |
| alpaca_bal = { | |
| "cash": float(account.get("cash", 0)), | |
| "portfolio_value": float(account.get("portfolio_value", 0)), | |
| } | |
| if positions: | |
| for pos in positions: | |
| alpaca_bal[pos["symbol"]] = { | |
| "qty": float(pos["qty"]), | |
| "market_value": float(pos["market_value"]), | |
| "avg_entry_price": float(pos["avg_entry_price"]), | |
| "current_price": float(pos["current_price"]), | |
| } | |
| snapshot["exchanges"]["alpaca"] = {"balances": alpaca_bal} | |
| total_usd += alpaca_bal["portfolio_value"] | |
| except Exception as e: | |
| snapshot["exchanges"]["alpaca"] = {"error": str(e)} | |
| # ββ Binance (was MISSING β this is the key fix) ββ | |
| try: | |
| binance = get_binance_client() | |
| balances = binance.get_balance() if binance else {} | |
| binance_bal = {} | |
| if balances: | |
| for asset, amount in balances.items(): | |
| if amount > 0.0: | |
| binance_bal[asset] = amount | |
| snapshot["exchanges"]["binance"] = {"balances": binance_bal} | |
| except Exception as e: | |
| snapshot["exchanges"]["binance"] = {"error": str(e)} | |
| snapshot["total_estimated_usd"] = total_usd # Rough β Kraken/Binance need pricing | |
| # Atomic write: temp file β rename | |
| try: | |
| fd, tmp_path = tempfile.mkstemp(dir=".", suffix=".tmp", prefix="_snap_") | |
| with os.fdopen(fd, 'w') as f: | |
| json.dump(snapshot, f, indent=2) | |
| os.replace(tmp_path, BALANCE_SNAPSHOT_FILE) | |
| except Exception as e: | |
| print(f"β οΈ Failed to write balance snapshot: {e}") | |
| return snapshot | |
| def get_portfolio_snapshot() -> Dict[str, Any]: | |
| """ | |
| Get a structured snapshot of the entire portfolio across all exchanges. | |
| Returns dict with exchange data that Queen/Orca can consume. | |
| """ | |
| snapshot = { | |
| "timestamp": time.time(), | |
| "exchanges": {}, | |
| "totals": { | |
| "total_value_usd": 0, | |
| "total_pnl_usd": 0, | |
| "positions_count": 0, | |
| "profitable_count": 0 | |
| } | |
| } | |
| cost_basis = load_cost_basis() | |
| # Alpaca | |
| try: | |
| alpaca = AlpacaClient() | |
| positions = alpaca.get_positions() | |
| alpaca_data = { | |
| "positions": [], | |
| "total_value": 0, | |
| "total_pnl": 0, | |
| "count": len(positions) if positions else 0 | |
| } | |
| if positions: | |
| for pos in positions: | |
| pnl = float(pos['unrealized_pl']) | |
| value = float(pos['market_value']) | |
| alpaca_data["positions"].append({ | |
| "symbol": pos['symbol'], | |
| "qty": float(pos['qty']), | |
| "entry_price": float(pos['avg_entry_price']), | |
| "current_price": float(pos['current_price']), | |
| "value": value, | |
| "pnl": pnl, | |
| "pnl_pct": float(pos['unrealized_plpc']) * 100 | |
| }) | |
| alpaca_data["total_value"] += value | |
| alpaca_data["total_pnl"] += pnl | |
| if pnl > 0: | |
| snapshot["totals"]["profitable_count"] += 1 | |
| snapshot["exchanges"]["alpaca"] = alpaca_data | |
| snapshot["totals"]["total_value_usd"] += alpaca_data["total_value"] | |
| snapshot["totals"]["total_pnl_usd"] += alpaca_data["total_pnl"] | |
| snapshot["totals"]["positions_count"] += alpaca_data["count"] | |
| except Exception as e: | |
| snapshot["exchanges"]["alpaca"] = {"error": str(e)} | |
| # Kraken | |
| try: | |
| kraken = get_kraken_client() | |
| balances = kraken.get_balance() | |
| ledgers = kraken.get_ledgers() | |
| kraken_data = { | |
| "positions": [], | |
| "total_value_usd": 0, | |
| "total_pnl_usd": 0, | |
| "count": 0, | |
| "profitable_count": 0 | |
| } | |
| if balances: | |
| # Fetch all tickers once | |
| all_tickers = kraken.get_24h_tickers() | |
| price_lookup = {} | |
| for ticker in all_tickers: | |
| symbol = ticker['symbol'] | |
| price = float(ticker.get('lastPrice', 0)) | |
| for quote in ['USD', 'EUR', 'GBP', 'USDT', 'USDC']: | |
| if symbol.endswith(quote): | |
| base = symbol[:-len(quote)] | |
| if base not in price_lookup or quote == 'USD': | |
| price_lookup[base] = {'price': price, 'quote': quote} | |
| break | |
| # Process ledgers for cost basis | |
| trades_by_ref = {} | |
| if ledgers and 'ledger' in ledgers: | |
| for ledger_id, entry in ledgers['ledger'].items(): | |
| if entry['type'] == 'trade': | |
| refid = entry['refid'] | |
| if refid not in trades_by_ref: | |
| trades_by_ref[refid] = [] | |
| trades_by_ref[refid].append(entry) | |
| kraken_cost_basis = {} | |
| for refid, entries in trades_by_ref.items(): | |
| if len(entries) == 2: | |
| entry1, entry2 = entries | |
| asset_entry = None | |
| currency_entry = None | |
| if entry1['asset'].startswith('Z'): | |
| currency_entry = entry1 | |
| asset_entry = entry2 | |
| elif entry2['asset'].startswith('Z'): | |
| currency_entry = entry2 | |
| asset_entry = entry1 | |
| elif entry1['asset'] in ['XXBT', 'XETH'] and entry2['asset'] not in ['XXBT', 'XETH']: | |
| currency_entry = entry1 | |
| asset_entry = entry2 | |
| elif entry2['asset'] in ['XXBT', 'XETH'] and entry1['asset'] not in ['XXBT', 'XETH']: | |
| currency_entry = entry2 | |
| asset_entry = entry1 | |
| else: | |
| if abs(float(entry1['amount'])) > abs(float(entry2['amount'])): | |
| currency_entry = entry1 | |
| asset_entry = entry2 | |
| else: | |
| currency_entry = entry2 | |
| asset_entry = entry1 | |
| if asset_entry and currency_entry: | |
| asset = asset_entry['asset'] | |
| if asset.startswith('X') and len(asset) > 4: | |
| asset = asset[1:] | |
| if asset.startswith('Z') and len(asset) > 4: | |
| asset = asset[1:] | |
| if asset.endswith('.d'): | |
| asset = asset[:-2] | |
| amount_bought = abs(float(asset_entry['amount'])) | |
| cost = abs(float(currency_entry['amount'])) | |
| if amount_bought > 0: | |
| if asset not in kraken_cost_basis: | |
| kraken_cost_basis[asset] = {'total_cost': 0, 'total_amount': 0} | |
| kraken_cost_basis[asset]['total_cost'] += cost | |
| kraken_cost_basis[asset]['total_amount'] += amount_bought | |
| for symbol, balance in balances.items(): | |
| if balance > 0.001: # Skip dust | |
| lookup_symbol = symbol | |
| if symbol.startswith('X') and len(symbol) > 4: | |
| lookup_symbol = symbol[1:] | |
| if symbol.startswith('Z') and len(symbol) > 4: | |
| lookup_symbol = symbol[1:] | |
| if symbol.endswith('.d'): | |
| lookup_symbol = symbol[:-2] | |
| price_data = price_lookup.get(lookup_symbol) | |
| cost_data = kraken_cost_basis.get(lookup_symbol) | |
| if price_data and price_data['price'] > 0: | |
| current_price = price_data['price'] | |
| value = balance * current_price | |
| entry_price = 0 | |
| pnl = 0 | |
| is_free = False | |
| if cost_data and cost_data['total_amount'] > 0: | |
| entry_price = cost_data['total_cost'] / cost_data['total_amount'] | |
| pnl = balance * (current_price - entry_price) | |
| else: | |
| is_free = True | |
| pnl = value # All value is profit for airdrops | |
| kraken_data["positions"].append({ | |
| "symbol": symbol, | |
| "qty": balance, | |
| "entry_price": entry_price, | |
| "current_price": current_price, | |
| "value_usd": value, | |
| "pnl_usd": pnl, | |
| "is_airdrop": is_free, | |
| "quote": price_data['quote'] | |
| }) | |
| kraken_data["total_value_usd"] += value | |
| kraken_data["total_pnl_usd"] += pnl | |
| kraken_data["count"] += 1 | |
| if pnl > 0: | |
| kraken_data["profitable_count"] += 1 | |
| snapshot["exchanges"]["kraken"] = kraken_data | |
| snapshot["totals"]["total_value_usd"] += kraken_data["total_value_usd"] | |
| snapshot["totals"]["total_pnl_usd"] += kraken_data["total_pnl_usd"] | |
| snapshot["totals"]["positions_count"] += kraken_data["count"] | |
| snapshot["totals"]["profitable_count"] += kraken_data["profitable_count"] | |
| except Exception as e: | |
| snapshot["exchanges"]["kraken"] = {"error": str(e)} | |
| # Binance | |
| try: | |
| binance = get_binance_client() | |
| balances = binance.get_balance() | |
| binance_data = { | |
| "positions": [], | |
| "total_value": 0, | |
| "total_pnl": 0, | |
| "count": 0, | |
| "profitable_count": 0 | |
| } | |
| if balances: | |
| for asset, balance in balances.items(): # Process ALL positions (was [:20]) | |
| if balance > 0: | |
| ticker_pair = f"{asset}USDC" | |
| cost_data = cost_basis.get(ticker_pair) or cost_basis.get(f"binance:{ticker_pair}") | |
| entry_price = 0 | |
| if cost_data and cost_data.get('exchange') == 'binance': | |
| entry_price = cost_data.get('avg_entry_price', 0) | |
| try: | |
| ticker = binance.get_ticker(ticker_pair) | |
| current_price = float(ticker.get('last', 0)) | |
| if current_price > 0: | |
| value = balance * current_price | |
| pnl = balance * (current_price - entry_price) if entry_price > 0 else 0 | |
| binance_data["positions"].append({ | |
| "symbol": asset, | |
| "qty": balance, | |
| "entry_price": entry_price, | |
| "current_price": current_price, | |
| "value": value, | |
| "pnl": pnl, | |
| "pnl_pct": ((current_price - entry_price) / entry_price) * 100 if entry_price > 0 else 0 | |
| }) | |
| binance_data["total_value"] += value | |
| binance_data["total_pnl"] += pnl | |
| binance_data["count"] += 1 | |
| if pnl > 0: | |
| binance_data["profitable_count"] += 1 | |
| except: | |
| pass # Skip assets with no USDC pair | |
| snapshot["exchanges"]["binance"] = binance_data | |
| snapshot["totals"]["total_value_usd"] += binance_data["total_value"] | |
| snapshot["totals"]["total_pnl_usd"] += binance_data["total_pnl"] | |
| snapshot["totals"]["positions_count"] += binance_data["count"] | |
| snapshot["totals"]["profitable_count"] += binance_data["profitable_count"] | |
| except Exception as e: | |
| snapshot["exchanges"]["binance"] = {"error": str(e)} | |
| return snapshot | |
| def save_profit_state(snapshot: Dict[str, Any]): | |
| """Save portfolio snapshot to file for Queen/Orca access.""" | |
| try: | |
| with open(PROFIT_STATE_FILE, 'w') as f: | |
| json.dump(snapshot, f, indent=2) | |
| except Exception as e: | |
| print(f"β οΈ Failed to save profit state: {e}") | |
| def publish_to_thought_bus(snapshot: Dict[str, Any]): | |
| """Publish portfolio data to Thought Bus for Queen awareness.""" | |
| if not THOUGHT_BUS_AVAILABLE: | |
| return | |
| try: | |
| bus = ThoughtBus() | |
| bus.emit("portfolio_snapshot", { | |
| "total_value_usd": snapshot["totals"]["total_value_usd"], | |
| "total_pnl_usd": snapshot["totals"]["total_pnl_usd"], | |
| "positions_count": snapshot["totals"]["positions_count"], | |
| "profitable_count": snapshot["totals"]["profitable_count"], | |
| "timestamp": snapshot["timestamp"], | |
| "exchanges": { | |
| "alpaca": snapshot["exchanges"].get("alpaca", {}).get("total_value", 0), | |
| "kraken": snapshot["exchanges"].get("kraken", {}).get("total_value_usd", 0), | |
| "binance": snapshot["exchanges"].get("binance", {}).get("total_value", 0) | |
| } | |
| }) | |
| except Exception as e: | |
| print(f"β οΈ Failed to publish to Thought Bus: {e}") | |
| def main(): | |
| print("\nπ° LIVE POSITION & PROFIT MONITOR\n") | |
| print("=" * 80) | |
| # Save raw balance snapshot FIRST (all 3 exchanges, atomic write) | |
| print("πΈ Taking pre-trade balance snapshot (all exchanges)...") | |
| save_balance_snapshot() | |
| # Get structured snapshot | |
| snapshot = get_portfolio_snapshot() | |
| # Save state for Queen/Orca | |
| save_profit_state(snapshot) | |
| publish_to_thought_bus(snapshot) | |
| # Load cost basis for display | |
| cost_basis = load_cost_basis() | |
| # Alpaca - shows unrealized P&L | |
| print("\nπ¦ ALPACA:") | |
| try: | |
| alpaca = AlpacaClient() | |
| positions = alpaca.get_positions() | |
| if not positions: | |
| print(" No open positions") | |
| else: | |
| total_value = 0 | |
| total_pnl = 0 | |
| for pos in positions: | |
| symbol = pos['symbol'] | |
| qty = float(pos['qty']) | |
| entry = float(pos['avg_entry_price']) | |
| current = float(pos['current_price']) | |
| value = float(pos['market_value']) | |
| pnl = float(pos['unrealized_pl']) | |
| pnl_pct = float(pos['unrealized_plpc']) * 100 | |
| total_value += value | |
| total_pnl += pnl | |
| status = "π’" if pnl > 0 else "π΄" | |
| print(f"\n {status} {symbol:10s}") | |
| print(f" Entry: ${entry:10.6f}") | |
| print(f" Current: ${current:10.6f}") | |
| print(f" Qty: {qty:10.4f}") | |
| print(f" Value: ${value:10.2f}") | |
| print(f" P&L: ${pnl:+10.2f} ({pnl_pct:+.2f}%)") | |
| # Distance to profit targets | |
| if pnl_pct < 0.5: | |
| print(f" β³ {0.5 - pnl_pct:.2f}% to 0.5% target") | |
| elif pnl_pct < 1.0: | |
| print(f" π― {1.0 - pnl_pct:.2f}% to 1.0% target") | |
| else: | |
| print(f" β PROFITABLE! Hit target!") | |
| print(f"\n TOTAL: ${total_value:.2f} | P&L: ${total_pnl:+.2f} ({total_pnl/total_value*100:+.2f}%)") | |
| except Exception as e: | |
| print(f" Error: {e}") | |
| # Kraken - show balance with P&L calculated from ledger history | |
| print("\n\nπ KRAKEN:") | |
| try: | |
| kraken = get_kraken_client() | |
| balances = kraken.get_balance() | |
| ledgers = kraken.get_ledgers() | |
| if not balances: | |
| print(" No positions") | |
| else: | |
| # π OPTIMIZATION: Fetch all market prices in ONE batch call | |
| print(" Fetching market data...") | |
| all_tickers = kraken.get_24h_tickers() | |
| price_lookup = {} | |
| # Build lookup table: asset -> {price, quote_currency} | |
| for ticker in all_tickers: | |
| symbol = ticker['symbol'] | |
| price = float(ticker.get('lastPrice', 0)) | |
| # Extract base and quote (e.g., "SOLUSD" -> SOL, USD) | |
| for quote in ['USD', 'EUR', 'GBP', 'USDT', 'USDC']: | |
| if symbol.endswith(quote): | |
| base = symbol[:-len(quote)] | |
| if base not in price_lookup or quote == 'USD': # Prefer USD | |
| price_lookup[base] = {'price': price, 'quote': quote} | |
| break | |
| # Process ledgers to find cost basis | |
| trades_by_ref = {} | |
| if ledgers and 'ledger' in ledgers: | |
| for ledger_id, entry in ledgers['ledger'].items(): | |
| if entry['type'] == 'trade': | |
| refid = entry['refid'] | |
| if refid not in trades_by_ref: | |
| trades_by_ref[refid] = [] | |
| trades_by_ref[refid].append(entry) | |
| kraken_cost_basis = {} | |
| for refid, entries in trades_by_ref.items(): | |
| if len(entries) == 2: | |
| # Identify asset and currency entries | |
| entry1, entry2 = entries | |
| asset_entry = None | |
| currency_entry = None | |
| # Currency assets start with Z (ZUSD, ZEUR) or X (XXBT, XETH for majors) | |
| # Non-currency assets are the altcoins | |
| if entry1['asset'].startswith('Z'): | |
| currency_entry = entry1 | |
| asset_entry = entry2 | |
| elif entry2['asset'].startswith('Z'): | |
| currency_entry = entry2 | |
| asset_entry = entry1 | |
| elif entry1['asset'] in ['XXBT', 'XETH'] and entry2['asset'] not in ['XXBT', 'XETH']: | |
| currency_entry = entry1 | |
| asset_entry = entry2 | |
| elif entry2['asset'] in ['XXBT', 'XETH'] and entry1['asset'] not in ['XXBT', 'XETH']: | |
| currency_entry = entry2 | |
| asset_entry = entry1 | |
| else: | |
| # Both are X-prefixed, pick the one with larger amount as currency | |
| if abs(float(entry1['amount'])) > abs(float(entry2['amount'])): | |
| currency_entry = entry1 | |
| asset_entry = entry2 | |
| else: | |
| currency_entry = entry2 | |
| asset_entry = entry1 | |
| if asset_entry and currency_entry: | |
| asset = asset_entry['asset'] | |
| # Normalize asset names (remove X/Z prefixes) | |
| if asset.startswith('X') and len(asset) > 4: | |
| asset = asset[1:] | |
| if asset.startswith('Z') and len(asset) > 4: | |
| asset = asset[1:] | |
| if asset.endswith('.d'): | |
| asset = asset[:-2] | |
| amount_bought = abs(float(asset_entry['amount'])) | |
| cost = abs(float(currency_entry['amount'])) | |
| if amount_bought > 0: # Only count buys | |
| if asset not in kraken_cost_basis: | |
| kraken_cost_basis[asset] = {'total_cost': 0, 'total_amount': 0} | |
| kraken_cost_basis[asset]['total_cost'] += cost | |
| kraken_cost_basis[asset]['total_amount'] += amount_bought | |
| profitable_count = 0 | |
| total_assets = sum(1 for b in balances.values() if b > 0) | |
| total_value_usd = 0 | |
| total_pnl_usd = 0 | |
| for symbol, balance in balances.items(): | |
| if balance > 0: | |
| # Normalize symbol for lookups | |
| lookup_symbol = symbol | |
| if symbol.startswith('X') and len(symbol) > 4: | |
| lookup_symbol = symbol[1:] | |
| if symbol.startswith('Z') and len(symbol) > 4: | |
| lookup_symbol = symbol[1:] | |
| if symbol.endswith('.d'): | |
| lookup_symbol = symbol[:-2] | |
| # Try to find price in our lookup table | |
| price_data = price_lookup.get(lookup_symbol) | |
| cost_data = kraken_cost_basis.get(lookup_symbol) | |
| if price_data and price_data['price'] > 0: | |
| current_price = price_data['price'] | |
| quote = price_data['quote'] | |
| value = balance * current_price | |
| if cost_data and cost_data['total_amount'] > 0: | |
| avg_entry_price = cost_data['total_cost'] / cost_data['total_amount'] | |
| pnl = balance * (current_price - avg_entry_price) | |
| pnl_pct = ((current_price - avg_entry_price) / avg_entry_price) * 100 if avg_entry_price > 0 else 0 | |
| status = "π’" if pnl > 0 else "π΄" | |
| print(f" {status} {symbol:12s} | Bal: {balance:10.6f} | Entry: {avg_entry_price:.6f} {quote} | Current: {current_price:.6f} {quote}") | |
| print(f" Value: {value:.2f} {quote} | P&L: {pnl:+.2f} {quote} ({pnl_pct:+.2f}%)") | |
| if pnl > 0: | |
| profitable_count += 1 | |
| total_value_usd += value | |
| total_pnl_usd += pnl | |
| else: | |
| # No cost basis = likely airdrop/staking | |
| print(f" π {symbol:12s} | Bal: {balance:10.6f} | Current: {current_price:.6f} {quote}") | |
| print(f" Value: {value:.2f} {quote} | FREE (airdrop/staking)") | |
| profitable_count += 1 | |
| total_value_usd += value | |
| else: | |
| # No price data available | |
| if balance < 0.001: | |
| continue # Skip dust | |
| print(f" βͺ {symbol:12s} | Balance: {balance:.6f}") | |
| print(f"\n Total: {total_assets} assets | {profitable_count} profitable | Est. Value: ${total_value_usd:.2f}") | |
| except Exception as e: | |
| print(f" Error: {e}") | |
| # Binance - show balance with P&L if cost basis available | |
| print("\n\nπ‘ BINANCE:") | |
| try: | |
| binance = get_binance_client() | |
| balances = binance.get_balance() | |
| if not balances: | |
| print(" No balances") | |
| else: | |
| count = 0 | |
| profitable_count = 0 | |
| for asset, balance in balances.items(): # Process ALL positions (was [:10]) | |
| if balance > 0: | |
| # Check cost basis - try both key formats | |
| ticker_pair = f"{asset}USDC" | |
| cost_data = cost_basis.get(ticker_pair) or cost_basis.get(f"binance:{ticker_pair}") | |
| if cost_data and cost_data.get('exchange') == 'binance': | |
| entry_price = cost_data.get('avg_entry_price', 0) | |
| # Get current price using USDC pairs | |
| try: | |
| ticker = binance.get_ticker(ticker_pair) | |
| current_price = float(ticker.get('last', 0)) | |
| if entry_price > 0 and current_price > 0: | |
| pnl_pct = ((current_price - entry_price) / entry_price) * 100 | |
| value = balance * current_price | |
| pnl = balance * (current_price - entry_price) | |
| status = "π’" if pnl > 0 else "π΄" | |
| print(f" {status} {asset:12s} | Bal: {balance:10.6f} | Entry: β¬{entry_price:.6f} | Current: β¬{current_price:.6f}") | |
| print(f" Value: β¬{value:.2f} | P&L: β¬{pnl:+.2f} ({pnl_pct:+.2f}%)") | |
| if pnl > 0: | |
| profitable_count += 1 | |
| else: | |
| print(f" βͺ {asset:12s} | Balance: {balance:.6f}") | |
| except: | |
| print(f" βͺ {asset:12s} | Balance: {balance:.6f}") | |
| else: | |
| print(f" βͺ {asset:12s} | Balance: {balance:.6f}") | |
| count += 1 | |
| print(f"\n Total: {count} assets | {profitable_count} profitable") | |
| except Exception as e: | |
| print(f" Error: {e}") | |
| print("\n" + "=" * 80 + "\n") | |
| # Queen/Orca integration confirmation | |
| print(f"π Portfolio state saved to: {PROFIT_STATE_FILE}") | |
| if THOUGHT_BUS_AVAILABLE: | |
| print("π§ Portfolio data published to Thought Bus β Queen can see it") | |
| else: | |
| print("π Thought Bus not available (Queen can still read state file)") | |
| if __name__ == "__main__": | |
| main() | |