This commit is contained in:
aaron 2026-03-29 22:11:29 +08:00
parent eb5edf919c
commit e48911d502
3 changed files with 49 additions and 2 deletions

View File

@ -281,13 +281,20 @@ class HyperliquidExecutor(BaseExecutor):
# ==================== 辅助方法 ====================
def _calculate_position_size(self, symbol: str, margin: float, price: float, leverage: int) -> float:
"""计算仓位大小"""
"""计算仓位大小(按 Hyperliquid szDecimals 精度截断)"""
try:
import math
# Hyperliquid 的仓位计算
position_value = margin * leverage
position_size = position_value / price
logger.info(f" 仓位计算: ${margin:.2f} × {leverage}x = ${position_value:.2f}{position_size:.6f} {symbol}")
# 按 Hyperliquid 要求的精度截断szDecimals
sz_decimals = self.hyperliquid.get_sz_decimals(symbol)
factor = 10 ** sz_decimals
position_size = math.floor(position_size * factor) / factor
logger.info(f" 仓位计算: ${margin:.2f} × {leverage}x = ${position_value:.2f}{position_size:.6f} {symbol} (精度: {sz_decimals}位)")
return position_size

View File

@ -34,6 +34,17 @@ class PaperTradingExecutor(BaseExecutor):
# 调整保证金(模拟盘无手续费)
adjusted_margin = margin
# 根据 confidence 推算信号等级
confidence = decision.get('confidence', 0)
if confidence >= 80:
signal_grade = 'A'
elif confidence >= 60:
signal_grade = 'B'
elif confidence >= 40:
signal_grade = 'C'
else:
signal_grade = 'D'
# 构建信号字典
signal = {
'symbol': symbol,
@ -42,6 +53,10 @@ class PaperTradingExecutor(BaseExecutor):
'entry_price': entry_price if order_type == 'limit' else current_price,
'stop_loss': stop_loss,
'take_profit': take_profit,
'signal_grade': signal_grade,
'confidence': confidence,
'quantity': adjusted_margin,
'position_size': decision.get('position_size', 'light'),
}
# 执行下单(统一调用方式)

View File

@ -160,6 +160,9 @@ class HyperliquidTradingService:
# 风险检查
self.check_risk_limits()
# 精度保护:确保 size 符合 szDecimals 要求
size = self._sanitize_size(symbol, size)
try:
if reduce_only:
# 平仓使用 market_close不需要指定 is_buy自动判断
@ -216,6 +219,10 @@ class HyperliquidTradingService:
"""下限价单"""
self.check_risk_limits()
# 精度保护:确保 size 和 price 符合要求
size = self._sanitize_size(symbol, size)
price = round(float(price), 5) # Hyperliquid 价格最多 5 位小数
try:
result = self.exchange.order(symbol, is_buy, size, price,
{"limit": {"tif": "Gtc"}},
@ -582,6 +589,24 @@ class HyperliquidTradingService:
logger.warning(f"获取 {symbol} szDecimals 失败,使用默认值 3")
return 3
def _sanitize_size(self, symbol: str, size: float) -> float:
"""
精度保护确保 size 符合 Hyperliquid szDecimals 要求
这是防止 float_to_wire causes rounding 错误的最后防线
"""
import math
try:
sz_decimals = self.get_sz_decimals(symbol)
factor = 10 ** sz_decimals
sanitized = math.floor(float(size) * factor) / factor
if sanitized != size:
logger.info(f" 精度截断: {size}{sanitized} ({symbol} szDecimals={sz_decimals})")
return sanitized
except Exception as e:
logger.warning(f" 精度截断失败: {e},使用原值 {size}")
return size
# 单例
_hyperliquid_service_instance = None