From ae62d893bc2d9dc29c95c149470ad341856ed41b Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 27 May 2025 13:53:12 +0300 Subject: [PATCH] initial balance on dash --- closed_trades_history.json | 17 --- core/trading_executor.py | 45 +++++++- test_mexc_balance_orders.py | 222 ++++++++++++++++++++++++++++++++++++ web/dashboard.py | 49 ++++++-- 4 files changed, 307 insertions(+), 26 deletions(-) delete mode 100644 closed_trades_history.json create mode 100644 test_mexc_balance_orders.py diff --git a/closed_trades_history.json b/closed_trades_history.json deleted file mode 100644 index 9281d15..0000000 --- a/closed_trades_history.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "trade_id": 1, - "side": "LONG", - "entry_time": "2025-05-27T10:47:14.593940+00:00", - "exit_time": "2025-05-27T10:47:19.603178+00:00", - "entry_price": 2635.93, - "exit_price": 2635.41, - "size": 0.179, - "gross_pnl": -0.09307999999999673, - "fees": 0.0, - "net_pnl": -0.09307999999999673, - "duration": "0:00:05.009238", - "symbol": "ETH/USDT", - "mexc_executed": false - } -] \ No newline at end of file diff --git a/core/trading_executor.py b/core/trading_executor.py index 4250ab4..b300d78 100644 --- a/core/trading_executor.py +++ b/core/trading_executor.py @@ -401,4 +401,47 @@ class TradingExecutor: """Reset daily statistics (call at start of new day)""" self.daily_trades = 0 self.daily_loss = 0.0 - logger.info("Daily trading statistics reset") \ No newline at end of file + logger.info("Daily trading statistics reset") + + def get_account_balance(self) -> Dict[str, Dict[str, float]]: + """Get account balance information from MEXC + + Returns: + Dict with asset balances in format: + { + 'USDT': {'free': 100.0, 'locked': 0.0}, + 'ETH': {'free': 0.5, 'locked': 0.0}, + ... + } + """ + try: + if not self.exchange: + logger.error("Exchange interface not available") + return {} + + # Get account info from MEXC + account_info = self.exchange.get_account_info() + if not account_info: + logger.error("Failed to get account info from MEXC") + return {} + + balances = {} + for balance in account_info.get('balances', []): + asset = balance.get('asset', '') + free = float(balance.get('free', 0)) + locked = float(balance.get('locked', 0)) + + # Only include assets with non-zero balance + if free > 0 or locked > 0: + balances[asset] = { + 'free': free, + 'locked': locked, + 'total': free + locked + } + + logger.info(f"Retrieved balances for {len(balances)} assets") + return balances + + except Exception as e: + logger.error(f"Error getting account balance: {e}") + return {} \ No newline at end of file diff --git a/test_mexc_balance_orders.py b/test_mexc_balance_orders.py new file mode 100644 index 0000000..837ec6b --- /dev/null +++ b/test_mexc_balance_orders.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python3 +""" +Test script for MEXC balance retrieval and $1 order execution +""" + +import sys +import os +import logging +from pathlib import Path + +# Add project root to path +sys.path.insert(0, os.path.abspath('.')) + +from core.trading_executor import TradingExecutor +from core.data_provider import DataProvider + +# Setup logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +def test_mexc_balance(): + """Test MEXC balance retrieval""" + print("="*60) + print("TESTING MEXC BALANCE RETRIEVAL") + print("="*60) + + try: + # Initialize trading executor + executor = TradingExecutor() + + # Check if trading is enabled + print(f"Trading enabled: {executor.trading_enabled}") + print(f"Dry run mode: {executor.dry_run}") + + if not executor.trading_enabled: + print("āŒ Trading not enabled - check config.yaml and API keys") + return False + + # Test balance retrieval + print("\nšŸ“Š Retrieving account balance...") + balances = executor.get_account_balance() + + if not balances: + print("āŒ No balances retrieved - check API connectivity") + return False + + print(f"āœ… Retrieved balances for {len(balances)} assets:") + for asset, balance_info in balances.items(): + free = balance_info['free'] + locked = balance_info['locked'] + total = balance_info['total'] + print(f" {asset}: Free: {free:.6f}, Locked: {locked:.6f}, Total: {total:.6f}") + + # Check USDT balance specifically + if 'USDT' in balances: + usdt_free = balances['USDT']['free'] + print(f"\nšŸ’° USDT available for trading: ${usdt_free:.2f}") + + if usdt_free >= 2.0: # Need at least $2 for testing + print("āœ… Sufficient USDT balance for $1 order testing") + return True + else: + print(f"āš ļø Insufficient USDT balance for testing (need $2+, have ${usdt_free:.2f})") + return False + else: + print("āŒ No USDT balance found") + return False + + except Exception as e: + logger.error(f"Error testing MEXC balance: {e}") + return False + +def test_mexc_order_execution(): + """Test $1 order execution (dry run)""" + print("\n" + "="*60) + print("TESTING $1 ORDER EXECUTION (DRY RUN)") + print("="*60) + + try: + # Initialize components + executor = TradingExecutor() + data_provider = DataProvider() + + if not executor.trading_enabled: + print("āŒ Trading not enabled - cannot test order execution") + return False + + # Test symbol + symbol = "ETH/USDT" + + # Get current price + print(f"\nšŸ“ˆ Getting current price for {symbol}...") + ticker_data = data_provider.get_historical_data(symbol, '1m', limit=1, refresh=True) + + if ticker_data is None or ticker_data.empty: + print(f"āŒ Could not get price data for {symbol}") + return False + + current_price = float(ticker_data['close'].iloc[-1]) + print(f"āœ… Current {symbol} price: ${current_price:.2f}") + + # Calculate order size for $1 + usd_amount = 1.0 + crypto_amount = usd_amount / current_price + print(f"šŸ’± $1 USD = {crypto_amount:.6f} ETH") + + # Test buy signal execution + print(f"\nšŸ›’ Testing BUY signal execution...") + buy_success = executor.execute_signal( + symbol=symbol, + action='BUY', + confidence=0.75, + current_price=current_price + ) + + if buy_success: + print("āœ… BUY signal executed successfully") + + # Check position + positions = executor.get_positions() + if symbol in positions: + position = positions[symbol] + print(f"šŸ“ Position opened: {position.quantity:.6f} {symbol} @ ${position.entry_price:.2f}") + + # Test sell signal execution + print(f"\nšŸ’° Testing SELL signal execution...") + sell_success = executor.execute_signal( + symbol=symbol, + action='SELL', + confidence=0.80, + current_price=current_price * 1.001 # Simulate small price increase + ) + + if sell_success: + print("āœ… SELL signal executed successfully") + + # Check trade history + trades = executor.get_trade_history() + if trades: + last_trade = trades[-1] + print(f"šŸ“Š Trade completed: P&L = ${last_trade.pnl:.4f}") + + return True + else: + print("āŒ SELL signal failed") + return False + else: + print("āŒ No position found after BUY signal") + return False + else: + print("āŒ BUY signal failed") + return False + + except Exception as e: + logger.error(f"Error testing order execution: {e}") + return False + +def test_dashboard_balance_integration(): + """Test dashboard balance integration""" + print("\n" + "="*60) + print("TESTING DASHBOARD BALANCE INTEGRATION") + print("="*60) + + try: + from web.dashboard import TradingDashboard + + # Create dashboard with trading executor + executor = TradingExecutor() + dashboard = TradingDashboard(trading_executor=executor) + + print(f"Dashboard starting balance: ${dashboard.starting_balance:.2f}") + + if dashboard.starting_balance > 0: + print("āœ… Dashboard successfully retrieved starting balance") + return True + else: + print("āš ļø Dashboard using default balance (MEXC not connected)") + return False + + except Exception as e: + logger.error(f"Error testing dashboard integration: {e}") + return False + +def main(): + """Run all tests""" + print("šŸš€ MEXC INTEGRATION TESTING") + print("Testing balance retrieval and $1 order execution") + + # Test 1: Balance retrieval + balance_test = test_mexc_balance() + + # Test 2: Order execution (only if balance test passes) + if balance_test: + order_test = test_mexc_order_execution() + else: + print("\nā­ļø Skipping order execution test (balance test failed)") + order_test = False + + # Test 3: Dashboard integration + dashboard_test = test_dashboard_balance_integration() + + # Summary + print("\n" + "="*60) + print("TEST SUMMARY") + print("="*60) + print(f"Balance Retrieval: {'āœ… PASS' if balance_test else 'āŒ FAIL'}") + print(f"Order Execution: {'āœ… PASS' if order_test else 'āŒ FAIL'}") + print(f"Dashboard Integration: {'āœ… PASS' if dashboard_test else 'āŒ FAIL'}") + + if balance_test and order_test and dashboard_test: + print("\nšŸŽ‰ ALL TESTS PASSED - Ready for live $1 testing!") + return True + else: + print("\nāš ļø Some tests failed - check configuration and API keys") + return False + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) \ No newline at end of file diff --git a/web/dashboard.py b/web/dashboard.py index 20cb89d..6cf4985 100644 --- a/web/dashboard.py +++ b/web/dashboard.py @@ -93,7 +93,7 @@ class TradingDashboard: self.current_position = None # {'side': 'BUY', 'price': 3456.78, 'size': 0.1, 'timestamp': datetime} self.total_realized_pnl = 0.0 self.total_fees = 0.0 - self.starting_balance = 100.0 # Starting portfolio value in USD + self.starting_balance = self._get_initial_balance() # Get balance from MEXC or default to 100 # Closed trades tracking for accounting self.closed_trades = [] # List of all closed trades with full details @@ -143,6 +143,34 @@ class TradingDashboard: logger.info("Trading Dashboard initialized with continuous training") + def _get_initial_balance(self) -> float: + """Get initial USDT balance from MEXC or return default""" + try: + if self.trading_executor and hasattr(self.trading_executor, 'get_account_balance'): + logger.info("Fetching initial balance from MEXC...") + + # Get USDT balance from MEXC + balance_info = self.trading_executor.get_account_balance() + if balance_info and 'USDT' in balance_info: + usdt_balance = float(balance_info['USDT'].get('free', 0)) + if usdt_balance > 0: + logger.info(f"MEXC: Retrieved USDT balance: ${usdt_balance:.2f}") + return usdt_balance + else: + logger.warning("MEXC: No USDT balance found") + else: + logger.warning("MEXC: Failed to retrieve balance info") + else: + logger.info("MEXC: Trading executor not available for balance retrieval") + + except Exception as e: + logger.error(f"Error getting MEXC balance: {e}") + + # Fallback to default + default_balance = 100.0 + logger.info(f"Using default starting balance: ${default_balance:.2f}") + return default_balance + def _setup_layout(self): """Setup the dashboard layout""" self.app.layout = html.Div([ @@ -1376,11 +1404,16 @@ class TradingDashboard: # Add MEXC execution status to decision record decision['mexc_executed'] = mexc_success - # Calculate confidence-based position size (0.05 to 0.2 range) - base_size = 0.1 # Base size - confidence_multiplier = max(0.5, min(2.0, decision['confidence'] * 2)) # 0.5x to 2x multiplier - position_size = base_size * confidence_multiplier - decision['size'] = round(position_size, 3) # Update decision with calculated size + # Calculate USD-based position size for testing ($1 orders) + if current_price and current_price > 0: + usd_size = 1.0 # $1 per trade for testing + position_size = usd_size / current_price # Convert USD to crypto amount + decision['size'] = round(position_size, 6) # Update decision with calculated size + decision['usd_size'] = usd_size # Track USD amount for logging + else: + # Fallback if no price available + decision['size'] = 0.001 + decision['usd_size'] = 1.0 if decision['action'] == 'BUY': # First, close any existing SHORT position @@ -1452,7 +1485,7 @@ class TradingDashboard: trade_record['fees'] = fee self.session_trades.append(trade_record) - logger.info(f"[TRADE] OPENED LONG: {decision['size']} @ ${decision['price']:.2f} (confidence: {decision['confidence']:.1%})") + logger.info(f"[TRADE] OPENED LONG: {decision['size']:.6f} (~${decision.get('usd_size', 1.0):.2f}) @ ${decision['price']:.2f} (confidence: {decision['confidence']:.1%})") elif self.current_position['side'] == 'LONG': # Already have a long position - could add to it or replace it @@ -1577,7 +1610,7 @@ class TradingDashboard: trade_record['fees'] = fee self.session_trades.append(trade_record) - logger.info(f"[TRADE] OPENED SHORT: {decision['size']} @ ${decision['price']:.2f} (confidence: {decision['confidence']:.1%})") + logger.info(f"[TRADE] OPENED SHORT: {decision['size']:.6f} (~${decision.get('usd_size', 1.0):.2f}) @ ${decision['price']:.2f} (confidence: {decision['confidence']:.1%})") elif self.current_position['side'] == 'SHORT': # Already have a short position - could add to it or replace it