in the bussiness -but wip
This commit is contained in:
@ -149,7 +149,7 @@ class MEXCInterface(ExchangeInterface):
|
||||
return {}
|
||||
|
||||
def _send_private_request(self, method: str, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
|
||||
"""Send a private request to the exchange with proper signature"""
|
||||
"""Send a private request to the exchange with proper signature and MEXC error handling"""
|
||||
if params is None:
|
||||
params = {}
|
||||
|
||||
@ -191,8 +191,51 @@ class MEXCInterface(ExchangeInterface):
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
logger.error(f"API error: Status Code: {response.status_code}, Response: {response.text}")
|
||||
return None
|
||||
# Parse error response for specific error codes
|
||||
try:
|
||||
error_data = response.json()
|
||||
error_code = error_data.get('code')
|
||||
error_msg = error_data.get('msg', 'Unknown error')
|
||||
|
||||
# Handle specific MEXC error codes
|
||||
if error_code == 30005: # Oversold
|
||||
logger.warning(f"MEXC Oversold detected (Code 30005) for {endpoint}. This indicates risk control measures are active.")
|
||||
logger.warning(f"Possible causes: Market manipulation detection, abnormal trading patterns, or position limits.")
|
||||
logger.warning(f"Action: Waiting before retry and reducing position size if needed.")
|
||||
|
||||
# For oversold errors, we should not retry immediately
|
||||
# Return a special error structure that the trading executor can handle
|
||||
return {
|
||||
'error': 'oversold',
|
||||
'code': 30005,
|
||||
'message': error_msg,
|
||||
'retry_after': 60 # Suggest waiting 60 seconds
|
||||
}
|
||||
elif error_code == 30001: # Transaction direction not allowed
|
||||
logger.error(f"MEXC: Transaction direction not allowed for {endpoint}")
|
||||
return {
|
||||
'error': 'direction_not_allowed',
|
||||
'code': 30001,
|
||||
'message': error_msg
|
||||
}
|
||||
elif error_code == 30004: # Insufficient position
|
||||
logger.error(f"MEXC: Insufficient position for {endpoint}")
|
||||
return {
|
||||
'error': 'insufficient_position',
|
||||
'code': 30004,
|
||||
'message': error_msg
|
||||
}
|
||||
else:
|
||||
logger.error(f"MEXC API error: Code: {error_code}, Message: {error_msg}")
|
||||
return {
|
||||
'error': 'api_error',
|
||||
'code': error_code,
|
||||
'message': error_msg
|
||||
}
|
||||
except:
|
||||
# Fallback if response is not JSON
|
||||
logger.error(f"API error: Status Code: {response.status_code}, Response: {response.text}")
|
||||
return None
|
||||
|
||||
except requests.exceptions.HTTPError as http_err:
|
||||
logger.error(f"HTTP error for {endpoint}: Status Code: {response.status_code}, Response: {response.text}")
|
||||
@ -297,75 +340,92 @@ class MEXCInterface(ExchangeInterface):
|
||||
|
||||
def place_order(self, symbol: str, side: str, order_type: str, quantity: float, price: Optional[float] = None) -> Dict[str, Any]:
|
||||
"""Place a new order on MEXC."""
|
||||
formatted_symbol = self._format_spot_symbol(symbol)
|
||||
|
||||
# Check if symbol is supported for API trading
|
||||
if not self.is_symbol_supported(symbol):
|
||||
supported_symbols = self.get_api_symbols()
|
||||
logger.error(f"Symbol {formatted_symbol} is not supported for API trading")
|
||||
logger.info(f"Supported symbols include: {supported_symbols[:10]}...") # Show first 10
|
||||
return {}
|
||||
|
||||
# Round quantity to MEXC precision requirements and ensure minimum order value
|
||||
# MEXC ETHUSDC requires precision based on baseAssetPrecision (5 decimals for ETH)
|
||||
if 'ETH' in formatted_symbol:
|
||||
quantity = round(quantity, 5) # MEXC ETHUSDC precision: 5 decimals
|
||||
# Ensure minimum order value (typically $10+ for MEXC)
|
||||
if price and quantity * price < 10.0:
|
||||
quantity = round(10.0 / price, 5) # Adjust to minimum $10 order
|
||||
elif 'BTC' in formatted_symbol:
|
||||
quantity = round(quantity, 6) # MEXC BTCUSDC precision: 6 decimals
|
||||
if price and quantity * price < 10.0:
|
||||
quantity = round(10.0 / price, 6) # Adjust to minimum $10 order
|
||||
else:
|
||||
quantity = round(quantity, 5) # Default precision for MEXC
|
||||
if price and quantity * price < 10.0:
|
||||
quantity = round(10.0 / price, 5) # Adjust to minimum $10 order
|
||||
|
||||
# MEXC doesn't support MARKET orders for many pairs - use LIMIT orders instead
|
||||
if order_type.upper() == 'MARKET':
|
||||
# Convert market order to limit order with aggressive pricing for immediate execution
|
||||
if price is None:
|
||||
ticker = self.get_ticker(symbol)
|
||||
if ticker and 'last' in ticker:
|
||||
current_price = float(ticker['last'])
|
||||
# For buy orders, use slightly above market to ensure immediate execution
|
||||
# For sell orders, use slightly below market to ensure immediate execution
|
||||
if side.upper() == 'BUY':
|
||||
price = current_price * 1.002 # 0.2% premium for immediate buy execution
|
||||
else:
|
||||
price = current_price * 0.998 # 0.2% discount for immediate sell execution
|
||||
else:
|
||||
logger.error("Cannot get current price for market order conversion")
|
||||
return {}
|
||||
try:
|
||||
logger.info(f"MEXC: place_order called with symbol={symbol}, side={side}, order_type={order_type}, quantity={quantity}, price={price}")
|
||||
|
||||
# Convert to limit order with immediate execution pricing
|
||||
order_type = 'LIMIT'
|
||||
logger.info(f"MEXC: Converting MARKET to aggressive LIMIT order at ${price:.2f} for immediate execution")
|
||||
formatted_symbol = self._format_spot_symbol(symbol)
|
||||
logger.info(f"MEXC: Formatted symbol: {symbol} -> {formatted_symbol}")
|
||||
|
||||
# Check if symbol is supported for API trading
|
||||
if not self.is_symbol_supported(symbol):
|
||||
supported_symbols = self.get_api_symbols()
|
||||
logger.error(f"Symbol {formatted_symbol} is not supported for API trading")
|
||||
logger.info(f"Supported symbols include: {supported_symbols[:10]}...") # Show first 10
|
||||
return {}
|
||||
|
||||
# Round quantity to MEXC precision requirements and ensure minimum order value
|
||||
# MEXC ETHUSDC requires precision based on baseAssetPrecision (5 decimals for ETH)
|
||||
original_quantity = quantity
|
||||
if 'ETH' in formatted_symbol:
|
||||
quantity = round(quantity, 5) # MEXC ETHUSDC precision: 5 decimals
|
||||
# Ensure minimum order value (typically $10+ for MEXC)
|
||||
if price and quantity * price < 10.0:
|
||||
quantity = round(10.0 / price, 5) # Adjust to minimum $10 order
|
||||
elif 'BTC' in formatted_symbol:
|
||||
quantity = round(quantity, 6) # MEXC BTCUSDC precision: 6 decimals
|
||||
if price and quantity * price < 10.0:
|
||||
quantity = round(10.0 / price, 6) # Adjust to minimum $10 order
|
||||
else:
|
||||
quantity = round(quantity, 5) # Default precision for MEXC
|
||||
if price and quantity * price < 10.0:
|
||||
quantity = round(10.0 / price, 5) # Adjust to minimum $10 order
|
||||
|
||||
if quantity != original_quantity:
|
||||
logger.info(f"MEXC: Adjusted quantity: {original_quantity} -> {quantity}")
|
||||
|
||||
# MEXC doesn't support MARKET orders for many pairs - use LIMIT orders instead
|
||||
if order_type.upper() == 'MARKET':
|
||||
# Convert market order to limit order with aggressive pricing for immediate execution
|
||||
if price is None:
|
||||
ticker = self.get_ticker(symbol)
|
||||
if ticker and 'last' in ticker:
|
||||
current_price = float(ticker['last'])
|
||||
# For buy orders, use slightly above market to ensure immediate execution
|
||||
# For sell orders, use slightly below market to ensure immediate execution
|
||||
if side.upper() == 'BUY':
|
||||
price = current_price * 1.002 # 0.2% premium for immediate buy execution
|
||||
else:
|
||||
price = current_price * 0.998 # 0.2% discount for immediate sell execution
|
||||
else:
|
||||
logger.error("Cannot get current price for market order conversion")
|
||||
return {}
|
||||
|
||||
# Convert to limit order with immediate execution pricing
|
||||
order_type = 'LIMIT'
|
||||
logger.info(f"MEXC: Converting MARKET to aggressive LIMIT order at ${price:.2f} for immediate execution")
|
||||
|
||||
# Prepare order parameters
|
||||
params = {
|
||||
'symbol': formatted_symbol,
|
||||
'side': side.upper(),
|
||||
'type': order_type.upper(),
|
||||
'quantity': str(quantity) # Quantity must be a string
|
||||
}
|
||||
|
||||
if price is not None:
|
||||
# Format price to remove unnecessary decimal places (e.g., 2900.0 -> 2900)
|
||||
params['price'] = str(int(price)) if price == int(price) else str(price)
|
||||
# Prepare order parameters
|
||||
params = {
|
||||
'symbol': formatted_symbol,
|
||||
'side': side.upper(),
|
||||
'type': order_type.upper(),
|
||||
'quantity': str(quantity) # Quantity must be a string
|
||||
}
|
||||
|
||||
if price is not None:
|
||||
# Format price to remove unnecessary decimal places (e.g., 2900.0 -> 2900)
|
||||
params['price'] = str(int(price)) if price == int(price) else str(price)
|
||||
|
||||
logger.info(f"MEXC: Placing {side.upper()} {order_type.upper()} order for {quantity} {formatted_symbol} at price {price}")
|
||||
|
||||
# Use the standard private request method which handles timestamp and signature
|
||||
endpoint = "order"
|
||||
result = self._send_private_request("POST", endpoint, params)
|
||||
|
||||
if result:
|
||||
logger.info(f"MEXC: Order placed successfully: {result}")
|
||||
return result
|
||||
else:
|
||||
logger.error(f"MEXC: Failed to place order")
|
||||
logger.info(f"MEXC: Placing {side.upper()} {order_type.upper()} order for {quantity} {formatted_symbol} at price {price}")
|
||||
logger.info(f"MEXC: Order parameters: {params}")
|
||||
|
||||
# Use the standard private request method which handles timestamp and signature
|
||||
endpoint = "order"
|
||||
result = self._send_private_request("POST", endpoint, params)
|
||||
|
||||
if result:
|
||||
logger.info(f"MEXC: Order placed successfully: {result}")
|
||||
return result
|
||||
else:
|
||||
logger.error(f"MEXC: Failed to place order - _send_private_request returned None/empty result")
|
||||
logger.error(f"MEXC: Failed order details - symbol: {formatted_symbol}, side: {side}, type: {order_type}, quantity: {quantity}, price: {price}")
|
||||
return {}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"MEXC: Exception in place_order: {e}")
|
||||
logger.error(f"MEXC: Exception details - symbol: {symbol}, side: {side}, type: {order_type}, quantity: {quantity}, price: {price}")
|
||||
import traceback
|
||||
logger.error(f"MEXC: Full traceback: {traceback.format_exc()}")
|
||||
return {}
|
||||
|
||||
def cancel_order(self, symbol: str, order_id: str) -> Dict[str, Any]:
|
||||
|
Reference in New Issue
Block a user