limit max positions

This commit is contained in:
Dobromir Popov
2025-07-15 02:27:33 +03:00
parent 439611cf88
commit 0b07825be0
4 changed files with 537 additions and 90 deletions

View File

@ -927,11 +927,9 @@ class TradingOrchestrator:
try:
current_time = datetime.now()
# Check if enough time has passed since last decision
if symbol in self.last_decision_time:
time_since_last = (current_time - self.last_decision_time[symbol]).total_seconds()
if time_since_last < self.decision_frequency:
return None
# EXECUTE EVERY SIGNAL: Remove decision frequency limit
# Allow immediate execution of every signal from the decision model
logger.debug(f"Processing signal for {symbol} - no frequency limit applied")
# Get current market data
current_price = self.data_provider.get_current_price(symbol)
@ -1333,43 +1331,15 @@ class TradingOrchestrator:
current_position_pnl, symbol
)
# Apply aggressiveness-based confidence thresholds
if best_action in ['BUY', 'SELL']:
# For entry signals, use entry aggressiveness
if not self._has_open_position(symbol):
if best_confidence < entry_threshold:
best_action = 'HOLD'
reasoning['entry_threshold_applied'] = True
reasoning['entry_threshold'] = entry_threshold
# For exit signals, use exit aggressiveness
else:
if best_confidence < exit_threshold:
best_action = 'HOLD'
reasoning['exit_threshold_applied'] = True
reasoning['exit_threshold'] = exit_threshold
else:
# Standard threshold for HOLD
if best_confidence < self.confidence_threshold:
best_action = 'HOLD'
reasoning['threshold_applied'] = True
# EXECUTE EVERY SIGNAL: Remove confidence thresholds and signal accumulation
# The decision model has already aggregated all model outputs (CNN, DQN, transformer, etc.)
# So we trust its decision and execute every signal
reasoning['execute_every_signal'] = True
reasoning['models_aggregated'] = [pred.model_name for pred in predictions]
reasoning['aggregated_confidence'] = best_confidence
# Signal accumulation check - require multiple confident signals
if best_action in ['BUY', 'SELL']:
required_signals = 3 # Require 3 confident signals
recent_decisions = self.get_recent_decisions(symbol, limit=5)
# Count recent signals in the same direction
same_direction_count = sum(1 for d in recent_decisions
if d.action == best_action and d.confidence > entry_threshold)
if same_direction_count < required_signals:
best_action = 'HOLD'
reasoning['signal_accumulation'] = True
reasoning['required_signals'] = required_signals
reasoning['current_signals'] = same_direction_count
logger.info(f"Signal accumulation: {same_direction_count}/{required_signals} signals for {best_action}")
else:
logger.info(f"Signal accumulation satisfied: {same_direction_count}/{required_signals} signals for {best_action}")
logger.info(f"EXECUTING EVERY SIGNAL: {best_action} (confidence: {best_confidence:.3f}) "
f"from aggregated models: {reasoning['models_aggregated']}")
# Add P&L-based decision adjustment
best_action, best_confidence = self._apply_pnl_feedback(

View File

@ -143,6 +143,10 @@ class TradingExecutor:
self.max_open_orders = 2 # Maximum number of open orders allowed
self.open_orders_count = 0 # Current count of open orders
# Rate limiting for open orders sync (30 seconds)
self.last_open_orders_sync = datetime.min
self.open_orders_sync_interval = 30 # seconds
# Trading symbols
self.symbols = self.config.get('symbols', ['ETH/USDT', 'BTC/USDT'])
@ -332,21 +336,42 @@ class TradingExecutor:
logger.debug(f"LOCK RELEASED: {action} for {symbol}")
def _get_open_orders_count(self) -> int:
"""Get current count of open orders across all symbols"""
"""Get current count of open orders across all symbols with rate limiting"""
try:
if self.simulation_mode:
return 0
# Check if enough time has passed since last sync
current_time = datetime.now()
time_since_last_sync = (current_time - self.last_open_orders_sync).total_seconds()
if time_since_last_sync < self.open_orders_sync_interval:
# Return cached count if within rate limit
logger.debug(f"Using cached open orders count ({self.open_orders_count}) - rate limited")
return self.open_orders_count
# Update last sync time
self.last_open_orders_sync = current_time
total_open_orders = 0
for symbol in self.symbols:
open_orders = self.exchange.get_open_orders(symbol)
total_open_orders += len(open_orders)
try:
open_orders = self.exchange.get_open_orders(symbol)
total_open_orders += len(open_orders)
except Exception as e:
logger.warning(f"Error getting open orders for {symbol}: {e}")
# Continue with other symbols
continue
# Update cached count
self.open_orders_count = total_open_orders
logger.debug(f"Updated open orders count: {total_open_orders}")
return total_open_orders
except Exception as e:
logger.error(f"Error getting open orders count: {e}")
return 0
return self.open_orders_count # Return cached value on error
def _can_place_new_order(self) -> bool:
"""Check if we can place a new order based on open order limit"""
@ -359,7 +384,7 @@ class TradingExecutor:
return can_place
def sync_open_orders(self) -> Dict[str, Any]:
"""Synchronize open orders with exchange and update internal state
"""Synchronize open orders with exchange and update internal state with rate limiting
Returns:
dict: Sync result with status and order details
@ -373,6 +398,24 @@ class TradingExecutor:
'count': 0
}
# Check rate limiting
current_time = datetime.now()
time_since_last_sync = (current_time - self.last_open_orders_sync).total_seconds()
if time_since_last_sync < self.open_orders_sync_interval:
# Return cached result if within rate limit
logger.debug(f"Open order sync rate limited - using cached data")
return {
'status': 'rate_limited',
'message': f'Rate limited - last sync was {time_since_last_sync:.1f}s ago',
'orders': [],
'count': self.open_orders_count,
'cached': True
}
# Update last sync time
self.last_open_orders_sync = current_time
sync_result = {
'status': 'started',
'orders': [],
@ -408,7 +451,7 @@ class TradingExecutor:
except Exception as e:
error_msg = f"Error syncing orders for {symbol}: {e}"
logger.error(error_msg)
logger.warning(error_msg) # Changed to warning since this is expected with rate limits
sync_result['errors'].append(error_msg)
# Update internal state
@ -505,11 +548,30 @@ class TradingExecutor:
logger.warning(f"Maximum concurrent positions reached: {len(self.positions)}")
return False
# SYNC OPEN ORDERS BEFORE CHECKING LIMITS
# This ensures we have accurate position data before making decisions
if not self.simulation_mode:
try:
logger.debug(f"Syncing open orders before trade execution for {symbol}")
sync_result = self.sync_open_orders()
if sync_result.get('status') == 'success':
logger.debug(f"Open orders synced successfully: {sync_result.get('count', 0)} orders")
else:
logger.warning(f"Open orders sync failed: {sync_result.get('message', 'Unknown error')}")
except Exception as e:
logger.warning(f"Error syncing open orders: {e}")
# Check open order limit
if not self._can_place_new_order():
logger.warning(f"Maximum open orders reached: {self._get_open_orders_count()}/{self.max_open_orders}")
return False
# Check position size limit before opening new positions
if action in ['BUY', 'SHORT'] and symbol not in self.positions:
if not self._check_position_size_limit():
logger.warning(f"Position size limit reached - cannot open new position for {symbol}")
return False
return True
def _execute_buy(self, symbol: str, confidence: float, current_price: float) -> bool:
@ -1153,25 +1215,30 @@ class TradingExecutor:
return False
def _calculate_position_size(self, confidence: float, current_price: float) -> float:
"""Calculate position size - use 100% of account balance for short-term scalping"""
"""Calculate position size - limited to 20% of account balance by default"""
# Get account balance (simulation or real)
account_balance = self._get_account_balance_for_sizing()
# Use 100% of account balance since we're holding for seconds/minutes only
# Scale by confidence: 70-100% of balance based on confidence (0.7-1.0 range)
# Get maximum position size limit (default 20% of balance)
max_position_percentage = self.mexc_config.get('max_position_percentage', 0.20)
max_position_value = account_balance * max_position_percentage
# Calculate desired position size based on confidence
# Scale by confidence: 70-100% of max position size based on confidence (0.7-1.0 range)
confidence_multiplier = max(0.7, min(1.0, confidence))
position_value = account_balance * confidence_multiplier
desired_position_value = max_position_value * confidence_multiplier
# Apply reduction based on consecutive losses (risk management)
reduction_factor = self.mexc_config.get('consecutive_loss_reduction_factor', 0.8)
adjusted_reduction_factor = reduction_factor ** self.consecutive_losses
position_value *= adjusted_reduction_factor
final_position_value = desired_position_value * adjusted_reduction_factor
logger.debug(f"Position calculation: account=${account_balance:.2f}, "
f"max_position=${max_position_value:.2f} ({max_position_percentage*100:.0f}%), "
f"confidence_mult={confidence_multiplier:.2f}, "
f"position=${position_value:.2f}, confidence={confidence:.2f}")
f"final_position=${final_position_value:.2f}, confidence={confidence:.2f}")
return position_value
return final_position_value
def _get_account_balance_for_sizing(self) -> float:
"""Get account balance for position sizing calculations"""
@ -1188,6 +1255,64 @@ class TradingExecutor:
logger.warning(f"Failed to get live account balance: {e}, using simulation default")
return self.mexc_config.get('simulation_account_usd', 100.0)
def _check_position_size_limit(self) -> bool:
"""Check if total open position value exceeds the maximum allowed percentage of balance"""
try:
# Get account balance
account_balance = self._get_account_balance_for_sizing()
# Get maximum position percentage (default 20%)
max_position_percentage = self.mexc_config.get('max_position_percentage', 0.20)
max_position_value = account_balance * max_position_percentage
# Calculate total current position value
total_position_value = 0.0
# Add existing positions
for symbol, position in self.positions.items():
# Get current price for the symbol
try:
ticker = self.exchange.get_ticker(symbol) if self.exchange else None
current_price = ticker['last'] if ticker and 'last' in ticker else position.entry_price
except Exception:
# Fallback to entry price if we can't get current price
current_price = position.entry_price
# Calculate position value
position_value = position.quantity * current_price
total_position_value += position_value
logger.debug(f"Existing position {symbol}: {position.quantity:.6f} @ ${current_price:.2f} = ${position_value:.2f}")
# Add potential value from open orders that could become positions
if not self.simulation_mode and self.exchange:
try:
open_orders = self.exchange.get_open_orders()
for order in open_orders:
if order.get('side', '').lower() in ['buy', 'sell']:
# Estimate the value if this order gets filled
order_quantity = float(order.get('quantity', 0))
order_price = float(order.get('price', 0))
if order_price > 0:
order_value = order_quantity * order_price
total_position_value += order_value
logger.debug(f"Open order {order.get('symbol')}: {order_quantity:.6f} @ ${order_price:.2f} = ${order_value:.2f}")
except Exception as e:
logger.debug(f"Error calculating open order values: {e}")
# Check if we would exceed the limit
if total_position_value >= max_position_value:
logger.warning(f"Position size limit reached: ${total_position_value:.2f} >= ${max_position_value:.2f} ({max_position_percentage*100:.0f}% of balance)")
return False
logger.debug(f"Position size check passed: ${total_position_value:.2f} < ${max_position_value:.2f} ({max_position_percentage*100:.0f}% of balance)")
return True
except Exception as e:
logger.error(f"Error checking position size limit: {e}")
# Allow trade if we can't check the limit
return True
def update_positions(self, symbol: str, current_price: float):
"""Update position P&L with current market price"""
if symbol in self.positions:

View File

@ -0,0 +1,306 @@
"""
Enhanced Position Synchronization System
Addresses the gap between dashboard position display and actual exchange account state
"""
import logging
import time
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any
logger = logging.getLogger(__name__)
class EnhancedPositionSync:
"""Enhanced position synchronization to ensure dashboard matches actual exchange state"""
def __init__(self, trading_executor, dashboard):
self.trading_executor = trading_executor
self.dashboard = dashboard
self.last_sync_time = 0
self.sync_interval = 10 # Sync every 10 seconds
self.position_history = [] # Track position changes
def sync_all_positions(self) -> Dict[str, Any]:
"""Comprehensive position sync for all symbols"""
try:
sync_results = {}
# 1. Get actual exchange positions
exchange_positions = self._get_actual_exchange_positions()
# 2. Get dashboard positions
dashboard_positions = self._get_dashboard_positions()
# 3. Compare and sync
for symbol in ['ETH/USDT', 'BTC/USDT']:
sync_result = self._sync_symbol_position(
symbol,
exchange_positions.get(symbol),
dashboard_positions.get(symbol)
)
sync_results[symbol] = sync_result
# 4. Update closed trades list from exchange
self._sync_closed_trades()
return {
'sync_time': datetime.now().isoformat(),
'results': sync_results,
'total_synced': len(sync_results),
'issues_found': sum(1 for r in sync_results.values() if not r['in_sync'])
}
except Exception as e:
logger.error(f"Error in comprehensive position sync: {e}")
return {'error': str(e)}
def _get_actual_exchange_positions(self) -> Dict[str, Dict]:
"""Get actual positions from exchange account"""
try:
positions = {}
if not self.trading_executor:
return positions
# Get account balances
if hasattr(self.trading_executor, 'get_account_balance'):
balances = self.trading_executor.get_account_balance()
for symbol in ['ETH/USDT', 'BTC/USDT']:
# Parse symbol to get base asset
base_asset = symbol.split('/')[0]
# Get balance for base asset
base_balance = balances.get(base_asset, {}).get('total', 0.0)
if base_balance > 0.001: # Minimum threshold
positions[symbol] = {
'side': 'LONG',
'size': base_balance,
'value': base_balance * self._get_current_price(symbol),
'source': 'exchange_balance'
}
# Also check trading executor's position tracking
if hasattr(self.trading_executor, 'get_positions'):
executor_positions = self.trading_executor.get_positions()
for symbol, position in executor_positions.items():
if position and hasattr(position, 'quantity') and position.quantity > 0:
positions[symbol] = {
'side': position.side,
'size': position.quantity,
'entry_price': position.entry_price,
'value': position.quantity * self._get_current_price(symbol),
'source': 'executor_tracking'
}
return positions
except Exception as e:
logger.error(f"Error getting actual exchange positions: {e}")
return {}
def _get_dashboard_positions(self) -> Dict[str, Dict]:
"""Get positions as shown on dashboard"""
try:
positions = {}
# Get from dashboard's current_position
if self.dashboard.current_position:
symbol = self.dashboard.current_position.get('symbol', 'ETH/USDT')
positions[symbol] = {
'side': self.dashboard.current_position.get('side'),
'size': self.dashboard.current_position.get('size'),
'entry_price': self.dashboard.current_position.get('price'),
'value': self.dashboard.current_position.get('size', 0) * self._get_current_price(symbol),
'source': 'dashboard_display'
}
return positions
except Exception as e:
logger.error(f"Error getting dashboard positions: {e}")
return {}
def _sync_symbol_position(self, symbol: str, exchange_pos: Optional[Dict], dashboard_pos: Optional[Dict]) -> Dict[str, Any]:
"""Sync position for a specific symbol"""
try:
sync_result = {
'symbol': symbol,
'exchange_position': exchange_pos,
'dashboard_position': dashboard_pos,
'in_sync': True,
'action_taken': 'none'
}
# Case 1: Exchange has position, dashboard doesn't
if exchange_pos and not dashboard_pos:
logger.warning(f"SYNC ISSUE: Exchange has {symbol} position but dashboard shows none")
# Update dashboard to reflect exchange position
self.dashboard.current_position = {
'symbol': symbol,
'side': exchange_pos['side'],
'size': exchange_pos['size'],
'price': exchange_pos.get('entry_price', self._get_current_price(symbol)),
'entry_time': datetime.now(),
'leverage': self.dashboard.current_leverage,
'source': 'sync_correction'
}
sync_result['in_sync'] = False
sync_result['action_taken'] = 'updated_dashboard_from_exchange'
# Case 2: Dashboard has position, exchange doesn't
elif dashboard_pos and not exchange_pos:
logger.warning(f"SYNC ISSUE: Dashboard shows {symbol} position but exchange has none")
# Clear dashboard position
self.dashboard.current_position = None
sync_result['in_sync'] = False
sync_result['action_taken'] = 'cleared_dashboard_position'
# Case 3: Both have positions but they differ
elif exchange_pos and dashboard_pos:
if (exchange_pos['side'] != dashboard_pos['side'] or
abs(exchange_pos['size'] - dashboard_pos['size']) > 0.001):
logger.warning(f"SYNC ISSUE: {symbol} position mismatch - Exchange: {exchange_pos['side']} {exchange_pos['size']:.3f}, Dashboard: {dashboard_pos['side']} {dashboard_pos['size']:.3f}")
# Update dashboard to match exchange
self.dashboard.current_position.update({
'side': exchange_pos['side'],
'size': exchange_pos['size'],
'price': exchange_pos.get('entry_price', dashboard_pos['entry_price'])
})
sync_result['in_sync'] = False
sync_result['action_taken'] = 'updated_dashboard_to_match_exchange'
return sync_result
except Exception as e:
logger.error(f"Error syncing position for {symbol}: {e}")
return {'symbol': symbol, 'error': str(e), 'in_sync': False}
def _sync_closed_trades(self):
"""Sync closed trades list with actual exchange trade history"""
try:
if not self.trading_executor:
return
# Get trade history from executor
if hasattr(self.trading_executor, 'get_trade_history'):
executor_trades = self.trading_executor.get_trade_history()
# Clear and rebuild closed_trades list
self.dashboard.closed_trades = []
for trade in executor_trades:
# Convert to dashboard format
trade_record = {
'symbol': getattr(trade, 'symbol', 'ETH/USDT'),
'side': getattr(trade, 'side', 'UNKNOWN'),
'quantity': getattr(trade, 'quantity', 0),
'entry_price': getattr(trade, 'entry_price', 0),
'exit_price': getattr(trade, 'exit_price', 0),
'entry_time': getattr(trade, 'entry_time', datetime.now()),
'exit_time': getattr(trade, 'exit_time', datetime.now()),
'pnl': getattr(trade, 'pnl', 0),
'fees': getattr(trade, 'fees', 0),
'confidence': getattr(trade, 'confidence', 1.0),
'trade_type': 'synced_from_executor'
}
# Only add completed trades (with exit_time)
if trade_record['exit_time']:
self.dashboard.closed_trades.append(trade_record)
# Update session PnL
self.dashboard.session_pnl = sum(trade['pnl'] for trade in self.dashboard.closed_trades)
logger.info(f"Synced {len(self.dashboard.closed_trades)} closed trades from executor")
except Exception as e:
logger.error(f"Error syncing closed trades: {e}")
def _get_current_price(self, symbol: str) -> float:
"""Get current price for a symbol"""
try:
return self.dashboard._get_current_price(symbol) or 3500.0
except:
return 3500.0 # Fallback price
def should_sync(self) -> bool:
"""Check if sync is needed based on time interval"""
current_time = time.time()
if current_time - self.last_sync_time >= self.sync_interval:
self.last_sync_time = current_time
return True
return False
def create_sync_status_display(self) -> Dict[str, Any]:
"""Create detailed sync status for dashboard display"""
try:
# Get current sync status
sync_results = self.sync_all_positions()
# Create display-friendly format
status_display = {
'last_sync': datetime.now().strftime('%H:%M:%S'),
'sync_healthy': sync_results.get('issues_found', 0) == 0,
'positions': {},
'closed_trades_count': len(self.dashboard.closed_trades),
'session_pnl': self.dashboard.session_pnl
}
# Add position details
for symbol, result in sync_results.get('results', {}).items():
status_display['positions'][symbol] = {
'in_sync': result['in_sync'],
'action_taken': result.get('action_taken', 'none'),
'has_exchange_position': result['exchange_position'] is not None,
'has_dashboard_position': result['dashboard_position'] is not None
}
return status_display
except Exception as e:
logger.error(f"Error creating sync status display: {e}")
return {'error': str(e)}
# Integration with existing dashboard
def integrate_enhanced_sync(dashboard):
"""Integrate enhanced sync with existing dashboard"""
# Create enhanced sync instance
enhanced_sync = EnhancedPositionSync(dashboard.trading_executor, dashboard)
# Add to dashboard
dashboard.enhanced_sync = enhanced_sync
# Modify existing metrics update to include sync
original_update_metrics = dashboard.update_metrics
def enhanced_update_metrics(n):
"""Enhanced metrics update with position sync"""
try:
# Perform periodic sync
if enhanced_sync.should_sync():
sync_results = enhanced_sync.sync_all_positions()
if sync_results.get('issues_found', 0) > 0:
logger.info(f"Position sync performed: {sync_results['issues_found']} issues corrected")
# Call original metrics update
return original_update_metrics(n)
except Exception as e:
logger.error(f"Error in enhanced metrics update: {e}")
return original_update_metrics(n)
# Replace the update method
dashboard.update_metrics = enhanced_update_metrics
return enhanced_sync

View File

@ -118,6 +118,9 @@ class CleanTradingDashboard:
)
self.component_manager = DashboardComponentManager()
# Initialize enhanced position sync system
self._initialize_enhanced_position_sync()
# Initialize Universal Data Adapter access through orchestrator
if UNIVERSAL_DATA_AVAILABLE:
self.universal_adapter = UniversalDataAdapter(self.data_provider)
@ -2711,26 +2714,58 @@ class CleanTradingDashboard:
}
def _sync_position_from_executor(self, symbol: str):
"""Sync current position from trading executor"""
"""Sync current position from trading executor and real Bybit positions"""
try:
if self.trading_executor and hasattr(self.trading_executor, 'get_current_position'):
executor_position = self.trading_executor.get_current_position(symbol)
if executor_position:
# Update dashboard position to match executor
self.current_position = {
'side': executor_position.get('side', 'UNKNOWN'),
'size': executor_position.get('size', 0),
'price': executor_position.get('price', 0),
'symbol': executor_position.get('symbol', symbol),
'entry_time': executor_position.get('entry_time', datetime.now()),
'leverage': self.current_leverage, # Store current leverage with position
'unrealized_pnl': executor_position.get('unrealized_pnl', 0)
}
logger.debug(f"Synced position from executor: {self.current_position['side']} {self.current_position['size']:.3f}")
# First try to get real position from Bybit
real_position = None
if self.trading_executor and hasattr(self.trading_executor, 'exchange'):
try:
# Get real positions from Bybit
bybit_positions = self.trading_executor.exchange.get_positions(symbol)
if bybit_positions:
# Use the first real position found
real_position = bybit_positions[0]
logger.info(f"Found real Bybit position: {real_position}")
else:
logger.debug("No real positions found on Bybit")
except Exception as e:
logger.debug(f"Error getting real Bybit positions: {e}")
# If we have a real position, use it
if real_position:
self.current_position = {
'side': 'LONG' if real_position.get('side', '').lower() == 'buy' else 'SHORT',
'size': real_position.get('size', 0),
'price': real_position.get('entry_price', 0),
'symbol': real_position.get('symbol', symbol),
'entry_time': datetime.now(), # We don't have entry time from API
'leverage': real_position.get('leverage', self.current_leverage),
'unrealized_pnl': real_position.get('unrealized_pnl', 0)
}
logger.info(f"Synced real Bybit position: {self.current_position['side']} {self.current_position['size']:.3f} @ ${self.current_position['price']:.2f}")
else:
# Fallback to executor's internal tracking
if self.trading_executor and hasattr(self.trading_executor, 'get_current_position'):
executor_position = self.trading_executor.get_current_position(symbol)
if executor_position:
# Update dashboard position to match executor
self.current_position = {
'side': executor_position.get('side', 'UNKNOWN'),
'size': executor_position.get('size', 0),
'price': executor_position.get('price', 0),
'symbol': executor_position.get('symbol', symbol),
'entry_time': executor_position.get('entry_time', datetime.now()),
'leverage': self.current_leverage, # Store current leverage with position
'unrealized_pnl': executor_position.get('unrealized_pnl', 0)
}
logger.debug(f"Synced position from executor: {self.current_position['side']} {self.current_position['size']:.3f}")
else:
# No position in executor
self.current_position = None
logger.debug("No position in trading executor")
else:
# No position in executor
self.current_position = None
logger.debug("No position in trading executor")
logger.debug("No trading executor available")
except Exception as e:
logger.debug(f"Error syncing position from executor: {e}")
@ -3999,7 +4034,7 @@ class CleanTradingDashboard:
logger.error(f"Error verifying position sync after trade: {e}")
def _periodic_position_sync_check(self):
"""Periodically check and sync position with MEXC account"""
"""Periodically check and sync position with Bybit account"""
try:
symbol = 'ETH/USDT'
@ -4007,26 +4042,18 @@ class CleanTradingDashboard:
if not self.trading_executor or getattr(self.trading_executor, 'simulation_mode', True):
return
# Determine current desired state based on dashboard position
# Sync real positions from Bybit
logger.debug(f"PERIODIC SYNC: Syncing real Bybit positions for {symbol}")
self._sync_position_from_executor(symbol)
# Log current position state
if self.current_position:
side = self.current_position.get('side', 'UNKNOWN')
if side.upper() in ['LONG', 'BUY']:
desired_state = 'LONG'
elif side.upper() in ['SHORT', 'SELL']:
desired_state = 'SHORT'
else:
desired_state = 'NO_POSITION'
size = self.current_position.get('size', 0)
price = self.current_position.get('price', 0)
logger.info(f"PERIODIC SYNC: Current position: {side} {size:.3f} @ ${price:.2f}")
else:
desired_state = 'NO_POSITION'
# Perform periodic sync check
logger.debug(f"PERIODIC SYNC: Checking position sync for {symbol} (desired: {desired_state})")
sync_success = self._sync_position_with_mexc(symbol, desired_state)
if sync_success:
logger.debug(f"PERIODIC SYNC: Position sync verified for {symbol}")
else:
logger.warning(f"PERIODIC SYNC: Position sync issue detected for {symbol}")
logger.info(f"PERIODIC SYNC: No current position for {symbol}")
except Exception as e:
logger.debug(f"Error in periodic position sync check: {e}")
@ -4914,6 +4941,25 @@ class CleanTradingDashboard:
logger.error(f"Error initializing enhanced training system: {e}")
self.training_system = None
def _initialize_enhanced_position_sync(self):
"""Initialize enhanced position synchronization system"""
try:
logger.info("Initializing enhanced position sync system...")
# Initialize position sync if trading executor is available
if self.trading_executor:
# Set up periodic position sync
self.position_sync_enabled = True
self.position_sync_interval = 30 # seconds
logger.info("Enhanced position sync system initialized")
else:
logger.warning("Trading executor not available - position sync disabled")
self.position_sync_enabled = False
except Exception as e:
logger.error(f"Error initializing enhanced position sync: {e}")
self.position_sync_enabled = False
def _initialize_cob_integration(self):
"""Initialize COB integration using orchestrator's COB system"""
try:
@ -6846,4 +6892,4 @@ def create_clean_dashboard(data_provider: Optional[DataProvider] = None, orchest
)
# test edit
# test edit