feat(position_manager): 增加从交易所读取止损和止盈价格的功能
在持仓管理中,新增 `_get_sltp_from_exchange` 方法以从币安获取当前的止损和止盈价格,确保在重启后不覆盖已有的保护。同时,优化了止损和止盈价格的设置逻辑,优先使用从交易所获取的值,提升风险控制能力和策略的灵活性。这一改动旨在增强系统的稳定性与用户友好性,确保交易策略的有效性。
This commit is contained in:
parent
1c33096917
commit
d7ccbe38e4
|
|
@ -1350,6 +1350,41 @@ class PositionManager:
|
|||
pass
|
||||
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:
|
||||
"""含手续费的保本止损价:做多=入场*(1+费率),做空=入场*(1-费率),平仓后不亏。"""
|
||||
if fee_buffer_pct is None:
|
||||
|
|
@ -3611,26 +3646,33 @@ class PositionManager:
|
|||
except (ValueError, TypeError):
|
||||
leverage = 10.0
|
||||
|
||||
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:
|
||||
stop_loss_pct_margin = stop_loss_pct_margin / 100.0
|
||||
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:
|
||||
take_profit_pct_margin = take_profit_pct_margin / 100.0
|
||||
# 如果配置中没有设置止盈,则使用止损的2倍作为默认
|
||||
if take_profit_pct_margin is None or take_profit_pct_margin == 0:
|
||||
take_profit_pct_margin = stop_loss_pct_margin * 2.0
|
||||
|
||||
stop_loss_price = self.risk_manager.get_stop_loss_price(
|
||||
entry_price, side, quantity, leverage,
|
||||
stop_loss_pct=stop_loss_pct_margin
|
||||
)
|
||||
take_profit_price = self.risk_manager.get_take_profit_price(
|
||||
entry_price, side, quantity, leverage,
|
||||
take_profit_pct=take_profit_pct_margin
|
||||
)
|
||||
# 优先从币安读取当前止损/止盈,避免用“初始止损”覆盖已有保本/移动止损
|
||||
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)
|
||||
if stop_loss_pct_margin is not None and stop_loss_pct_margin > 1:
|
||||
stop_loss_pct_margin = stop_loss_pct_margin / 100.0
|
||||
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:
|
||||
take_profit_pct_margin = take_profit_pct_margin / 100.0
|
||||
if take_profit_pct_margin is None or take_profit_pct_margin == 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(
|
||||
entry_price, side, quantity, leverage,
|
||||
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(
|
||||
entry_price, side, quantity, leverage,
|
||||
take_profit_pct=take_profit_pct_margin
|
||||
)
|
||||
|
||||
entry_reason = 'manual_entry_temp' if sync_create_manual else 'sync_recovered'
|
||||
position_info = {
|
||||
|
|
@ -3684,6 +3726,12 @@ class PositionManager:
|
|||
await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=mp or current_price)
|
||||
except Exception as 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:
|
||||
err_msg = str(e) or repr(e) or type(e).__name__
|
||||
logger.error(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user