Sfoglia il codice sorgente

feat(交易策略): 添加预签名交易功能以减少开仓延迟

实现预签名做多和做空交易功能,当价格变动超过5bps时重新签名
新增_presign_open_orders方法预签名订单,_open_position_with_presigned方法使用预签名交易开仓
skyfffire 3 giorni fa
parent
commit
b1bb82663d
1 ha cambiato i file con 148 aggiunte e 7 eliminazioni
  1. 148 7
      src/leadlag/strategy.py

+ 148 - 7
src/leadlag/strategy.py

@@ -114,6 +114,12 @@ class TradingStrategy:
         self.closing_order_id = None    # 当前平仓订单ID
         self.last_closing_price = None  # 上次挂单价格,用于判断是否需要replace
         
+        # 预签名交易相关变量(做多和做空各一笔)
+        self.presigned_long_tx = None   # 预签名的做多交易信息
+        self.presigned_short_tx = None  # 预签名的做空交易信息
+        self.presigned_prices = None    # 存储预签名时的binance_price
+        self.presigned_bps_threshold = 5  # 价格变动超过此bps时重新签名
+        
         # WebSocket连接引用(由listener设置)
         self.websocket_connection = None
         
@@ -157,6 +163,90 @@ class TradingStrategy:
         
         return True
     
+    def _calculate_bps_change(self, current_price, prev_price):
+        """计算价格变化的bps"""
+        if prev_price == 0:
+            return float('inf')
+        return abs((current_price - prev_price) / prev_price) * 10000
+    
+    async def _presign_open_orders(self, market_info, binance_price):
+        """
+        预签名开仓订单(做多和做空各一笔)
+        当binance_price变动超过5bps时重新签名
+        
+        Args:
+            market_info: 市场信息
+            binance_price: binance价格
+        """
+        binance_price_float = float(binance_price) if isinstance(binance_price, str) else binance_price
+        
+        # 检查是否需要重新签名
+        need_presign = False
+        
+        # 首次签名
+        if self.presigned_prices is None:
+            need_presign = True
+            logger.info(f"首次预签名开仓订单,binance_price={binance_price_float}")
+        else:
+            # 检查价格变化(与签名时的binance_price对比)
+            price_change = self._calculate_bps_change(binance_price_float, self.presigned_prices)
+            
+            if price_change >= self.presigned_bps_threshold:
+                need_presign = True
+                logger.info(f"价格变化超过{self.presigned_bps_threshold}bps,重新签名。price_change={price_change:.2f}bps")
+        
+        if not need_presign:
+            return
+        
+        try:
+            # 计算开仓价格(往不利方向)
+            # 做多:在binance_price基础上往上加bps(更高的价格)
+            long_price = binance_price_float * (1 + self.entry_price_bps / 10000)
+            # 做空:在binance_price基础上往下减bps(更低的价格)
+            short_price = binance_price_float * (1 - self.entry_price_bps / 10000)
+            
+            logger.info(f"预签名订单 - binance_price={binance_price_float}, 做多价格={long_price}, 做空价格={short_price}")
+            
+            # 签名做多订单(买入)
+            long_tx_info, long_oid, error = await self.create_order_tx(
+                market_info=market_info,
+                quantity=self.trade_quantity,
+                price=long_price,
+                is_ask=False,  # 买入
+                reduce_only=False,
+                order_type=self.signer_client.ORDER_TYPE_MARKET,
+            )
+            
+            if error:
+                logger.error(f"预签名做多订单失败: {error}")
+                self.presigned_long_tx = None
+            else:
+                self.presigned_long_tx = (long_tx_info, long_oid)
+                logger.info(f"预签名做多订单成功: oid={long_oid}")
+            
+            # 签名做空订单(卖出)
+            short_tx_info, short_oid, error = await self.create_order_tx(
+                market_info=market_info,
+                quantity=self.trade_quantity,
+                price=short_price,
+                is_ask=True,  # 卖出
+                reduce_only=False,
+                order_type=self.signer_client.ORDER_TYPE_MARKET,
+            )
+            
+            if error:
+                logger.error(f"预签名做空订单失败: {error}")
+                self.presigned_short_tx = None
+            else:
+                self.presigned_short_tx = (short_tx_info, short_oid)
+                logger.info(f"预签名做空订单成功: oid={short_oid}")
+            
+            # 保存签名时的binance_price
+            self.presigned_prices = binance_price_float
+            
+        except Exception as e:
+            logger.error(f"预签名订单时发生错误: {str(e)}")
+    
     async def do_strategy(self, market_data):
         """
         执行策略逻辑
@@ -331,10 +421,14 @@ class TradingStrategy:
             return
             
         market_info = market_data.get('market_info')
+        binance_price = market_data.get('binance_price')
         
-        if not market_info:
+        if not market_info or not binance_price:
             return
         
+        # 定期预签名开仓订单(做多和做空各一笔)
+        await self._presign_open_orders(market_info, binance_price)
+        
         # 使用存储的ask_bps和bid_bps进行开单逻辑判断
         # 是否卖出由bid_bps决定,是否买入由ask_bps决定
         
@@ -347,7 +441,7 @@ class TradingStrategy:
             # 做空:bid价差过大,lighter买价高于binance,卖出lighter
             logger.info(f"触发做空条件:bid_bps={self.current_bid_bps:.2f}bps > {self.entry_price_bps}bps")
             self.position_side = 'short'
-            await self._open_position(market_info, market_data.get('binance_price'))
+            await self._open_position_with_presigned(market_info, binance_price, 'short')
         elif self.current_ask_bps is not None and self.current_ask_bps < -self.entry_price_bps:
             # 检查交易间隔
             if not self._can_trade():
@@ -356,10 +450,57 @@ class TradingStrategy:
             # 做多:ask价差过小(负值),lighter卖价低于binance,买入lighter
             logger.info(f"触发做多条件:ask_bps={self.current_ask_bps:.2f}bps < -{self.entry_price_bps}bps")
             self.position_side = 'long'
-            await self._open_position(market_info, market_data.get('binance_price'))
+            await self._open_position_with_presigned(market_info, binance_price, 'long')
+    
+    async def _open_position_with_presigned(self, market_info, binance_price, direction):
+        """使用预签名交易开仓
+        
+        Args:
+            market_info: 市场信息
+            binance_price: binance价格
+            direction: 开仓方向 ('long' 或 'short')
+        """
+        side_desc = '做多' if direction == 'long' else '做空'
+        
+        # 获取对应方向的预签名交易
+        if direction == 'long' and self.presigned_long_tx:
+            tx_info, oid = self.presigned_long_tx
+            logger.info(f"使用预签名做多交易开仓,oid={oid}")
+        elif direction == 'short' and self.presigned_short_tx:
+            tx_info, oid = self.presigned_short_tx
+            logger.info(f"使用预签名做空交易开仓,oid={oid}")
+        else:
+            logger.warning(f"没有可用的预签名{side_desc}交易,回退到普通开仓")
+            await self._open_position(market_info, binance_price)
+            return
+        
+        # 直接发送预签名交易
+        try:
+            tx_hash, error = await self.send_order_tx(tx_info)
+            
+            if error:
+                logger.error(f"发送预签名{side_desc}交易失败: {error}")
+                # 回退到普通开仓
+                await self._open_position(market_info, binance_price)
+                return
+            
+            # 记录开仓时间
+            self.last_trade_time = time.time()
+            logger.info(f"预签名{side_desc}交易已发送,交易哈希={tx_hash}")
+            
+            # 清空已使用的预签名交易
+            if direction == 'long':
+                self.presigned_long_tx = None
+            else:
+                self.presigned_short_tx = None
+            
+        except Exception as e:
+            logger.error(f"发送预签名{side_desc}交易时出错: {str(e)}")
+            # 回退到普通开仓
+            await self._open_position(market_info, binance_price)
     
     async def _open_position(self, market_info, binance_price):
-        """开仓"""
+        """开仓(备选方案,当预签名交易失败时使用)"""
         # 直接使用binance_price作为交易价格
         binance_price_float = float(binance_price) if isinstance(binance_price, str) else binance_price
         
@@ -375,7 +516,7 @@ class TradingStrategy:
             is_ask = True
             side_desc = '做空'
         
-        logger.info(f"开始开仓:方向={side_desc},数量={self.trade_quantity},价格={price}")
+        logger.info(f"开始开仓(备选):方向={side_desc},数量={self.trade_quantity},价格={price}")
         
         tx_hash, oid, error = await self.create_order_and_send_tx(
             market_info=market_info,
@@ -387,14 +528,14 @@ class TradingStrategy:
         )
         
         if error:
-            logger.error(f"开仓失败: {error}")
+            logger.error(f"备选开仓失败: {error}")
             logger.info(f"状态转换: EXECUTING_OPEN -> IDLE_MONITORING")
             self.state = StrategyState.IDLE_MONITORING
             return
         
         # 记录开仓时间
         self.last_trade_time = time.time()
-        logger.info(f"开仓交易已发送,交易哈希={tx_hash}")
+        logger.info(f"备选开仓交易已发送,交易哈希={tx_hash}")
     
     async def _handle_closing_with_limit_order(self, market_data):
         """处理限价单平仓状态 - 挂仅减仓的限价单平仓"""