This commit is contained in:
Dobromir Popov
2025-07-14 17:56:09 +03:00
parent d53a2ba75d
commit 4a55c5ff03
11 changed files with 1509 additions and 118 deletions

View File

@ -22,7 +22,8 @@ import sys
# Add NN directory to path for exchange interfaces
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'NN'))
from NN.exchanges import MEXCInterface
from NN.exchanges.exchange_factory import ExchangeFactory
from NN.exchanges.exchange_interface import ExchangeInterface
from .config import get_config
from .config_sync import ConfigSynchronizer
@ -63,53 +64,68 @@ class TradeRecord:
hold_time_seconds: float = 0.0 # Hold time in seconds
class TradingExecutor:
"""Handles trade execution through MEXC API with risk management"""
"""Handles trade execution through multiple exchange APIs with risk management"""
def __init__(self, config_path: str = "config.yaml"):
"""Initialize the trading executor"""
self.config = get_config(config_path)
self.mexc_config = self.config.get('mexc_trading', {})
self.exchanges_config = self.config.get('exchanges', {})
self.trading_config = self.config.get('trading', {})
# Initialize MEXC interface
api_key = os.getenv('MEXC_API_KEY', self.mexc_config.get('api_key', ''))
api_secret = os.getenv('MEXC_SECRET_KEY', self.mexc_config.get('api_secret', ''))
# Initialize exchanges using factory
self.primary_exchange = ExchangeFactory.get_primary_exchange(self.exchanges_config)
self.all_exchanges = ExchangeFactory.create_multiple_exchanges(self.exchanges_config)
# Determine trading mode from unified config
trading_mode = self.mexc_config.get('trading_mode', 'simulation')
# Set primary exchange as main interface
self.exchange = self.primary_exchange
# Map trading mode to exchange test_mode and execution mode
if trading_mode == 'simulation':
exchange_test_mode = True
if not self.exchange:
logger.error("Failed to initialize primary exchange")
self.trading_enabled = False
self.simulation_mode = True
elif trading_mode == 'testnet':
exchange_test_mode = True
self.simulation_mode = False
elif trading_mode == 'live':
exchange_test_mode = False
self.simulation_mode = False
else:
logger.warning(f"Unknown trading_mode '{trading_mode}', defaulting to simulation")
exchange_test_mode = True
self.simulation_mode = True
primary_name = self.exchanges_config.get('primary', 'deribit')
primary_config = self.exchanges_config.get(primary_name, {})
# Determine trading and simulation modes
trading_mode = primary_config.get('trading_mode', 'simulation')
self.trading_enabled = self.trading_config.get('enabled', True)
self.simulation_mode = trading_mode == 'simulation'
logger.info(f"Trading Executor initialized with {primary_name} as primary exchange")
logger.info(f"Trading mode: {trading_mode}, Simulation: {self.simulation_mode}")
self.exchange = MEXCInterface(
api_key=api_key,
api_secret=api_secret,
test_mode=exchange_test_mode,
# 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
)
# Trading state
self.positions: Dict[str, Position] = {}
self.trade_history: List[TradeRecord] = []
# Trading state management
self.current_position = {} # symbol -> position data
self.trade_history = []
self.daily_trades = 0
self.daily_pnl = 0.0
self.daily_loss = 0.0
self.last_trade_time = {}
self.trading_enabled = self.mexc_config.get('enabled', False)
self.trading_mode = trading_mode
self.consecutive_losses = 0 # Track consecutive losing trades
logger.debug(f"TRADING EXECUTOR: Initial trading_enabled state from config: {self.trading_enabled}")
# 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')
# Initialize session stats
self.session_start_time = datetime.now()
self.session_trades = 0
self.session_pnl = 0.0
# Position tracking
self.positions = {} # symbol -> Position object
self.trade_records = [] # List of TradeRecord objects
logger.info(f"TradingExecutor initialized - Trading: {self.trading_enabled}, Mode: {self.trading_mode}")
# Legacy compatibility (deprecated)
self.dry_run = self.simulation_mode
@ -155,24 +171,34 @@ class TradingExecutor:
logger.info(f"Trading Executor initialized - Mode: {self.trading_mode}, Enabled: {self.trading_enabled}")
def _connect_exchange(self) -> bool:
"""Connect to the MEXC exchange"""
def _safe_exchange_call(self, method_name: str, *args, **kwargs):
"""Safely call exchange methods with null checking"""
if not self.exchange:
logger.warning(f"No exchange interface available for {method_name}")
return None
try:
logger.debug("TRADING EXECUTOR: Calling self.exchange.connect()...")
connected = self.exchange.connect()
logger.debug(f"TRADING EXECUTOR: self.exchange.connect() returned: {connected}")
if connected:
logger.info("Successfully connected to MEXC exchange")
return True
method = getattr(self.exchange, method_name, None)
if method:
return method(*args, **kwargs)
else:
logger.error("Failed to connect to MEXC exchange: Connection returned False.")
if not self.dry_run:
logger.info("TRADING EXECUTOR: Setting trading_enabled to False due to connection failure.")
self.trading_enabled = False
return False
logger.error(f"Method {method_name} not available on exchange")
return None
except Exception as e:
logger.error(f"Error connecting to MEXC exchange: {e}. Setting trading_enabled to False.")
self.trading_enabled = False
logger.error(f"Error calling {method_name}: {e}")
return None
def _connect_exchange(self) -> bool:
"""Connect to the primary exchange"""
if not self.exchange:
logger.warning("No exchange interface available")
return False
if self.exchange.connect():
logger.info("Successfully connected to exchange")
return True
else:
logger.error("Failed to connect to exchange")
return False
def execute_signal(self, symbol: str, action: str, confidence: float,