feat(position_manager): 增加从交易所读取止损和止盈价格的功能
在持仓管理中,新增 `_get_sltp_from_exchange` 方法以从币安获取当前的止损和止盈价格,确保在重启后不覆盖已有的保护。同时,优化了止损和止盈价格的设置逻辑,优先使用从交易所获取的值,提升风险控制能力和策略的灵活性。这一改动旨在增强系统的稳定性与用户友好性,确保交易策略的有效性。
This commit is contained in:
parent
1c33096917
commit
d7ccbe38e4
|
|
@ -1350,6 +1350,41 @@ class PositionManager:
|
||||||
pass
|
pass
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
async def _get_sltp_from_exchange(self, symbol: str, side: str) -> tuple:
|
||||||
|
"""从币安条件单读取当前止损价、止盈价,便于重启后不覆盖已有保护。(stop_price, take_profit_price),缺的为 None。"""
|
||||||
|
sl_price, tp_price = None, None
|
||||||
|
try:
|
||||||
|
for o in (await self.client.get_open_orders(symbol)) or []:
|
||||||
|
t = str(o.get("type") or "").upper()
|
||||||
|
sp = o.get("stopPrice") or o.get("triggerPrice")
|
||||||
|
try:
|
||||||
|
p = float(sp) if sp is not None else None
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
p = None
|
||||||
|
if p is None:
|
||||||
|
continue
|
||||||
|
if t in ("STOP_MARKET", "STOP"):
|
||||||
|
sl_price = p
|
||||||
|
elif t in ("TAKE_PROFIT_MARKET", "TAKE_PROFIT"):
|
||||||
|
tp_price = p
|
||||||
|
# 条件单多在 CONDITIONAL 里
|
||||||
|
for o in (await self.client.futures_get_open_algo_orders(symbol, algo_type="CONDITIONAL")) or []:
|
||||||
|
t = str(o.get("orderType") or o.get("type") or "").upper()
|
||||||
|
sp = o.get("stopPrice") or o.get("triggerPrice") or o.get("tp")
|
||||||
|
try:
|
||||||
|
p = float(sp) if sp is not None else None
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
p = None
|
||||||
|
if p is None:
|
||||||
|
continue
|
||||||
|
if t in ("STOP_MARKET", "STOP"):
|
||||||
|
sl_price = p
|
||||||
|
elif t in ("TAKE_PROFIT_MARKET", "TAKE_PROFIT"):
|
||||||
|
tp_price = p
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"{symbol} 从交易所读取止损/止盈失败: {e}")
|
||||||
|
return (sl_price, tp_price)
|
||||||
|
|
||||||
def _breakeven_stop_price(self, entry_price: float, side: str, fee_buffer_pct: Optional[float] = None) -> float:
|
def _breakeven_stop_price(self, entry_price: float, side: str, fee_buffer_pct: Optional[float] = None) -> float:
|
||||||
"""含手续费的保本止损价:做多=入场*(1+费率),做空=入场*(1-费率),平仓后不亏。"""
|
"""含手续费的保本止损价:做多=入场*(1+费率),做空=入场*(1-费率),平仓后不亏。"""
|
||||||
if fee_buffer_pct is None:
|
if fee_buffer_pct is None:
|
||||||
|
|
@ -3611,22 +3646,29 @@ class PositionManager:
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
leverage = 10.0
|
leverage = 10.0
|
||||||
|
|
||||||
|
# 优先从币安读取当前止损/止盈,避免用“初始止损”覆盖已有保本/移动止损
|
||||||
|
sl_from_ex, tp_from_ex = await self._get_sltp_from_exchange(symbol, side)
|
||||||
|
if sl_from_ex is not None or tp_from_ex is not None:
|
||||||
|
stop_loss_price = float(sl_from_ex) if sl_from_ex is not None else None
|
||||||
|
take_profit_price = float(tp_from_ex) if tp_from_ex is not None else None
|
||||||
|
else:
|
||||||
|
stop_loss_price = None
|
||||||
|
take_profit_price = None
|
||||||
|
if stop_loss_price is None or take_profit_price is None:
|
||||||
stop_loss_pct_margin = config.TRADING_CONFIG.get('STOP_LOSS_PERCENT', 0.08)
|
stop_loss_pct_margin = config.TRADING_CONFIG.get('STOP_LOSS_PERCENT', 0.08)
|
||||||
# ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式)
|
|
||||||
if stop_loss_pct_margin is not None and stop_loss_pct_margin > 1:
|
if stop_loss_pct_margin is not None and stop_loss_pct_margin > 1:
|
||||||
stop_loss_pct_margin = stop_loss_pct_margin / 100.0
|
stop_loss_pct_margin = stop_loss_pct_margin / 100.0
|
||||||
take_profit_pct_margin = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.15)
|
take_profit_pct_margin = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.15)
|
||||||
# ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式)
|
|
||||||
if take_profit_pct_margin is not None and take_profit_pct_margin > 1:
|
if take_profit_pct_margin is not None and take_profit_pct_margin > 1:
|
||||||
take_profit_pct_margin = take_profit_pct_margin / 100.0
|
take_profit_pct_margin = take_profit_pct_margin / 100.0
|
||||||
# 如果配置中没有设置止盈,则使用止损的2倍作为默认
|
|
||||||
if take_profit_pct_margin is None or take_profit_pct_margin == 0:
|
if take_profit_pct_margin is None or take_profit_pct_margin == 0:
|
||||||
take_profit_pct_margin = stop_loss_pct_margin * 2.0
|
take_profit_pct_margin = (stop_loss_pct_margin or 0.05) * 2.0
|
||||||
|
if stop_loss_price is None:
|
||||||
stop_loss_price = self.risk_manager.get_stop_loss_price(
|
stop_loss_price = self.risk_manager.get_stop_loss_price(
|
||||||
entry_price, side, quantity, leverage,
|
entry_price, side, quantity, leverage,
|
||||||
stop_loss_pct=stop_loss_pct_margin
|
stop_loss_pct=stop_loss_pct_margin or 0.05
|
||||||
)
|
)
|
||||||
|
if take_profit_price is None:
|
||||||
take_profit_price = self.risk_manager.get_take_profit_price(
|
take_profit_price = self.risk_manager.get_take_profit_price(
|
||||||
entry_price, side, quantity, leverage,
|
entry_price, side, quantity, leverage,
|
||||||
take_profit_pct=take_profit_pct_margin
|
take_profit_pct=take_profit_pct_margin
|
||||||
|
|
@ -3684,6 +3726,12 @@ class PositionManager:
|
||||||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=mp or current_price)
|
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=mp or current_price)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"{symbol} 补挂币安止盈止损失败(不影响监控): {e}")
|
logger.warning(f"{symbol} 补挂币安止盈止损失败(不影响监控): {e}")
|
||||||
|
# 重启后立即按当前价做一次保本/移动止损检查并同步,不依赖首条 WS 推送
|
||||||
|
try:
|
||||||
|
_px = float(position.get("markPrice", 0) or 0) or float(current_price or entry_price)
|
||||||
|
await self._check_single_position(symbol, _px)
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"{symbol} 启动时保本/移动止损检查失败: {e}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err_msg = str(e) or repr(e) or type(e).__name__
|
err_msg = str(e) or repr(e) or type(e).__name__
|
||||||
logger.error(
|
logger.error(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user