|
@@ -448,76 +448,96 @@ class HyperliquidClient:
|
|
|
logger.error(f"❌ Error loading markets: {error_message} (Full exception: {e})")
|
|
|
return None
|
|
|
|
|
|
- def place_stop_loss_order(self, symbol: str, side: str, amount: float, price: float, params: Optional[Dict] = None) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
|
|
|
+ def place_stop_loss_order(self, symbol: str, side: str, amount: float, stop_price_arg: float, params: Optional[Dict] = None) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
|
|
|
"""
|
|
|
- Place a stop loss order (implemented as a limit order).
|
|
|
+ Place a stop loss order (as a stop-market order).
|
|
|
Returns a tuple: (order_object, error_message_string).
|
|
|
Error_message_string is None on success. Order_object is None on failure.
|
|
|
|
|
|
Args:
|
|
|
symbol: Trading symbol (e.g., 'BTC/USDC:USDC')
|
|
|
- side: 'buy' or 'sell'
|
|
|
+ side: 'buy' or 'sell' (side of the order to be placed when stop is triggered)
|
|
|
amount: Order amount
|
|
|
- price: Stop loss price
|
|
|
- params: Additional parameters for CCXT compatibility
|
|
|
+ stop_price_arg: The price at which the stop loss triggers
|
|
|
+ params: Additional parameters (mostly unused now, but kept for signature compatibility)
|
|
|
"""
|
|
|
try:
|
|
|
if not self.sync_client:
|
|
|
logger.error("❌ Client not initialized")
|
|
|
return None, "Client not initialized"
|
|
|
+
|
|
|
+ # Construct parameters for a trigger order (stop-market)
|
|
|
+ # The main order type is 'market', triggered at stop_price_arg.
|
|
|
+ # The 'price' for the create_order call will be None.
|
|
|
+ trigger_params = {
|
|
|
+ 'trigger': {
|
|
|
+ 'triggerPx': str(stop_price_arg), # The stop price
|
|
|
+ 'isMarket': True, # Execute as a market order when triggered
|
|
|
+ 'tpsl': 'sl' # Indicate it's a stop loss
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- # Stop loss orders are implemented as limit orders
|
|
|
- # They will be filled when the market price reaches the stop price
|
|
|
- order_params = params or {}
|
|
|
-
|
|
|
- # Add order type information for clarity in logs
|
|
|
- logger.info(f"🛑 Placing stop loss order: {side} {amount} {symbol} @ ${price}")
|
|
|
-
|
|
|
- order = self.sync_client.create_limit_order(symbol, side, amount, price, params=order_params)
|
|
|
-
|
|
|
- logger.info(f"✅ Successfully placed stop loss order for {amount} {symbol} at ${price}")
|
|
|
- logger.debug(f"📄 Stop loss order details: {order}")
|
|
|
+ # Merge with any incoming params, though trigger_params should take precedence for SL logic
|
|
|
+ if params:
|
|
|
+ trigger_params.update(params)
|
|
|
+
|
|
|
+ logger.info(f"🛑 Placing STOP-MARKET order: {side} {amount} {symbol} with trigger @ ${stop_price_arg:.4f}")
|
|
|
+
|
|
|
+ # For a stop-market order, the 'price' argument to create_order is None.
|
|
|
+ # The 'type' argument to create_order is 'market'.
|
|
|
+ order = self.sync_client.create_order(
|
|
|
+ symbol,
|
|
|
+ 'market', # Order type to execute when triggered
|
|
|
+ side,
|
|
|
+ amount,
|
|
|
+ None, # Price is None for market orders
|
|
|
+ params=trigger_params
|
|
|
+ )
|
|
|
+
|
|
|
+ logger.info(f"✅ Successfully placed stop-market order for {amount} {symbol}, trigger @ ${stop_price_arg:.4f}")
|
|
|
+ logger.debug(f"📄 Stop-market order details: {order}")
|
|
|
|
|
|
return order, None
|
|
|
except Exception as e:
|
|
|
error_message = self._extract_error_message(e)
|
|
|
- logger.error(f"❌ Error placing stop loss order: {error_message} (Full exception: {e})")
|
|
|
+ logger.error(f"❌ Error placing stop-market order: {error_message} (Full exception: {e})")
|
|
|
return None, error_message
|
|
|
|
|
|
- def place_take_profit_order(self, symbol: str, side: str, amount: float, price: float, params: Optional[Dict] = None) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
|
|
|
+ def place_take_profit_order(self, symbol: str, side: str, amount: float, take_profit_price_arg: float, params: Optional[Dict] = None) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
|
|
|
"""
|
|
|
- Place a take profit order (implemented as a limit order).
|
|
|
+ Place a take profit order (as a limit order, or can be adapted to trigger like SL).
|
|
|
+ Currently places a limit order. For true TP trigger, needs similar logic to SL.
|
|
|
Returns a tuple: (order_object, error_message_string).
|
|
|
- Error_message_string is None on success. Order_object is None on failure.
|
|
|
|
|
|
Args:
|
|
|
- symbol: Trading symbol (e.g., 'BTC/USDC:USDC')
|
|
|
+ symbol: Trading symbol
|
|
|
side: 'buy' or 'sell'
|
|
|
amount: Order amount
|
|
|
- price: Take profit price
|
|
|
- params: Additional parameters for CCXT compatibility
|
|
|
+ take_profit_price_arg: The price for the take profit order
|
|
|
+ params: Additional parameters
|
|
|
"""
|
|
|
+ # TODO: Implement actual take profit trigger logic (similar to stop_loss_order if needed)
|
|
|
+ # For now, it remains a limit order as per previous implementation,
|
|
|
+ # but could be changed to a trigger order: isMarket=False, tpsl='tp'.
|
|
|
+ logger.warning("⚠️ place_take_profit_order currently places a LIMIT order. For triggered TP, it needs updating similar to SL.")
|
|
|
try:
|
|
|
if not self.sync_client:
|
|
|
logger.error("❌ Client not initialized")
|
|
|
return None, "Client not initialized"
|
|
|
|
|
|
- # Take profit orders are implemented as limit orders
|
|
|
- # They will be filled when the market price reaches the target price
|
|
|
order_params = params or {}
|
|
|
|
|
|
- # Add order type information for clarity in logs
|
|
|
- logger.info(f"🎯 Placing take profit order: {side} {amount} {symbol} @ ${price}")
|
|
|
+ logger.info(f"🎯 Placing take profit (LIMIT) order: {side} {amount} {symbol} @ ${take_profit_price_arg}")
|
|
|
|
|
|
- order = self.sync_client.create_limit_order(symbol, side, amount, price, params=order_params)
|
|
|
+ order = self.sync_client.create_limit_order(symbol, side, amount, take_profit_price_arg, params=order_params)
|
|
|
|
|
|
- logger.info(f"✅ Successfully placed take profit order for {amount} {symbol} at ${price}")
|
|
|
+ logger.info(f"✅ Successfully placed take profit (LIMIT) order for {amount} {symbol} at ${take_profit_price_arg}")
|
|
|
logger.debug(f"📄 Take profit order details: {order}")
|
|
|
|
|
|
return order, None
|
|
|
except Exception as e:
|
|
|
error_message = self._extract_error_message(e)
|
|
|
- logger.error(f"❌ Error placing take profit order: {error_message} (Full exception: {e})")
|
|
|
+ logger.error(f"❌ Error placing take profit (LIMIT) order: {error_message} (Full exception: {e})")
|
|
|
return None, error_message
|
|
|
|
|
|
def get_recent_fills(self, limit: int = 100) -> Optional[List[Dict[str, Any]]]:
|