This commit is contained in:
薇薇安 2026-02-14 19:59:57 +08:00
parent b779b7b9ec
commit 0a9377f5ac

View File

@ -1627,20 +1627,23 @@ class PositionManager:
continue
current_position = position_dict[symbol]
entry_price = position_info['entryPrice']
quantity = position_info['quantity'] # 修复获取quantity
# 统一转为 float避免 Decimal 与 float 运算报错DB/补建可能返回 Decimal
entry_price = float(position_info['entryPrice'])
quantity = float(position_info['quantity'])
# 获取当前标记价格
current_price = current_position.get('markPrice', 0)
if current_price == 0:
# 如果标记价格为0尝试从ticker获取
ticker = await self.client.get_ticker_24h(symbol)
if ticker:
current_price = ticker['price']
current_price = float(ticker.get('price', 0) or 0)
else:
current_price = entry_price
else:
current_price = float(current_price)
# 计算当前盈亏(基于保证金)
leverage = position_info.get('leverage', 10)
leverage = float(position_info.get('leverage', 10) or 10)
position_value = entry_price * quantity
margin = position_value / leverage if leverage > 0 else position_value
@ -1660,7 +1663,8 @@ class PositionManager:
pnl_percent_price = ((entry_price - current_price) / entry_price) * 100
# 更新最大盈利(基于保证金)
if pnl_percent_margin > position_info.get('maxProfit', 0):
max_profit = float(position_info.get('maxProfit', 0) or 0)
if pnl_percent_margin > max_profit:
position_info['maxProfit'] = pnl_percent_margin
# 移动止损逻辑(盈利后保护利润,基于保证金)
@ -1716,7 +1720,8 @@ class PositionManager:
# 计算新的止损价(基于剩余仓位)
if position_info['side'] == 'BUY':
new_stop_loss = entry_price + (remaining_pnl - protect_amount) / remaining_quantity
if new_stop_loss > position_info['stopLoss']:
current_sl = float(position_info['stopLoss']) if position_info.get('stopLoss') is not None else None
if current_sl is None or new_stop_loss > current_sl:
position_info['stopLoss'] = new_stop_loss
logger.info(
f"{symbol} 移动止损更新(剩余仓位): {new_stop_loss:.4f} "
@ -1730,7 +1735,8 @@ class PositionManager:
new_stop_loss = entry_price + (remaining_pnl - protect_amount) / remaining_quantity
# 对于做空,止损价应该越来越高(更宽松),所以检查 new_stop_loss > 当前止损
# 同时,移动止损只应该在盈利时激活
if new_stop_loss > position_info['stopLoss'] and remaining_pnl > 0:
current_sl = float(position_info['stopLoss']) if position_info.get('stopLoss') is not None else None
if current_sl is not None and new_stop_loss > current_sl and remaining_pnl > 0:
position_info['stopLoss'] = new_stop_loss
logger.info(
f"{symbol} 移动止损更新(剩余仓位): {new_stop_loss:.4f} "
@ -1745,7 +1751,8 @@ class PositionManager:
# 保护利润:当前盈亏 - 保护金额 = (止损价 - 开仓价) × 数量
# 所以:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量
new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity
if new_stop_loss > position_info['stopLoss']:
current_sl = float(position_info['stopLoss']) if position_info.get('stopLoss') is not None else None
if current_sl is None or new_stop_loss > current_sl:
position_info['stopLoss'] = new_stop_loss
logger.info(
f"{symbol} 移动止损更新: {new_stop_loss:.4f} "
@ -1759,7 +1766,8 @@ class PositionManager:
new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity
# 对于做空,止损价应该越来越高(更宽松),所以检查 new_stop_loss > 当前止损
# 同时,移动止损只应该在盈利时激活,不应该在亏损时把止损往下移
if new_stop_loss > position_info['stopLoss'] and pnl_amount > 0:
current_sl = float(position_info['stopLoss']) if position_info.get('stopLoss') is not None else None
if current_sl is not None and new_stop_loss > current_sl and pnl_amount > 0:
position_info['stopLoss'] = new_stop_loss
logger.info(
f"{symbol} 移动止损更新: {new_stop_loss:.4f} "
@ -1768,7 +1776,8 @@ class PositionManager:
# 检查止损(使用更新后的止损价,基于保证金收益比)
# ⚠️ 重要:止损检查应该在时间锁之前,止损必须立即执行
stop_loss = position_info.get('stopLoss')
stop_loss_raw = position_info.get('stopLoss')
stop_loss = float(stop_loss_raw) if stop_loss_raw is not None else None
should_close_due_to_sl = False
exit_reason_sl = None
@ -1873,10 +1882,12 @@ class PositionManager:
# 2) 分步止盈策略本身已提供利润保护50%在1:1止盈剩余保本
# 3) 交易所级别止盈单已提供保护
# 4) 及时止盈可以保护利润,避免价格回落
take_profit_1 = position_info.get('takeProfit1') # 第一目标盈亏比1:1
take_profit_2 = position_info.get('takeProfit2', position_info.get('takeProfit')) # 第二目标
take_profit_1_raw = position_info.get('takeProfit1') # 第一目标盈亏比1:1
take_profit_1 = float(take_profit_1_raw) if take_profit_1_raw is not None else None
take_profit_2_raw = position_info.get('takeProfit2', position_info.get('takeProfit')) # 第二目标
take_profit_2 = float(take_profit_2_raw) if take_profit_2_raw is not None else None
partial_profit_taken = position_info.get('partialProfitTaken', False)
remaining_quantity = position_info.get('remainingQuantity', quantity)
remaining_quantity = float(position_info.get('remainingQuantity', quantity))
# 第一目标TAKE_PROFIT_1_PERCENT 止盈默认15%保证金了结50%仓位
# ✅ 已移除时间锁限制,可以立即执行
@ -2022,12 +2033,13 @@ class PositionManager:
# 如果未部分止盈,但达到【第二目标】止盈价对应的收益比时,才全部平仓
# ⚠️ 修复:不再使用 TAKE_PROFIT_PERCENT(10%) 作为全平条件,否则会“刚赚一点就整仓止盈”
# 改为使用 take_profit_2 价格对应的保证金收益%,与第一目标(20%) 取较大者,避免盈利过少
take_profit_2 = position_info.get('takeProfit2', position_info.get('takeProfit'))
if take_profit_2 is not None and margin and margin > 0:
take_profit_2_full = position_info.get('takeProfit2', position_info.get('takeProfit'))
take_profit_2_full = float(take_profit_2_full) if take_profit_2_full is not None else None
if take_profit_2_full is not None and margin and margin > 0:
if position_info['side'] == 'BUY':
take_profit_2_amount = (take_profit_2 - entry_price) * quantity
take_profit_2_amount = (take_profit_2_full - entry_price) * quantity
else:
take_profit_2_amount = (entry_price - take_profit_2) * quantity
take_profit_2_amount = (entry_price - take_profit_2_full) * quantity
take_profit_2_pct_margin = (take_profit_2_amount / margin * 100) if margin > 0 else 0
# 至少要求达到第一目标对应的收益%(如 20%),避免过早全平
take_profit_1_pct = (config.TRADING_CONFIG.get('TAKE_PROFIT_1_PERCENT', 0.20) or 0.20)
@ -2039,7 +2051,7 @@ class PositionManager:
logger.info(
f"{symbol} 触发止盈(第二目标/保证金): "
f"当前盈亏={pnl_percent_margin:.2f}% of margin >= 目标={min_pct_for_full_tp:.2f}% | "
f"当前价={current_price:.4f}, 第二目标价={take_profit_2:.4f}"
f"当前价={current_price:.4f}, 第二目标价={take_profit_2_full:.4f}"
)
exit_reason = 'take_profit'
# 更新数据库