trading risk management
This commit is contained in:
0
core/exchanges/bybit/debug/Order_history_sample.md
Normal file
0
core/exchanges/bybit/debug/Order_history_sample.md
Normal file
@ -260,8 +260,113 @@ class TradingExecutor:
|
|||||||
elif self.trading_enabled and self.exchange:
|
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: Using {self.primary_name.upper()} exchange - fee sync not available")
|
||||||
|
|
||||||
|
# Sync positions from exchange on startup if in live mode
|
||||||
|
if not self.simulation_mode and self.exchange and self.trading_enabled:
|
||||||
|
self._sync_positions_on_startup()
|
||||||
|
|
||||||
logger.info(f"Trading Executor initialized - Exchange: {self.primary_name.upper()}, 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 _sync_positions_on_startup(self):
|
||||||
|
"""Sync positions from exchange on startup"""
|
||||||
|
try:
|
||||||
|
logger.info("TRADING EXECUTOR: Syncing positions from exchange on startup...")
|
||||||
|
|
||||||
|
# Get all open positions from exchange
|
||||||
|
if hasattr(self.exchange, 'get_positions'):
|
||||||
|
exchange_positions = self.exchange.get_positions()
|
||||||
|
if exchange_positions:
|
||||||
|
for position in exchange_positions:
|
||||||
|
symbol = position.get('symbol', '').replace('USDT', '/USDT')
|
||||||
|
size = float(position.get('size', 0))
|
||||||
|
side = position.get('side', '').upper()
|
||||||
|
entry_price = float(position.get('entry_price', 0))
|
||||||
|
|
||||||
|
if size > 0 and symbol and side in ['LONG', 'SHORT']:
|
||||||
|
# Create position object
|
||||||
|
pos_obj = Position(
|
||||||
|
symbol=symbol,
|
||||||
|
side=side,
|
||||||
|
quantity=size,
|
||||||
|
entry_price=entry_price,
|
||||||
|
entry_time=datetime.now()
|
||||||
|
)
|
||||||
|
self.positions[symbol] = pos_obj
|
||||||
|
logger.info(f"POSITION SYNC: Found {side} position for {symbol}: {size} @ ${entry_price:.2f}")
|
||||||
|
|
||||||
|
logger.info(f"POSITION SYNC: Synced {len(self.positions)} positions from exchange")
|
||||||
|
else:
|
||||||
|
logger.warning("Exchange does not support position retrieval")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"POSITION SYNC: Error syncing positions on startup: {e}")
|
||||||
|
|
||||||
|
def _sync_single_position_from_exchange(self, symbol: str, exchange_position: dict):
|
||||||
|
"""Sync a single position from exchange to local state"""
|
||||||
|
try:
|
||||||
|
size = float(exchange_position.get('size', 0))
|
||||||
|
side = exchange_position.get('side', '').upper()
|
||||||
|
entry_price = float(exchange_position.get('entry_price', 0))
|
||||||
|
|
||||||
|
if size > 0 and side in ['LONG', 'SHORT']:
|
||||||
|
pos_obj = Position(
|
||||||
|
symbol=symbol,
|
||||||
|
side=side,
|
||||||
|
quantity=size,
|
||||||
|
entry_price=entry_price,
|
||||||
|
entry_time=datetime.now()
|
||||||
|
)
|
||||||
|
self.positions[symbol] = pos_obj
|
||||||
|
logger.info(f"POSITION SYNC: Added {side} position for {symbol}: {size} @ ${entry_price:.2f}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error syncing single position for {symbol}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def close_all_positions(self):
|
||||||
|
"""Emergency close all positions - both local and exchange"""
|
||||||
|
logger.warning("CLOSE ALL POSITIONS: Starting emergency position closure")
|
||||||
|
positions_closed = 0
|
||||||
|
|
||||||
|
# Get all positions to close (local + exchange)
|
||||||
|
positions_to_close = set()
|
||||||
|
|
||||||
|
# Add local positions
|
||||||
|
for symbol in self.positions.keys():
|
||||||
|
positions_to_close.add(symbol)
|
||||||
|
|
||||||
|
# Add exchange positions if not in simulation mode
|
||||||
|
if not self.simulation_mode and self.exchange:
|
||||||
|
try:
|
||||||
|
exchange_positions = self.exchange.get_positions()
|
||||||
|
if exchange_positions:
|
||||||
|
for pos in exchange_positions:
|
||||||
|
symbol = pos.get('symbol', '').replace('USDT', '/USDT')
|
||||||
|
size = float(pos.get('size', 0))
|
||||||
|
if size > 0:
|
||||||
|
positions_to_close.add(symbol)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error getting exchange positions for closure: {e}")
|
||||||
|
|
||||||
|
# Close all positions
|
||||||
|
for symbol in positions_to_close:
|
||||||
|
try:
|
||||||
|
if symbol in self.positions:
|
||||||
|
position = self.positions[symbol]
|
||||||
|
if position.side == 'LONG':
|
||||||
|
if self._close_long_position(symbol, 1.0, position.entry_price):
|
||||||
|
positions_closed += 1
|
||||||
|
elif position.side == 'SHORT':
|
||||||
|
if self._close_short_position(symbol, 1.0, position.entry_price):
|
||||||
|
positions_closed += 1
|
||||||
|
else:
|
||||||
|
logger.warning(f"Position {symbol} found on exchange but not locally - manual intervention needed")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error closing position {symbol}: {e}")
|
||||||
|
|
||||||
|
logger.warning(f"CLOSE ALL POSITIONS: Closed {positions_closed} positions")
|
||||||
|
return positions_closed
|
||||||
|
|
||||||
def _safe_exchange_call(self, method_name: str, *args, **kwargs):
|
def _safe_exchange_call(self, method_name: str, *args, **kwargs):
|
||||||
"""Safely call exchange methods with null checking"""
|
"""Safely call exchange methods with null checking"""
|
||||||
if not self.exchange:
|
if not self.exchange:
|
||||||
@ -374,6 +479,27 @@ class TradingExecutor:
|
|||||||
if action == 'HOLD':
|
if action == 'HOLD':
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# PERIODIC POSITION SYNC: Every 10th signal execution, sync positions from exchange to prevent desync
|
||||||
|
if not hasattr(self, '_signal_count'):
|
||||||
|
self._signal_count = 0
|
||||||
|
self._signal_count += 1
|
||||||
|
|
||||||
|
if self._signal_count % 10 == 0 and not self.simulation_mode and self.exchange:
|
||||||
|
logger.debug(f"PERIODIC SYNC: Checking position sync for {symbol} (signal #{self._signal_count})")
|
||||||
|
try:
|
||||||
|
exchange_positions = self.exchange.get_positions(symbol)
|
||||||
|
if exchange_positions:
|
||||||
|
for pos in exchange_positions:
|
||||||
|
size = float(pos.get('size', 0))
|
||||||
|
if size > 0 and symbol not in self.positions:
|
||||||
|
logger.warning(f"DESYNC DETECTED: Found position on exchange but not locally for {symbol}")
|
||||||
|
self._sync_single_position_from_exchange(symbol, pos)
|
||||||
|
elif symbol in self.positions:
|
||||||
|
logger.warning(f"DESYNC DETECTED: Have local position but none on exchange for {symbol}")
|
||||||
|
# Consider removing local position or investigating further
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error in periodic position sync: {e}")
|
||||||
|
|
||||||
# Check safety conditions
|
# Check safety conditions
|
||||||
if not self._check_safety_conditions(symbol, action):
|
if not self._check_safety_conditions(symbol, action):
|
||||||
return False
|
return False
|
||||||
@ -866,17 +992,33 @@ class TradingExecutor:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def _execute_buy(self, symbol: str, confidence: float, current_price: float) -> bool:
|
def _execute_buy(self, symbol: str, confidence: float, current_price: float) -> bool:
|
||||||
"""Execute a buy order"""
|
"""Execute a buy order with enhanced position management"""
|
||||||
# Check if we have a short position to close
|
# CRITICAL: Check for existing positions (both local and exchange)
|
||||||
if symbol in self.positions:
|
if symbol in self.positions:
|
||||||
position = self.positions[symbol]
|
position = self.positions[symbol]
|
||||||
if position.side == 'SHORT':
|
if position.side == 'SHORT':
|
||||||
logger.info(f"Closing SHORT position in {symbol}")
|
logger.info(f"Closing SHORT position in {symbol}")
|
||||||
return self._close_short_position(symbol, confidence, current_price)
|
return self._close_short_position(symbol, confidence, current_price)
|
||||||
else:
|
else:
|
||||||
logger.info(f"Already have LONG position in {symbol}")
|
logger.warning(f"POSITION SAFETY: Already have LONG position in {symbol} - blocking duplicate trade")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# ADDITIONAL SAFETY: Double-check with exchange if not in simulation mode
|
||||||
|
if not self.simulation_mode and self.exchange:
|
||||||
|
try:
|
||||||
|
exchange_positions = self.exchange.get_positions(symbol)
|
||||||
|
if exchange_positions:
|
||||||
|
for pos in exchange_positions:
|
||||||
|
if float(pos.get('size', 0)) > 0:
|
||||||
|
logger.warning(f"POSITION SAFETY: Found existing position on exchange for {symbol} - blocking duplicate trade")
|
||||||
|
logger.warning(f"Position details: {pos}")
|
||||||
|
# Sync this position to local state
|
||||||
|
self._sync_single_position_from_exchange(symbol, pos)
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error checking exchange positions for {symbol}: {e}")
|
||||||
|
# Don't block trade if we can't check - but log it
|
||||||
|
|
||||||
# Cancel any existing open orders before placing new order
|
# Cancel any existing open orders before placing new order
|
||||||
if not self.simulation_mode:
|
if not self.simulation_mode:
|
||||||
self._cancel_open_orders(symbol)
|
self._cancel_open_orders(symbol)
|
||||||
@ -902,6 +1044,12 @@ class TradingExecutor:
|
|||||||
else:
|
else:
|
||||||
# Place real order with enhanced error handling
|
# Place real order with enhanced error handling
|
||||||
result = self._place_order_with_retry(symbol, 'BUY', 'MARKET', quantity, current_price)
|
result = self._place_order_with_retry(symbol, 'BUY', 'MARKET', quantity, current_price)
|
||||||
|
|
||||||
|
# Check for position check error
|
||||||
|
if result and 'error' in result and result['error'] == 'existing_position':
|
||||||
|
logger.error(f"BUY order blocked: {result['message']}")
|
||||||
|
return False
|
||||||
|
|
||||||
if result and 'orderId' in result:
|
if result and 'orderId' in result:
|
||||||
# Use actual fill information if available, otherwise fall back to order parameters
|
# Use actual fill information if available, otherwise fall back to order parameters
|
||||||
filled_quantity = result.get('executedQty', quantity)
|
filled_quantity = result.get('executedQty', quantity)
|
||||||
@ -943,7 +1091,27 @@ class TradingExecutor:
|
|||||||
return self._execute_short(symbol, confidence, current_price)
|
return self._execute_short(symbol, confidence, current_price)
|
||||||
|
|
||||||
def _execute_short(self, symbol: str, confidence: float, current_price: float) -> bool:
|
def _execute_short(self, symbol: str, confidence: float, current_price: float) -> bool:
|
||||||
"""Execute a short order (sell without holding the asset)"""
|
"""Execute a short order (sell without holding the asset) with enhanced position management"""
|
||||||
|
# CRITICAL: Check for any existing positions before opening SHORT
|
||||||
|
if symbol in self.positions:
|
||||||
|
logger.warning(f"POSITION SAFETY: Already have position in {symbol} - blocking SHORT trade")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# ADDITIONAL SAFETY: Double-check with exchange if not in simulation mode
|
||||||
|
if not self.simulation_mode and self.exchange:
|
||||||
|
try:
|
||||||
|
exchange_positions = self.exchange.get_positions(symbol)
|
||||||
|
if exchange_positions:
|
||||||
|
for pos in exchange_positions:
|
||||||
|
if float(pos.get('size', 0)) > 0:
|
||||||
|
logger.warning(f"POSITION SAFETY: Found existing position on exchange for {symbol} - blocking SHORT trade")
|
||||||
|
logger.warning(f"Position details: {pos}")
|
||||||
|
# Sync this position to local state
|
||||||
|
self._sync_single_position_from_exchange(symbol, pos)
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error checking exchange positions for SHORT {symbol}: {e}")
|
||||||
|
|
||||||
# Cancel any existing open orders before placing new order
|
# Cancel any existing open orders before placing new order
|
||||||
if not self.simulation_mode:
|
if not self.simulation_mode:
|
||||||
self._cancel_open_orders(symbol)
|
self._cancel_open_orders(symbol)
|
||||||
@ -969,6 +1137,12 @@ class TradingExecutor:
|
|||||||
else:
|
else:
|
||||||
# Place real short order with enhanced error handling
|
# Place real short order with enhanced error handling
|
||||||
result = self._place_order_with_retry(symbol, 'SELL', 'MARKET', quantity, current_price)
|
result = self._place_order_with_retry(symbol, 'SELL', 'MARKET', quantity, current_price)
|
||||||
|
|
||||||
|
# Check for position check error
|
||||||
|
if result and 'error' in result and result['error'] == 'existing_position':
|
||||||
|
logger.error(f"SHORT order blocked: {result['message']}")
|
||||||
|
return False
|
||||||
|
|
||||||
if result and 'orderId' in result:
|
if result and 'orderId' in result:
|
||||||
# Use actual fill information if available, otherwise fall back to order parameters
|
# Use actual fill information if available, otherwise fall back to order parameters
|
||||||
filled_quantity = result.get('executedQty', quantity)
|
filled_quantity = result.get('executedQty', quantity)
|
||||||
@ -996,6 +1170,25 @@ class TradingExecutor:
|
|||||||
|
|
||||||
def _place_order_with_retry(self, symbol: str, side: str, order_type: str, quantity: float, current_price: float, max_retries: int = 3) -> Dict[str, Any]:
|
def _place_order_with_retry(self, symbol: str, side: str, order_type: str, quantity: float, current_price: float, max_retries: int = 3) -> Dict[str, Any]:
|
||||||
"""Place order with retry logic for MEXC error handling"""
|
"""Place order with retry logic for MEXC error handling"""
|
||||||
|
|
||||||
|
# FINAL POSITION CHECK: Verify no existing position before placing order
|
||||||
|
if not self.simulation_mode and self.exchange:
|
||||||
|
try:
|
||||||
|
exchange_positions = self.exchange.get_positions(symbol)
|
||||||
|
if exchange_positions:
|
||||||
|
for pos in exchange_positions:
|
||||||
|
size = float(pos.get('size', 0))
|
||||||
|
if size > 0:
|
||||||
|
logger.error(f"FINAL POSITION CHECK FAILED: Found existing position for {symbol} before placing order")
|
||||||
|
logger.error(f"Position details: {pos}")
|
||||||
|
logger.error(f"Order details: {side} {quantity} @ ${current_price}")
|
||||||
|
# Sync the position to local state
|
||||||
|
self._sync_single_position_from_exchange(symbol, pos)
|
||||||
|
return {'error': 'existing_position', 'message': f'Position already exists for {symbol}'}
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error in final position check for {symbol}: {e}")
|
||||||
|
# Continue with order placement if we can't check positions
|
||||||
|
|
||||||
order_start_time = time.time()
|
order_start_time = time.time()
|
||||||
max_order_time = 8.0 # Maximum 8 seconds for order placement (leaves 2s buffer for lock timeout)
|
max_order_time = 8.0 # Maximum 8 seconds for order placement (leaves 2s buffer for lock timeout)
|
||||||
|
|
||||||
@ -1808,7 +2001,27 @@ class TradingExecutor:
|
|||||||
# Calculate total current position value
|
# Calculate total current position value
|
||||||
total_position_value = 0.0
|
total_position_value = 0.0
|
||||||
|
|
||||||
# Add existing positions
|
# ENHANCED: Also check exchange positions to ensure we don't miss any
|
||||||
|
if not self.simulation_mode and self.exchange:
|
||||||
|
try:
|
||||||
|
exchange_positions = self.exchange.get_positions()
|
||||||
|
if exchange_positions:
|
||||||
|
for pos in exchange_positions:
|
||||||
|
symbol = pos.get('symbol', '').replace('USDT', '/USDT')
|
||||||
|
size = float(pos.get('size', 0))
|
||||||
|
entry_price = float(pos.get('entry_price', 0))
|
||||||
|
if size > 0 and symbol:
|
||||||
|
# Check if this position is also in our local state
|
||||||
|
if symbol not in self.positions:
|
||||||
|
logger.warning(f"POSITION LIMIT: Found untracked exchange position for {symbol}: {size} @ ${entry_price:.2f}")
|
||||||
|
# Add to total even if not in local state
|
||||||
|
position_value = size * entry_price
|
||||||
|
total_position_value += position_value
|
||||||
|
logger.debug(f"Exchange position {symbol}: {size:.6f} @ ${entry_price:.2f} = ${position_value:.2f}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error checking exchange positions for limit: {e}")
|
||||||
|
|
||||||
|
# Add existing local positions
|
||||||
for symbol, position in self.positions.items():
|
for symbol, position in self.positions.items():
|
||||||
# Get current price for the symbol
|
# Get current price for the symbol
|
||||||
try:
|
try:
|
||||||
|
@ -1245,92 +1245,94 @@ class CleanTradingDashboard:
|
|||||||
return [html.I(className="fas fa-exclamation-triangle me-1"), "Store Failed"]
|
return [html.I(className="fas fa-exclamation-triangle me-1"), "Store Failed"]
|
||||||
return [html.I(className="fas fa-save me-1"), "Store All Models"]
|
return [html.I(className="fas fa-save me-1"), "Store All Models"]
|
||||||
|
|
||||||
# Trading Mode Toggle
|
# Trading Mode Toggle - TEMPORARILY DISABLED TO FIX UI ERROR
|
||||||
@self.app.callback(
|
# @self.app.callback(
|
||||||
Output('trading-mode-display', 'children'),
|
# Output('trading-mode-display', 'children'),
|
||||||
Output('trading-mode-display', 'className'),
|
# Output('trading-mode-display', 'className'),
|
||||||
[Input('trading-mode-switch', 'value')]
|
# [Input('trading-mode-switch', 'value')]
|
||||||
)
|
# )
|
||||||
def update_trading_mode(switch_value):
|
# def update_trading_mode(switch_value):
|
||||||
"""Update trading mode display and apply changes"""
|
# """Update trading mode display and apply changes"""
|
||||||
try:
|
# logger.debug(f"Trading mode callback triggered with value: {switch_value}")
|
||||||
is_live = 'live' in (switch_value or [])
|
# try:
|
||||||
self.trading_mode_live = is_live
|
# is_live = 'live' in (switch_value or [])
|
||||||
|
# self.trading_mode_live = is_live
|
||||||
|
#
|
||||||
|
# # Update trading executor mode if available
|
||||||
|
# if hasattr(self, 'trading_executor') and self.trading_executor:
|
||||||
|
# if hasattr(self.trading_executor, 'set_trading_mode'):
|
||||||
|
# # Use the new set_trading_mode method
|
||||||
|
# success = self.trading_executor.set_trading_mode('live' if is_live else 'simulation')
|
||||||
|
# if success:
|
||||||
|
# logger.info(f"TRADING MODE: {'LIVE' if is_live else 'SIMULATION'} - Mode updated successfully")
|
||||||
|
# else:
|
||||||
|
# logger.error(f"Failed to update trading mode to {'LIVE' if is_live else 'SIMULATION'}")
|
||||||
|
# else:
|
||||||
|
# # Fallback to direct property setting
|
||||||
|
# if is_live:
|
||||||
|
# self.trading_executor.trading_mode = 'live'
|
||||||
|
# self.trading_executor.simulation_mode = False
|
||||||
|
# logger.info("TRADING MODE: LIVE - Real orders will be executed!")
|
||||||
|
# else:
|
||||||
|
# self.trading_executor.trading_mode = 'simulation'
|
||||||
|
# self.trading_executor.simulation_mode = True
|
||||||
|
# logger.info("TRADING MODE: SIMULATION - Orders are simulated")
|
||||||
|
#
|
||||||
|
# # Return display text and styling
|
||||||
|
# if is_live:
|
||||||
|
# return "LIVE", "fw-bold text-danger"
|
||||||
|
# else:
|
||||||
|
# return "SIM", "fw-bold text-warning"
|
||||||
|
#
|
||||||
|
# except Exception as e:
|
||||||
|
# logger.error(f"Error updating trading mode: {e}")
|
||||||
|
# return "ERROR", "fw-bold text-danger"
|
||||||
|
|
||||||
# Update trading executor mode if available
|
# Cold Start Toggle - TEMPORARILY DISABLED TO FIX UI ERROR
|
||||||
if hasattr(self, 'trading_executor') and self.trading_executor:
|
# @self.app.callback(
|
||||||
if hasattr(self.trading_executor, 'set_trading_mode'):
|
# Output('cold-start-display', 'children'),
|
||||||
# Use the new set_trading_mode method
|
# Output('cold-start-display', 'className'),
|
||||||
success = self.trading_executor.set_trading_mode('live' if is_live else 'simulation')
|
# [Input('cold-start-switch', 'value')]
|
||||||
if success:
|
# )
|
||||||
logger.info(f"TRADING MODE: {'LIVE' if is_live else 'SIMULATION'} - Mode updated successfully")
|
# def update_cold_start(switch_value):
|
||||||
else:
|
# """Update cold start training mode"""
|
||||||
logger.error(f"Failed to update trading mode to {'LIVE' if is_live else 'SIMULATION'}")
|
# logger.debug(f"Cold start callback triggered with value: {switch_value}")
|
||||||
else:
|
# try:
|
||||||
# Fallback to direct property setting
|
# is_enabled = 'enabled' in (switch_value or [])
|
||||||
if is_live:
|
# self.cold_start_enabled = is_enabled
|
||||||
self.trading_executor.trading_mode = 'live'
|
#
|
||||||
self.trading_executor.simulation_mode = False
|
# # Update orchestrator cold start mode if available
|
||||||
logger.info("TRADING MODE: LIVE - Real orders will be executed!")
|
# if hasattr(self, 'orchestrator') and self.orchestrator:
|
||||||
else:
|
# if hasattr(self.orchestrator, 'set_cold_start_training_enabled'):
|
||||||
self.trading_executor.trading_mode = 'simulation'
|
# # Use the new set_cold_start_training_enabled method
|
||||||
self.trading_executor.simulation_mode = True
|
# success = self.orchestrator.set_cold_start_training_enabled(is_enabled)
|
||||||
logger.info("TRADING MODE: SIMULATION - Orders are simulated")
|
# if success:
|
||||||
|
# logger.info(f"COLD START: {'ON' if is_enabled else 'OFF'} - Training mode updated successfully")
|
||||||
# Return display text and styling
|
# else:
|
||||||
if is_live:
|
# logger.error(f"Failed to update cold start training to {'ON' if is_enabled else 'OFF'}")
|
||||||
return "LIVE", "fw-bold text-danger"
|
# else:
|
||||||
else:
|
# # Fallback to direct property setting
|
||||||
return "SIM", "fw-bold text-warning"
|
# if hasattr(self.orchestrator, 'cold_start_enabled'):
|
||||||
|
# self.orchestrator.cold_start_enabled = is_enabled
|
||||||
except Exception as e:
|
#
|
||||||
logger.error(f"Error updating trading mode: {e}")
|
# # Update training frequency based on cold start mode
|
||||||
return "ERROR", "fw-bold text-danger"
|
# if hasattr(self.orchestrator, 'training_frequency'):
|
||||||
|
# if is_enabled:
|
||||||
# Cold Start Toggle
|
# self.orchestrator.training_frequency = 'high' # Train on every signal
|
||||||
@self.app.callback(
|
# logger.info("COLD START: ON - Excessive training enabled")
|
||||||
Output('cold-start-display', 'children'),
|
# else:
|
||||||
Output('cold-start-display', 'className'),
|
# self.orchestrator.training_frequency = 'normal' # Normal training
|
||||||
[Input('cold-start-switch', 'value')]
|
# logger.info("COLD START: OFF - Normal training frequency")
|
||||||
)
|
#
|
||||||
def update_cold_start(switch_value):
|
# # Return display text and styling
|
||||||
"""Update cold start training mode"""
|
# if is_enabled:
|
||||||
try:
|
# return "ON", "fw-bold text-success"
|
||||||
is_enabled = 'enabled' in (switch_value or [])
|
# else:
|
||||||
self.cold_start_enabled = is_enabled
|
# return "OFF", "fw-bold text-secondary"
|
||||||
|
#
|
||||||
# Update orchestrator cold start mode if available
|
# except Exception as e:
|
||||||
if hasattr(self, 'orchestrator') and self.orchestrator:
|
# logger.error(f"Error updating cold start mode: {e}")
|
||||||
if hasattr(self.orchestrator, 'set_cold_start_training_enabled'):
|
# return "ERROR", "fw-bold text-danger"
|
||||||
# Use the new set_cold_start_training_enabled method
|
|
||||||
success = self.orchestrator.set_cold_start_training_enabled(is_enabled)
|
|
||||||
if success:
|
|
||||||
logger.info(f"COLD START: {'ON' if is_enabled else 'OFF'} - Training mode updated successfully")
|
|
||||||
else:
|
|
||||||
logger.error(f"Failed to update cold start training to {'ON' if is_enabled else 'OFF'}")
|
|
||||||
else:
|
|
||||||
# Fallback to direct property setting
|
|
||||||
if hasattr(self.orchestrator, 'cold_start_enabled'):
|
|
||||||
self.orchestrator.cold_start_enabled = is_enabled
|
|
||||||
|
|
||||||
# Update training frequency based on cold start mode
|
|
||||||
if hasattr(self.orchestrator, 'training_frequency'):
|
|
||||||
if is_enabled:
|
|
||||||
self.orchestrator.training_frequency = 'high' # Train on every signal
|
|
||||||
logger.info("COLD START: ON - Excessive training enabled")
|
|
||||||
else:
|
|
||||||
self.orchestrator.training_frequency = 'normal' # Normal training
|
|
||||||
logger.info("COLD START: OFF - Normal training frequency")
|
|
||||||
|
|
||||||
# Return display text and styling
|
|
||||||
if is_enabled:
|
|
||||||
return "ON", "fw-bold text-success"
|
|
||||||
else:
|
|
||||||
return "OFF", "fw-bold text-secondary"
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error updating cold start mode: {e}")
|
|
||||||
return "ERROR", "fw-bold text-danger"
|
|
||||||
|
|
||||||
def _get_current_price(self, symbol: str) -> Optional[float]:
|
def _get_current_price(self, symbol: str) -> Optional[float]:
|
||||||
"""Get current price for symbol - ONLY using our data providers"""
|
"""Get current price for symbol - ONLY using our data providers"""
|
||||||
|
Reference in New Issue
Block a user