This commit is contained in:
Dobromir Popov
2025-07-14 22:22:16 +03:00
parent 4a55c5ff03
commit ee2e6478d8
11 changed files with 1268 additions and 35 deletions

View File

@@ -95,10 +95,14 @@ class TradingExecutor:
logger.info(f"Trading Executor initialized with {primary_name} as primary exchange")
logger.info(f"Trading mode: {trading_mode}, Simulation: {self.simulation_mode}")
# Get primary exchange name and config
self.primary_name = self.exchanges_config.get('primary', 'mexc')
self.primary_config = self.exchanges_config.get(self.primary_name, {})
# Initialize config synchronizer with the primary exchange
self.config_sync = ConfigSynchronizer(
config_path=config_path,
mexc_interface=self.exchange if self.trading_enabled else None
mexc_interface=self.exchange if (self.trading_enabled and self.primary_name == 'mexc') else None
)
# Trading state management
@@ -111,9 +115,7 @@ class TradingExecutor:
self.consecutive_losses = 0 # Track consecutive losing trades
# Store trading mode for compatibility
primary_name = self.exchanges_config.get('primary', 'deribit')
primary_config = self.exchanges_config.get(primary_name, {})
self.trading_mode = primary_config.get('trading_mode', 'simulation')
self.trading_mode = self.primary_config.get('trading_mode', 'simulation')
# Initialize session stats
self.session_start_time = datetime.now()
@@ -144,16 +146,19 @@ class TradingExecutor:
logger.info(f"Trading Executor initialized - Mode: {self.trading_mode}, Enabled: {self.trading_enabled}")
# Initialize config synchronizer for automatic fee updates
# Get exchange-specific configuration
self.exchange_config = self.primary_config
# Initialize config synchronizer for automatic fee updates (only for MEXC)
self.config_synchronizer = ConfigSynchronizer(
config_path=config_path,
mexc_interface=self.exchange if self.trading_enabled else None
mexc_interface=self.exchange if (self.trading_enabled and self.primary_name == 'mexc') else None
)
# Perform initial fee sync on startup if trading is enabled
if self.trading_enabled and self.exchange:
# Perform initial fee sync on startup if trading is enabled and using MEXC
if self.trading_enabled and self.exchange and self.primary_name == 'mexc':
try:
logger.info("TRADING EXECUTOR: Performing initial fee synchronization with MEXC API")
logger.info(f"TRADING EXECUTOR: Performing initial fee synchronization with {self.primary_name.upper()} API")
sync_result = self.config_synchronizer.sync_trading_fees(force=True)
if sync_result.get('status') == 'success':
logger.info("TRADING EXECUTOR: Fee synchronization completed successfully")
@@ -161,15 +166,17 @@ class TradingExecutor:
logger.info(f"TRADING EXECUTOR: Fee changes applied: {list(sync_result['changes'].keys())}")
# Reload config to get updated fees
self.config = get_config(config_path)
self.mexc_config = self.config.get('mexc_trading', {})
self.exchange_config = self.config.get('exchanges', {}).get(self.primary_name, {})
elif sync_result.get('status') == 'warning':
logger.warning("TRADING EXECUTOR: Fee sync completed with warnings")
else:
logger.warning(f"TRADING EXECUTOR: Fee sync failed: {sync_result.get('status')}")
except Exception as e:
logger.warning(f"TRADING EXECUTOR: Initial fee sync failed: {e}")
elif self.trading_enabled and self.exchange:
logger.info(f"TRADING EXECUTOR: Using {self.primary_name.upper()} exchange - fee sync not available")
logger.info(f"Trading Executor initialized - Mode: {self.trading_mode}, Enabled: {self.trading_enabled}")
logger.info(f"Trading Executor initialized - Exchange: {self.primary_name.upper()}, Mode: {self.trading_mode}, Enabled: {self.trading_enabled}")
def _safe_exchange_call(self, method_name: str, *args, **kwargs):
"""Safely call exchange methods with null checking"""
@@ -343,30 +350,26 @@ class TradingExecutor:
def _check_safety_conditions(self, symbol: str, action: str) -> bool:
"""Check if it's safe to execute a trade"""
# Check if trading is stopped
if self.mexc_config.get('emergency_stop', False):
if self.exchange_config.get('emergency_stop', False):
logger.warning("Emergency stop is active - no trades allowed")
return False
# Check symbol allowlist
allowed_symbols = self.mexc_config.get('allowed_symbols', [])
allowed_symbols = self.exchange_config.get('allowed_symbols', [])
if allowed_symbols and symbol not in allowed_symbols:
logger.warning(f"Symbol {symbol} not in allowed list: {allowed_symbols}")
return False
# Check daily loss limit
max_daily_loss = self.mexc_config.get('max_daily_loss_usd', 5.0)
# Check daily loss limit (use trading config as fallback)
max_daily_loss = self.exchange_config.get('max_daily_loss_usd',
self.trading_config.get('max_daily_loss_usd', 200.0))
if self.daily_loss >= max_daily_loss:
logger.warning(f"Daily loss limit reached: ${self.daily_loss:.2f} >= ${max_daily_loss}")
return False
# Check daily trade limit
# max_daily_trades = self.mexc_config.get('max_daily_trades', 100)
# if self.daily_trades >= max_daily_trades:
# logger.warning(f"Daily trade limit reached: {self.daily_trades}")
# return False
# Check trade interval - allow bypass for test scenarios
min_interval = self.mexc_config.get('min_trade_interval_seconds', 5)
min_interval = self.exchange_config.get('min_trade_interval_seconds',
self.trading_config.get('min_trade_interval_seconds', 5))
last_trade = self.last_trade_time.get(symbol, datetime.min)
time_since_last = (datetime.now() - last_trade).total_seconds()
@@ -382,7 +385,8 @@ class TradingExecutor:
return False
# Check concurrent positions
max_positions = self.mexc_config.get('max_concurrent_positions', 1)
max_positions = self.exchange_config.get('max_concurrent_positions',
self.trading_config.get('max_concurrent_positions', 3))
if len(self.positions) >= max_positions and action == 'BUY':
logger.warning(f"Maximum concurrent positions reached: {len(self.positions)}")
return False
@@ -767,7 +771,8 @@ class TradingExecutor:
if self.simulation_mode:
logger.info(f"SIMULATION MODE ({self.trading_mode.upper()}) - Short close logged but not executed")
# Calculate simulated fees in simulation mode
taker_fee_rate = self.mexc_config.get('trading_fees', {}).get('taker_fee', 0.0006)
trading_fees = self.exchange_config.get('trading_fees', {})
taker_fee_rate = trading_fees.get('taker_fee', trading_fees.get('default_fee', 0.0006))
simulated_fees = position.quantity * current_price * taker_fee_rate
# Calculate P&L for short position and hold time
@@ -811,7 +816,7 @@ class TradingExecutor:
try:
# Get order type from config
order_type = self.mexc_config.get('order_type', 'market').lower()
order_type = self.exchange_config.get('order_type', 'market').lower()
# For limit orders, set price slightly above market for immediate execution
limit_price = None
@@ -952,7 +957,7 @@ class TradingExecutor:
try:
# Get order type from config
order_type = self.mexc_config.get('order_type', 'market').lower()
order_type = self.exchange_config.get('order_type', 'market').lower()
# For limit orders, set price slightly below market for immediate execution
limit_price = None
@@ -1858,4 +1863,4 @@ class TradingExecutor:
logger.error(f"Error executing corrective trades: {e}")
import traceback
logger.error(f"CORRECTIVE: Full traceback: {traceback.format_exc()}")
return False
return False