a
This commit is contained in:
parent
6c04202a55
commit
df634a8f02
|
|
@ -316,19 +316,26 @@ class BinanceClient:
|
||||||
# 提取数量精度信息
|
# 提取数量精度信息
|
||||||
quantity_precision = s.get('quantityPrecision', 8)
|
quantity_precision = s.get('quantityPrecision', 8)
|
||||||
|
|
||||||
# 从filters中提取minQty和stepSize
|
# 从filters中提取minQty、stepSize和minNotional
|
||||||
min_qty = None
|
min_qty = None
|
||||||
step_size = None
|
step_size = None
|
||||||
|
min_notional = None
|
||||||
for f in s.get('filters', []):
|
for f in s.get('filters', []):
|
||||||
if f['filterType'] == 'LOT_SIZE':
|
if f['filterType'] == 'LOT_SIZE':
|
||||||
min_qty = float(f.get('minQty', 0))
|
min_qty = float(f.get('minQty', 0))
|
||||||
step_size = float(f.get('stepSize', 0))
|
step_size = float(f.get('stepSize', 0))
|
||||||
break
|
elif f['filterType'] == 'MIN_NOTIONAL':
|
||||||
|
min_notional = float(f.get('notional', 0))
|
||||||
|
|
||||||
|
# 如果没有从filters获取到minNotional,使用默认值5 USDT
|
||||||
|
if min_notional is None or min_notional == 0:
|
||||||
|
min_notional = 5.0
|
||||||
|
|
||||||
info = {
|
info = {
|
||||||
'quantityPrecision': quantity_precision,
|
'quantityPrecision': quantity_precision,
|
||||||
'minQty': min_qty or 0,
|
'minQty': min_qty or 0,
|
||||||
'stepSize': step_size or 0
|
'stepSize': step_size or 0,
|
||||||
|
'minNotional': min_notional
|
||||||
}
|
}
|
||||||
|
|
||||||
# 缓存信息
|
# 缓存信息
|
||||||
|
|
@ -416,7 +423,33 @@ class BinanceClient:
|
||||||
logger.error(f"调整后的数量无效: {adjusted_quantity} (原始: {quantity})")
|
logger.error(f"调整后的数量无效: {adjusted_quantity} (原始: {quantity})")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
logger.info(f"下单: {symbol} {side} {adjusted_quantity} (原始: {quantity}) @ {order_type}")
|
# 获取当前价格以计算名义价值
|
||||||
|
if price is None:
|
||||||
|
ticker = await self.get_ticker_24h(symbol)
|
||||||
|
if not ticker:
|
||||||
|
logger.error(f"无法获取 {symbol} 的价格信息")
|
||||||
|
return None
|
||||||
|
current_price = ticker['price']
|
||||||
|
else:
|
||||||
|
current_price = price
|
||||||
|
|
||||||
|
# 计算订单名义价值
|
||||||
|
notional_value = adjusted_quantity * current_price
|
||||||
|
min_notional = symbol_info.get('minNotional', 5.0) if symbol_info else 5.0
|
||||||
|
|
||||||
|
logger.info(f"下单检查: {symbol} {side} {adjusted_quantity} (原始: {quantity}) @ {order_type}")
|
||||||
|
logger.info(f" 当前价格: {current_price:.4f} USDT")
|
||||||
|
logger.info(f" 订单名义价值: {notional_value:.2f} USDT")
|
||||||
|
logger.info(f" 最小名义价值: {min_notional:.2f} USDT")
|
||||||
|
|
||||||
|
# 检查名义价值是否满足最小要求
|
||||||
|
if notional_value < min_notional:
|
||||||
|
logger.warning(
|
||||||
|
f"❌ {symbol} 订单名义价值不足: {notional_value:.2f} USDT < "
|
||||||
|
f"最小要求: {min_notional:.2f} USDT"
|
||||||
|
)
|
||||||
|
logger.warning(f" 需要增加数量或提高仓位大小")
|
||||||
|
return None
|
||||||
|
|
||||||
if order_type == 'MARKET':
|
if order_type == 'MARKET':
|
||||||
order = await self.client.futures_create_order(
|
order = await self.client.futures_create_order(
|
||||||
|
|
@ -437,7 +470,7 @@ class BinanceClient:
|
||||||
price=price
|
price=price
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"下单成功: {symbol} {side} {adjusted_quantity} @ {order_type}")
|
logger.info(f"下单成功: {symbol} {side} {adjusted_quantity} @ {order_type} (名义价值: {notional_value:.2f} USDT)")
|
||||||
return order
|
return order
|
||||||
except BinanceAPIException as e:
|
except BinanceAPIException as e:
|
||||||
error_code = e.code if hasattr(e, 'code') else None
|
error_code = e.code if hasattr(e, 'code') else None
|
||||||
|
|
@ -446,6 +479,11 @@ class BinanceClient:
|
||||||
logger.error(f" 原始数量: {quantity}")
|
logger.error(f" 原始数量: {quantity}")
|
||||||
if symbol_info:
|
if symbol_info:
|
||||||
logger.error(f" 交易对精度: {symbol_info}")
|
logger.error(f" 交易对精度: {symbol_info}")
|
||||||
|
elif error_code == -4164:
|
||||||
|
logger.error(f"下单失败 {symbol} {side}: 订单名义价值不足 - {e}")
|
||||||
|
logger.error(f" 订单名义价值必须至少为 5 USDT (除非选择 reduce only)")
|
||||||
|
if symbol_info:
|
||||||
|
logger.error(f" 最小名义价值: {symbol_info.get('minNotional', 5.0)} USDT")
|
||||||
else:
|
else:
|
||||||
logger.error(f"下单失败 {symbol} {side}: {e}")
|
logger.error(f"下单失败 {symbol} {side}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -252,14 +252,40 @@ class RiskManager:
|
||||||
position_value = available_balance * position_percent
|
position_value = available_balance * position_percent
|
||||||
logger.info(f" 计算仓位价值: {position_value:.2f} USDT ({position_percent*100:.1f}% of {available_balance:.2f})")
|
logger.info(f" 计算仓位价值: {position_value:.2f} USDT ({position_percent*100:.1f}% of {available_balance:.2f})")
|
||||||
|
|
||||||
|
# 确保仓位价值满足最小名义价值要求(币安要求至少5 USDT)
|
||||||
|
min_notional = 5.0 # 币安合约最小名义价值
|
||||||
|
if position_value < min_notional:
|
||||||
|
logger.warning(f" ⚠ 仓位价值 {position_value:.2f} USDT < 最小名义价值 {min_notional:.2f} USDT")
|
||||||
|
# 尝试增加仓位价值到最小名义价值,但不超过最大仓位限制
|
||||||
|
max_allowed_value = available_balance * max_position_percent
|
||||||
|
if min_notional <= max_allowed_value:
|
||||||
|
position_value = min_notional
|
||||||
|
logger.info(f" ✓ 调整仓位价值到最小名义价值: {position_value:.2f} USDT")
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f" ❌ 无法满足最小名义价值要求: "
|
||||||
|
f"需要 {min_notional:.2f} USDT,但最大允许 {max_allowed_value:.2f} USDT"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
# 计算数量(考虑合约的最小数量精度)
|
# 计算数量(考虑合约的最小数量精度)
|
||||||
quantity = position_value / current_price
|
quantity = position_value / current_price
|
||||||
logger.info(f" 计算数量: {quantity:.4f} (价值: {position_value:.2f} / 价格: {current_price:.4f})")
|
logger.info(f" 计算数量: {quantity:.4f} (价值: {position_value:.2f} / 价格: {current_price:.4f})")
|
||||||
|
|
||||||
|
# 验证计算出的数量对应的名义价值
|
||||||
|
calculated_notional = quantity * current_price
|
||||||
|
if calculated_notional < min_notional:
|
||||||
|
# 如果计算出的名义价值仍然不足,增加数量
|
||||||
|
required_quantity = min_notional / current_price
|
||||||
|
logger.warning(f" ⚠ 计算出的名义价值 {calculated_notional:.2f} USDT < {min_notional:.2f} USDT")
|
||||||
|
logger.info(f" ✓ 调整数量从 {quantity:.4f} 到 {required_quantity:.4f}")
|
||||||
|
quantity = required_quantity
|
||||||
|
position_value = required_quantity * current_price
|
||||||
|
|
||||||
# 检查是否通过风险控制
|
# 检查是否通过风险控制
|
||||||
logger.info(f" 检查仓位大小是否符合风险控制要求...")
|
logger.info(f" 检查仓位大小是否符合风险控制要求...")
|
||||||
if await self.check_position_size(symbol, quantity):
|
if await self.check_position_size(symbol, quantity):
|
||||||
logger.info(f"✓ {symbol} 仓位计算成功: {quantity:.4f} (价值: {position_value:.2f} USDT)")
|
logger.info(f"✓ {symbol} 仓位计算成功: {quantity:.4f} (价值: {position_value:.2f} USDT, 名义价值: {quantity * current_price:.2f} USDT)")
|
||||||
return quantity
|
return quantity
|
||||||
else:
|
else:
|
||||||
logger.warning(f"❌ {symbol} 仓位检查未通过,无法开仓")
|
logger.warning(f"❌ {symbol} 仓位检查未通过,无法开仓")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user