|
|
@@ -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):
|
|
|
"""处理限价单平仓状态 - 挂仅减仓的限价单平仓"""
|