Browse Source

Enhance order placement in HyperliquidClient and update TradingEngine logging

- Added slippage calculation for market orders in HyperliquidClient, ensuring price protection during order execution.
- Updated TradingEngine to use asynchronous formatting for amount and price in logging messages, improving clarity and consistency across order types.
- Enhanced logging for market and limit orders to reflect accurate price and amount details.
Carles Sentis 2 days ago
parent
commit
4bc0ceb637
3 changed files with 28 additions and 14 deletions
  1. 14 0
      src/clients/hyperliquid_client.py
  2. 13 13
      src/trading/trading_engine.py
  3. 1 1
      trading_bot.py

+ 14 - 0
src/clients/hyperliquid_client.py

@@ -318,10 +318,24 @@ class HyperliquidClient:
                 logger.error("❌ Client not initialized")
                 return None, "Client not initialized"
 
+            # Get current market price for slippage calculation
+            ticker = self.sync_client.fetch_ticker(symbol)
+            if not ticker or not ticker.get('last'):
+                error_msg = f"Could not fetch current price for {symbol} to calculate slippage."
+                logger.error(f"❌ {error_msg}")
+                return None, error_msg
+
+            current_price = ticker['last']
+            slippage_percent = 0.5  # 0.5% slippage
+            slippage_price = current_price * (1 + slippage_percent / 100) if side == 'buy' else current_price * (1 - slippage_percent / 100)
+
             order_params = params or {}
             # Add margin mode from config
             if Config.HYPERLIQUID_MARGIN_MODE:
                 order_params['marginMode'] = Config.HYPERLIQUID_MARGIN_MODE.lower()
+            
+            # Hyperliquid requires a price for market orders for slippage protection.
+            order_params['price'] = slippage_price
 
             logger.info(f"Placing market order: {side} {amount} {symbol} with params {order_params}")
             

+ 13 - 13
src/trading/trading_engine.py

@@ -306,10 +306,10 @@ class TradingEngine:
             # 2. Place the order with the exchange
             if order_type_for_stats == 'limit':
                 # Use token for formatting, symbol for logging context
-                logger.info(f"Placing LIMIT BUY order ({bot_order_ref_id}) for {formatter.format_amount(token_amount, token)} {symbol} at {formatter.format_price_with_symbol(order_placement_price, token)}")
+                logger.info(f"Placing LIMIT BUY order ({bot_order_ref_id}) for {await formatter.format_amount(token_amount, token)} {symbol} at {await formatter.format_price_with_symbol(order_placement_price, token)}")
                 exchange_order_data, error_msg = self.client.place_limit_order(symbol, 'buy', token_amount, order_placement_price)
             else: # Market order
-                logger.info(f"Placing MARKET BUY order ({bot_order_ref_id}) for {formatter.format_amount(token_amount, token)} {symbol} (approx. price {formatter.format_price_with_symbol(order_placement_price, token)})")
+                logger.info(f"Placing MARKET BUY order ({bot_order_ref_id}) for {await formatter.format_amount(token_amount, token)} {symbol} (approx. price {await formatter.format_price_with_symbol(order_placement_price, token)})")
                 exchange_order_data, error_msg = self.client.place_market_order(symbol, 'buy', token_amount)
             
             if error_msg:
@@ -463,10 +463,10 @@ class TradingEngine:
 
             # 2. Place the order with the exchange
             if order_type_for_stats == 'limit':
-                logger.info(f"Placing LIMIT SELL order ({bot_order_ref_id}) for {formatter.format_amount(token_amount, token)} {symbol} at {formatter.format_price_with_symbol(order_placement_price, token)}")
+                logger.info(f"Placing LIMIT SELL order ({bot_order_ref_id}) for {await formatter.format_amount(token_amount, token)} {symbol} at {await formatter.format_price_with_symbol(order_placement_price, token)}")
                 exchange_order_data, error_msg = self.client.place_limit_order(symbol, 'sell', token_amount, order_placement_price)
             else: # Market order
-                logger.info(f"Placing MARKET SELL order ({bot_order_ref_id}) for {formatter.format_amount(token_amount, token)} {symbol} (approx. price {formatter.format_price_with_symbol(order_placement_price, token)})")
+                logger.info(f"Placing MARKET SELL order ({bot_order_ref_id}) for {await formatter.format_amount(token_amount, token)} {symbol} (approx. price {await formatter.format_price_with_symbol(order_placement_price, token)})")
                 exchange_order_data, error_msg = self.client.place_market_order(symbol, 'sell', token_amount)
             
             if error_msg:
@@ -589,7 +589,7 @@ class TradingEngine:
                 return {"success": False, "error": "Failed to record exit order intent in database."}
 
             # 2. Execute market order to close position
-            logger.info(f"Placing MARKET {exit_side.upper()} order ({bot_order_ref_id}) to close {formatter.format_amount(contracts_to_close, token)} {symbol}")
+            logger.info(f"Placing MARKET {exit_side.upper()} order ({bot_order_ref_id}) to close {await formatter.format_amount(contracts_to_close, token)} {symbol}")
             exchange_order_data, error_msg = self.client.place_market_order(symbol, exit_side, contracts_to_close)
             
             if error_msg:
@@ -700,7 +700,7 @@ class TradingEngine:
                 return {"success": False, "error": "Failed to record SL limit order intent in database."}
 
             # 2. Place a direct LIMIT order for the stop loss
-            logger.info(f"Placing direct LIMIT STOP LOSS ({exit_side.upper()}) order ({bot_order_ref_id}) for {formatter.format_amount(contracts, token)} {symbol} at limit price {formatter.format_price_with_symbol(stop_price, token)}")
+            logger.info(f"Placing direct LIMIT STOP LOSS ({exit_side.upper()}) order ({bot_order_ref_id}) for {await formatter.format_amount(contracts, token)} {symbol} at limit price {await formatter.format_price_with_symbol(stop_price, token)}")
             exchange_order_data, error_msg = self.client.place_limit_order(symbol, exit_side, contracts, price=stop_price)
             
             if error_msg:
@@ -795,7 +795,7 @@ class TradingEngine:
                 return {"success": False, "error": "Failed to record TP order intent in database."}
 
             # 2. Place limit order at take profit price
-            logger.info(f"Placing TAKE PROFIT (LIMIT {exit_side.upper()}) order ({bot_order_ref_id}) for {formatter.format_amount(contracts, token)} {symbol} at {formatter.format_price_with_symbol(profit_price, token)}")
+            logger.info(f"Placing TAKE PROFIT (LIMIT {exit_side.upper()}) order ({bot_order_ref_id}) for {await formatter.format_amount(contracts, token)} {symbol} at {await formatter.format_price_with_symbol(profit_price, token)}")
             exchange_order_data, error_msg = self.client.place_limit_order(symbol, exit_side, contracts, profit_price)
             
             if error_msg:
@@ -1012,7 +1012,7 @@ class TradingEngine:
             return {"success": False, "error": msg}
 
         # 2. Place the limit order on the exchange
-        logger.info(f"Placing LIMIT STOP LOSS ({sl_order_side.upper()}) for lifecycle {lifecycle_id[:8]} ({bot_order_ref_id}): {formatter.format_amount(amount_to_cover, token)} {symbol} @ {formatter.format_price_with_symbol(sl_price, token)}")
+        logger.info(f"Placing LIMIT STOP LOSS ({sl_order_side.upper()}) for lifecycle {lifecycle_id[:8]} ({bot_order_ref_id}): {await formatter.format_amount(amount_to_cover, token)} {symbol} @ {await formatter.format_price_with_symbol(sl_price, token)}")
         exchange_order_data, error_msg = self.client.place_limit_order(symbol, sl_order_side, amount_to_cover, sl_price)
 
         if error_msg:
@@ -1116,8 +1116,8 @@ class TradingEngine:
 
         if current_price and current_price > 0:
             token = symbol.split('/')[0] if symbol else "TOKEN" # Extract token for formatter
-            current_price_str = formatter.format_price_with_symbol(current_price, token)
-            stop_price_str = formatter.format_price_with_symbol(stop_price, token)
+            current_price_str = await formatter.format_price_with_symbol(current_price, token)
+            stop_price_str = await formatter.format_price_with_symbol(stop_price, token)
 
             if sl_order_side.lower() == 'buy':
                 # SHORT position stop loss (BUY to close)
@@ -1161,10 +1161,10 @@ class TradingEngine:
 
         # 2. Place the actual SL order on the exchange
         if use_market_order:
-            logger.info(f"🚨 Placing ACTUAL SL ORDER (MARKET {sl_order_side.upper()}) from trigger {original_trigger_order_db_id}. New BotRef: {actual_sl_bot_order_ref_id}, Amount: {formatter.format_amount(amount, token)}, Trigger was: {formatter.format_price_with_symbol(stop_price, token)}")
+            logger.info(f"🚨 Placing ACTUAL SL ORDER (MARKET {sl_order_side.upper()}) from trigger {original_trigger_order_db_id}. New BotRef: {actual_sl_bot_order_ref_id}, Amount: {await formatter.format_amount(amount, token)}, Trigger was: {await formatter.format_price_with_symbol(stop_price, token)}")
             exchange_order_data, error_msg = self.client.place_market_order(symbol, sl_order_side, amount)
         else:
-            logger.info(f"📊 Placing ACTUAL SL ORDER (LIMIT {sl_order_side.upper()}) from trigger {original_trigger_order_db_id}. New BotRef: {actual_sl_bot_order_ref_id}, Amount: {formatter.format_amount(amount, token)}, Price: {formatter.format_price_with_symbol(stop_price, token)}")
+            logger.info(f"📊 Placing ACTUAL SL ORDER (LIMIT {sl_order_side.upper()}) from trigger {original_trigger_order_db_id}. New BotRef: {actual_sl_bot_order_ref_id}, Amount: {await formatter.format_amount(amount, token)}, Price: {await formatter.format_price_with_symbol(stop_price, token)}")
             exchange_order_data, error_msg = self.client.place_limit_order(symbol, sl_order_side, amount, stop_price)
 
         if error_msg:
@@ -1197,7 +1197,7 @@ class TradingEngine:
         if use_market_order:
             success_message += " for immediate execution (price moved beyond stop level)."
         else:
-            success_message += f" at {formatter.format_price_with_symbol(stop_price, token)}."
+            success_message += f" at {await formatter.format_price_with_symbol(stop_price, token)}."
 
         return {
             "success": True,

+ 1 - 1
trading_bot.py

@@ -14,7 +14,7 @@ from datetime import datetime
 from pathlib import Path
 
 # Bot version
-BOT_VERSION = "2.4.268"
+BOT_VERSION = "2.4.269"
 
 # Add src directory to Python path
 sys.path.insert(0, str(Path(__file__).parent / "src"))