test bybit opening/closing orders

This commit is contained in:
Dobromir Popov
2025-07-15 00:03:59 +03:00
parent 5b2dd3b0b8
commit a7905ce4e9
6 changed files with 849 additions and 32 deletions

View File

@ -131,7 +131,7 @@ class TradingExecutor:
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
@ -276,7 +276,7 @@ class TradingExecutor:
quote_asset = 'USDC' # Use USDC instead
logger.info(f"BALANCE CHECK: Using USDC fallback balance for {symbol}")
else:
available_balance = self.exchange.get_balance(quote_asset)
available_balance = self.exchange.get_balance(quote_asset)
logger.info(f"BALANCE CHECK: Symbol: {symbol}, Action: {action}, Required: ${required_capital:.2f} {quote_asset}, Available: ${available_balance:.2f} {quote_asset}")
@ -303,23 +303,23 @@ class TradingExecutor:
logger.info(f"LOCK ACQUIRED: Executing {action} for {symbol}")
start_time = time.time()
if action == 'BUY':
if action == 'BUY':
result = self._execute_buy(symbol, confidence, current_price)
elif action == 'SELL':
elif action == 'SELL':
result = self._execute_sell(symbol, confidence, current_price)
elif action == 'SHORT': # Explicitly handle SHORT if it's a direct signal
elif action == 'SHORT': # Explicitly handle SHORT if it's a direct signal
result = self._execute_short(symbol, confidence, current_price)
else:
logger.warning(f"Unknown action: {action}")
else:
logger.warning(f"Unknown action: {action}")
result = False
execution_time = time.time() - start_time
logger.info(f"EXECUTION COMPLETE: {action} for {symbol} took {execution_time:.2f}s, result: {result}")
return result
except Exception as e:
logger.error(f"Error executing {action} signal for {symbol}: {e}")
return False
except Exception as e:
logger.error(f"Error executing {action} signal for {symbol}: {e}")
return False
finally:
self.lock.release()
logger.debug(f"LOCK RELEASED: {action} for {symbol}")
@ -386,7 +386,7 @@ class TradingExecutor:
logger.info(f"Test mode: bypassing trade interval for {symbol}")
else:
logger.info(f"Trade interval not met for {symbol} ({time_since_last:.1f}s < {min_interval}s)")
return False
return False
# Check concurrent positions
max_positions = self.exchange_config.get('max_concurrent_positions',
@ -442,7 +442,7 @@ class TradingExecutor:
# Only create position if order was actually filled
if result.get('filled', True): # Assume filled for backward compatibility
self.positions[symbol] = Position(
symbol=symbol,
symbol=symbol,
side='LONG',
quantity=float(filled_quantity),
entry_price=float(fill_price),
@ -452,7 +452,7 @@ class TradingExecutor:
logger.info(f"BUY position created: {filled_quantity:.6f} {symbol} at ${fill_price:.4f}")
self.last_trade_time[symbol] = datetime.now()
return True
else:
else:
logger.error(f"BUY order placed but not filled: {result}")
return False
else:
@ -488,12 +488,12 @@ class TradingExecutor:
if self.simulation_mode:
# Create simulated short position
self.positions[symbol] = Position(
symbol=symbol,
self.positions[symbol] = Position(
symbol=symbol,
side='SHORT',
quantity=quantity,
entry_price=current_price,
entry_time=datetime.now(),
quantity=quantity,
entry_price=current_price,
entry_time=datetime.now(),
order_id=f"sim_{int(datetime.now().timestamp())}"
)
logger.info(f"Simulated SHORT order: {quantity:.6f} {symbol} at ${current_price:.2f}")
@ -517,15 +517,15 @@ class TradingExecutor:
order_id=result['orderId']
)
logger.info(f"SHORT position created: {filled_quantity:.6f} {symbol} at ${fill_price:.4f}")
self.last_trade_time[symbol] = datetime.now()
return True
else:
self.last_trade_time[symbol] = datetime.now()
return True
else:
logger.error(f"SHORT order placed but not filled: {result}")
return False
else:
logger.error("Failed to place SHORT order")
return False
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"""
order_start_time = time.time()
@ -628,7 +628,7 @@ class TradingExecutor:
try:
self.exchange.cancel_order(symbol, order_id)
logger.info(f"Cancelled unfilled order {order_id}")
except Exception as e:
except Exception as e:
logger.error(f"Failed to cancel unfilled order {order_id}: {e}")
# If this was the last attempt, return failure
@ -763,7 +763,7 @@ class TradingExecutor:
if symbol not in self.positions:
logger.warning(f"No position to close in {symbol}")
return False
position = self.positions[symbol]
if position.side != 'SHORT':
logger.warning(f"Position in {symbol} is not SHORT, cannot close with BUY")
@ -899,7 +899,7 @@ class TradingExecutor:
except Exception as e:
logger.error(f"Error closing SHORT position: {e}")
return False
def _close_long_position(self, symbol: str, confidence: float, current_price: float) -> bool:
"""Close a long position by selling"""
if symbol not in self.positions:
@ -1190,18 +1190,18 @@ class TradingExecutor:
raw_balances = self.exchange.get_all_balances()
if raw_balances:
# Convert to the expected format with 'type' field
combined_balances = {}
combined_balances = {}
for asset, balance_data in raw_balances.items():
if isinstance(balance_data, dict):
combined_balances[asset] = {
combined_balances[asset] = {
'free': balance_data.get('free', 0.0),
'locked': balance_data.get('locked', 0.0),
'total': balance_data.get('total', 0.0),
'type': 'spot' # Default to spot for now
}
logger.info(f"Retrieved balances for {len(combined_balances)} assets from {self.primary_name}")
return combined_balances
return combined_balances
else:
logger.warning(f"No balances returned from {self.primary_name} exchange")
return {}