stability
This commit is contained in:
@ -317,4 +317,32 @@ def setup_logging(config: Optional[Config] = None):
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to initialize error log handler: {e}")
|
||||
|
||||
# Add dedicated trade log to capture all NN signals (executed and ignored)
|
||||
try:
|
||||
from logging.handlers import RotatingFileHandler
|
||||
trade_log_dir = Path('logs')
|
||||
trade_log_dir.mkdir(parents=True, exist_ok=True)
|
||||
trade_log_path = trade_log_dir / 'trades.log'
|
||||
|
||||
class FlushingTradeHandler(RotatingFileHandler):
|
||||
def emit(self, record):
|
||||
super().emit(record)
|
||||
self.flush()
|
||||
|
||||
trade_handler = FlushingTradeHandler(
|
||||
str(trade_log_path), maxBytes=20*1024*1024, backupCount=10, encoding='utf-8'
|
||||
)
|
||||
trade_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
||||
trade_handler.setFormatter(trade_formatter)
|
||||
trade_handler.setLevel(logging.INFO)
|
||||
|
||||
trade_logger = logging.getLogger('trade_log')
|
||||
trade_logger.setLevel(logging.INFO)
|
||||
trade_logger.addHandler(trade_handler)
|
||||
# Avoid double propagation to root to keep trade log clean
|
||||
trade_logger.propagate = False
|
||||
logger.info("Trade log handler initialized at logs/trades.log")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to initialize trade log handler: {e}")
|
||||
|
||||
logger.info("Logging configured successfully with SafeFormatter")
|
||||
|
@ -608,21 +608,18 @@ class CleanTradingDashboard:
|
||||
|
||||
def _monitor_order_execution(self):
|
||||
"""Monitor order execution status in live mode and update dashboard signals"""
|
||||
try:
|
||||
logger.info("Starting order execution monitoring for live mode")
|
||||
while True:
|
||||
try:
|
||||
time.sleep(5) # Check every 5 seconds
|
||||
|
||||
# Check for signals that were attempted but not yet executed
|
||||
for decision in self.recent_decisions:
|
||||
if (decision.get('execution_attempted', False) and
|
||||
not decision.get('executed', False) and
|
||||
not decision.get('execution_failure', False)):
|
||||
|
||||
# Check if the order was actually filled
|
||||
symbol = decision.get('symbol', 'ETH/USDT')
|
||||
action = decision.get('action', 'HOLD')
|
||||
|
||||
# Check if position was actually opened/closed
|
||||
if self.trading_executor and hasattr(self.trading_executor, 'positions'):
|
||||
if symbol in self.trading_executor.positions:
|
||||
@ -639,9 +636,8 @@ class CleanTradingDashboard:
|
||||
else:
|
||||
# No position exists, order might still be pending
|
||||
logger.debug(f"No position found for {symbol}, order may still be pending")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in order execution monitoring: {e}")
|
||||
logger.warning(f"Order execution monitoring iteration error: {e}")
|
||||
|
||||
def _delayed_training_check(self):
|
||||
"""Check and start training after a delay to allow initialization"""
|
||||
@ -8898,6 +8894,7 @@ class CleanTradingDashboard:
|
||||
async def _on_trading_decision(self, decision):
|
||||
"""Handle trading decision from orchestrator and execute through trading executor."""
|
||||
try:
|
||||
trade_logger = logging.getLogger('trade_log')
|
||||
# Handle both object and dict formats
|
||||
if hasattr(decision, 'action'):
|
||||
action = getattr(decision, 'action', 'HOLD')
|
||||
@ -8940,6 +8937,10 @@ class CleanTradingDashboard:
|
||||
dashboard_decision['source'] = 'Unknown'
|
||||
|
||||
logger.info(f"[ORCHESTRATOR SIGNAL] Received: {action} for {symbol} (confidence: {confidence:.3f})")
|
||||
try:
|
||||
trade_logger.info(f"SIGNAL action={action} symbol={symbol} confidence={confidence:.4f} price={price if price is not None else 'NA'} source={dashboard_decision.get('source','Unknown')}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# EXECUTE THE DECISION THROUGH TRADING EXECUTOR
|
||||
# check if we are entering or exiting a position with this signal
|
||||
@ -9003,6 +9004,10 @@ class CleanTradingDashboard:
|
||||
else:
|
||||
logger.warning(f"[ORCHESTRATOR EXECUTION] FAILED: {action} execution blocked for {symbol}")
|
||||
dashboard_decision['execution_failure'] = True
|
||||
try:
|
||||
trade_logger.info(f"IGNORED action={action} symbol={symbol} confidence={confidence:.4f} reason=blocked")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[ORCHESTRATOR EXECUTION] ERROR: Failed to execute {action} for {symbol}: {e}")
|
||||
@ -9010,11 +9015,26 @@ class CleanTradingDashboard:
|
||||
else:
|
||||
if not self.trading_executor:
|
||||
logger.warning("[ORCHESTRATOR EXECUTION] No trading executor available")
|
||||
try:
|
||||
trade_logger.info(f"IGNORED action={action} symbol={symbol} confidence={confidence:.4f} reason=no_executor")
|
||||
except Exception:
|
||||
pass
|
||||
elif confidence <= 0.5:
|
||||
logger.info(f"[ORCHESTRATOR EXECUTION] Low confidence signal ignored: {action} for {symbol} (confidence: {confidence:.3f})")
|
||||
try:
|
||||
trade_logger.info(f"IGNORED action={action} symbol={symbol} confidence={confidence:.4f} reason=low_conf_threshold")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Store decision in dashboard
|
||||
self.recent_decisions.append(dashboard_decision)
|
||||
try:
|
||||
if dashboard_decision.get('executed'):
|
||||
trade_logger.info(f"EXECUTED action={action} symbol={symbol} confidence={confidence:.4f} executed={dashboard_decision.get('executed')} sim={self.trading_executor.simulation_mode if self.trading_executor else 'NA'}")
|
||||
elif dashboard_decision.get('execution_attempted'):
|
||||
trade_logger.info(f"ATTEMPTED action={action} symbol={symbol} confidence={confidence:.4f} live=True")
|
||||
except Exception:
|
||||
pass
|
||||
if len(self.recent_decisions) > 200:
|
||||
self.recent_decisions.pop(0)
|
||||
|
||||
@ -9102,8 +9122,18 @@ class CleanTradingDashboard:
|
||||
logger.info("WebSocket connected")
|
||||
self.is_streaming = True
|
||||
ws_url = "wss://stream.binance.com:9443/ws/ethusdt@kline_1s"
|
||||
backoff = 1
|
||||
while True:
|
||||
try:
|
||||
ws = websocket.WebSocketApp(ws_url, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open)
|
||||
ws.run_forever()
|
||||
ws.run_forever(ping_interval=20, ping_timeout=10)
|
||||
logger.info(f"WebSocket stopped, restarting in {backoff}s")
|
||||
time.sleep(backoff)
|
||||
backoff = min(backoff * 2, 60)
|
||||
except Exception as _ws_e:
|
||||
logger.error(f"WebSocket loop error: {_ws_e}")
|
||||
time.sleep(backoff)
|
||||
backoff = min(backoff * 2, 60)
|
||||
except Exception as e:
|
||||
logger.error(f"WebSocket worker error: {e}")
|
||||
self.is_streaming = False
|
||||
|
Reference in New Issue
Block a user