bybit ballance working
This commit is contained in:
81
NN/exchanges/bybit/debug/test_bybit_balance.py
Normal file
81
NN/exchanges/bybit/debug/test_bybit_balance.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add project root to path
|
||||||
|
project_root = Path(__file__).parent
|
||||||
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
|
from NN.exchanges.bybit_interface import BybitInterface
|
||||||
|
|
||||||
|
async def test_bybit_balance():
|
||||||
|
"""Test if we can read real balance from Bybit"""
|
||||||
|
|
||||||
|
print("Testing Bybit Balance Reading...")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
# Initialize Bybit interface
|
||||||
|
bybit = BybitInterface()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Connect to Bybit
|
||||||
|
print("Connecting to Bybit...")
|
||||||
|
success = await bybit.connect()
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
print("ERROR: Failed to connect to Bybit")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("✓ Connected to Bybit successfully")
|
||||||
|
|
||||||
|
# Test get_balance for USDT
|
||||||
|
print("\nTesting get_balance('USDT')...")
|
||||||
|
usdt_balance = await bybit.get_balance('USDT')
|
||||||
|
print(f"USDT Balance: {usdt_balance}")
|
||||||
|
|
||||||
|
# Test get_all_balances
|
||||||
|
print("\nTesting get_all_balances()...")
|
||||||
|
all_balances = await bybit.get_all_balances()
|
||||||
|
print(f"All Balances: {all_balances}")
|
||||||
|
|
||||||
|
# Check if we have any non-zero balances
|
||||||
|
print("\nBalance Analysis:")
|
||||||
|
if isinstance(all_balances, dict):
|
||||||
|
for symbol, balance in all_balances.items():
|
||||||
|
if isinstance(balance, (int, float)) and balance > 0:
|
||||||
|
print(f" {symbol}: {balance}")
|
||||||
|
elif isinstance(balance, dict):
|
||||||
|
# Handle nested balance structure
|
||||||
|
total = balance.get('total', 0) or balance.get('available', 0)
|
||||||
|
if total > 0:
|
||||||
|
print(f" {symbol}: {total}")
|
||||||
|
|
||||||
|
# Test account info if available
|
||||||
|
print("\nTesting account info...")
|
||||||
|
try:
|
||||||
|
if hasattr(bybit, 'client') and bybit.client:
|
||||||
|
# Try to get account info
|
||||||
|
account_info = bybit.client.get_wallet_balance(accountType="UNIFIED")
|
||||||
|
print(f"Account Info: {account_info}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Account info error: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cleanup
|
||||||
|
if hasattr(bybit, 'client') and bybit.client:
|
||||||
|
try:
|
||||||
|
await bybit.client.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Run the test
|
||||||
|
asyncio.run(test_bybit_balance())
|
@ -168,7 +168,20 @@ class BybitInterface(ExchangeInterface):
|
|||||||
coins = account.get('coin', [])
|
coins = account.get('coin', [])
|
||||||
for coin in coins:
|
for coin in coins:
|
||||||
if coin.get('coin', '').upper() == asset.upper():
|
if coin.get('coin', '').upper() == asset.upper():
|
||||||
available_balance = float(coin.get('availableToWithdraw', 0))
|
# Try availableToWithdraw first, then equity, then walletBalance
|
||||||
|
available_str = coin.get('availableToWithdraw', '')
|
||||||
|
if available_str:
|
||||||
|
available_balance = float(available_str)
|
||||||
|
else:
|
||||||
|
# Use equity if availableToWithdraw is empty
|
||||||
|
equity_str = coin.get('equity', '')
|
||||||
|
if equity_str:
|
||||||
|
available_balance = float(equity_str)
|
||||||
|
else:
|
||||||
|
# Fall back to walletBalance
|
||||||
|
wallet_str = coin.get('walletBalance', '0')
|
||||||
|
available_balance = float(wallet_str) if wallet_str else 0.0
|
||||||
|
|
||||||
logger.debug(f"Balance for {asset}: {available_balance}")
|
logger.debug(f"Balance for {asset}: {available_balance}")
|
||||||
return available_balance
|
return available_balance
|
||||||
|
|
||||||
@ -198,6 +211,14 @@ class BybitInterface(ExchangeInterface):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error getting account summary: {e}")
|
logger.error(f"Error getting account summary: {e}")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def get_account_info(self) -> Dict[str, Any]:
|
||||||
|
"""Get account information (alias for get_account_summary for compatibility).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary with account information
|
||||||
|
"""
|
||||||
|
return self.get_account_summary()
|
||||||
|
|
||||||
def get_all_balances(self) -> Dict[str, Dict[str, float]]:
|
def get_all_balances(self) -> Dict[str, Dict[str, float]]:
|
||||||
"""Get all account balances in the format expected by trading executor.
|
"""Get all account balances in the format expected by trading executor.
|
||||||
@ -217,8 +238,23 @@ class BybitInterface(ExchangeInterface):
|
|||||||
asset = coin.get('coin', '')
|
asset = coin.get('coin', '')
|
||||||
if asset:
|
if asset:
|
||||||
# Convert Bybit balance format to MEXC-compatible format
|
# Convert Bybit balance format to MEXC-compatible format
|
||||||
available = float(coin.get('availableToWithdraw', 0))
|
# Handle empty string values that cause conversion errors
|
||||||
locked = float(coin.get('locked', 0))
|
available_str = coin.get('availableToWithdraw', '')
|
||||||
|
locked_str = coin.get('locked', '')
|
||||||
|
equity_str = coin.get('equity', '')
|
||||||
|
wallet_str = coin.get('walletBalance', '')
|
||||||
|
|
||||||
|
# Use equity or walletBalance if availableToWithdraw is empty
|
||||||
|
if available_str:
|
||||||
|
available = float(available_str)
|
||||||
|
elif equity_str:
|
||||||
|
available = float(equity_str)
|
||||||
|
elif wallet_str:
|
||||||
|
available = float(wallet_str)
|
||||||
|
else:
|
||||||
|
available = 0.0
|
||||||
|
|
||||||
|
locked = float(locked_str) if locked_str else 0.0
|
||||||
|
|
||||||
balances[asset] = {
|
balances[asset] = {
|
||||||
'free': available,
|
'free': available,
|
||||||
|
@ -99,6 +99,10 @@ class TradingExecutor:
|
|||||||
self.primary_name = self.exchanges_config.get('primary', 'mexc')
|
self.primary_name = self.exchanges_config.get('primary', 'mexc')
|
||||||
self.primary_config = self.exchanges_config.get(self.primary_name, {})
|
self.primary_config = self.exchanges_config.get(self.primary_name, {})
|
||||||
|
|
||||||
|
# Set exchange config for compatibility (replaces mexc_config)
|
||||||
|
self.exchange_config = self.primary_config
|
||||||
|
self.mexc_config = self.primary_config # Legacy compatibility
|
||||||
|
|
||||||
# Initialize config synchronizer with the primary exchange
|
# Initialize config synchronizer with the primary exchange
|
||||||
self.config_sync = ConfigSynchronizer(
|
self.config_sync = ConfigSynchronizer(
|
||||||
config_path=config_path,
|
config_path=config_path,
|
||||||
@ -1166,14 +1170,13 @@ class TradingExecutor:
|
|||||||
logger.info("Daily trading statistics reset")
|
logger.info("Daily trading statistics reset")
|
||||||
|
|
||||||
def get_account_balance(self) -> Dict[str, Dict[str, float]]:
|
def get_account_balance(self) -> Dict[str, Dict[str, float]]:
|
||||||
"""Get account balance information from MEXC, including spot and futures.
|
"""Get account balance information from the primary exchange (universal method).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict with asset balances in format:
|
Dict with asset balances in format:
|
||||||
{
|
{
|
||||||
'USDT': {'free': 100.0, 'locked': 0.0, 'total': 100.0, 'type': 'spot'},
|
'USDT': {'free': 100.0, 'locked': 0.0, 'total': 100.0, 'type': 'spot'},
|
||||||
'ETH': {'free': 0.5, 'locked': 0.0, 'total': 0.5, 'type': 'spot'},
|
'ETH': {'free': 0.5, 'locked': 0.0, 'total': 0.5, 'type': 'spot'},
|
||||||
'FUTURES_USDT': {'free': 500.0, 'locked': 50.0, 'total': 550.0, 'type': 'futures'}
|
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -1182,47 +1185,29 @@ class TradingExecutor:
|
|||||||
logger.error("Exchange interface not available")
|
logger.error("Exchange interface not available")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
combined_balances = {}
|
# Use the universal get_all_balances method that works with all exchanges
|
||||||
|
if hasattr(self.exchange, 'get_all_balances'):
|
||||||
# 1. Get Spot Account Info
|
raw_balances = self.exchange.get_all_balances()
|
||||||
spot_account_info = self.exchange.get_account_info()
|
if raw_balances:
|
||||||
if spot_account_info and 'balances' in spot_account_info:
|
# Convert to the expected format with 'type' field
|
||||||
for balance in spot_account_info['balances']:
|
combined_balances = {}
|
||||||
asset = balance.get('asset', '')
|
for asset, balance_data in raw_balances.items():
|
||||||
free = float(balance.get('free', 0))
|
if isinstance(balance_data, dict):
|
||||||
locked = float(balance.get('locked', 0))
|
combined_balances[asset] = {
|
||||||
if free > 0 or locked > 0:
|
'free': balance_data.get('free', 0.0),
|
||||||
combined_balances[asset] = {
|
'locked': balance_data.get('locked', 0.0),
|
||||||
'free': free,
|
'total': balance_data.get('total', 0.0),
|
||||||
'locked': locked,
|
'type': 'spot' # Default to spot for now
|
||||||
'total': free + locked,
|
}
|
||||||
'type': 'spot'
|
|
||||||
}
|
logger.info(f"Retrieved balances for {len(combined_balances)} assets from {self.primary_name}")
|
||||||
|
return combined_balances
|
||||||
|
else:
|
||||||
|
logger.warning(f"No balances returned from {self.primary_name} exchange")
|
||||||
|
return {}
|
||||||
else:
|
else:
|
||||||
logger.warning("Failed to get spot account info from MEXC or no balances found.")
|
logger.error(f"Exchange {self.primary_name} does not support get_all_balances method")
|
||||||
|
return {}
|
||||||
# 2. Get Futures Account Info (commented out until futures API is implemented)
|
|
||||||
# futures_account_info = self.exchange.get_futures_account_info()
|
|
||||||
# if futures_account_info:
|
|
||||||
# for currency, asset_data in futures_account_info.items():
|
|
||||||
# # MEXC Futures API returns 'availableBalance' and 'frozenBalance'
|
|
||||||
# free = float(asset_data.get('availableBalance', 0))
|
|
||||||
# locked = float(asset_data.get('frozenBalance', 0))
|
|
||||||
# total = free + locked # total is the sum of available and frozen
|
|
||||||
# if free > 0 or locked > 0:
|
|
||||||
# # Prefix with 'FUTURES_' to distinguish from spot, or decide on a unified key
|
|
||||||
# # For now, let's keep them distinct for clarity
|
|
||||||
# combined_balances[f'FUTURES_{currency}'] = {
|
|
||||||
# 'free': free,
|
|
||||||
# 'locked': locked,
|
|
||||||
# 'total': total,
|
|
||||||
# 'type': 'futures'
|
|
||||||
# }
|
|
||||||
# else:
|
|
||||||
# logger.warning("Failed to get futures account info from MEXC or no futures assets found.")
|
|
||||||
|
|
||||||
logger.info(f"Retrieved combined balances for {len(combined_balances)} assets.")
|
|
||||||
return combined_balances
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error getting account balance: {e}")
|
logger.error(f"Error getting account balance: {e}")
|
||||||
@ -1426,7 +1411,11 @@ class TradingExecutor:
|
|||||||
if sync_result.get('changes_made'):
|
if sync_result.get('changes_made'):
|
||||||
logger.info("TRADING EXECUTOR: Reloading config after fee sync")
|
logger.info("TRADING EXECUTOR: Reloading config after fee sync")
|
||||||
self.config = get_config(self.config_synchronizer.config_path)
|
self.config = get_config(self.config_synchronizer.config_path)
|
||||||
self.mexc_config = self.config.get('mexc_trading', {})
|
# Update to use primary exchange config
|
||||||
|
self.exchanges_config = self.config.get('exchanges', {})
|
||||||
|
self.primary_name = self.exchanges_config.get('primary', 'mexc')
|
||||||
|
self.primary_config = self.exchanges_config.get(self.primary_name, {})
|
||||||
|
self.mexc_config = self.primary_config # Legacy compatibility
|
||||||
|
|
||||||
return sync_result
|
return sync_result
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user