fix(account): 优化止损和止盈价格获取逻辑
在账户模块中,改进了止损和止盈价格的获取逻辑,确保在无数据库记录时能够根据币安持仓和配置比例进行计算。同时,增强了异常处理,确保在无法确定止损止盈价时提供详细的错误信息。这一改动旨在提升风险控制能力和系统的稳定性。
This commit is contained in:
parent
d80d4559c5
commit
ab100bdc23
|
|
@ -80,70 +80,71 @@ async def _ensure_exchange_sltp_for_symbol(symbol: str, account_id: int = 1):
|
||||||
except Exception:
|
except Exception:
|
||||||
mark_price = None
|
mark_price = None
|
||||||
|
|
||||||
# 4) 从数据库 open trade 取止损/止盈价(优先取最近一条)
|
# 4) 止损/止盈价:优先从数据库 open trade 取;无 DB 记录时用币安持仓 + 配置比例计算(支持手动开仓补挂)
|
||||||
from database.models import Trade
|
from database.models import Trade
|
||||||
open_trades = Trade.get_by_symbol(symbol, status='open', account_id=account_id) or []
|
open_trades = Trade.get_by_symbol(symbol, status='open', account_id=account_id) or []
|
||||||
if not open_trades:
|
sl = None
|
||||||
raise HTTPException(status_code=400, detail=f"{symbol} 数据库无 open 交易记录,无法确定止损止盈价")
|
tp = None
|
||||||
# 尽量取最新一条 open trade(避免同一symbol多条 open 时取到旧记录)
|
entry_price = float(p0.get("entryPrice", 0) or 0)
|
||||||
try:
|
qty = abs(float(amt))
|
||||||
open_trades.sort(key=lambda x: int(x.get("id", 0) or 0), reverse=True)
|
lv = float(p0.get("leverage", 0) or 0) or 10.0
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
trade = open_trades[0]
|
|
||||||
|
|
||||||
sl = trade.get("stop_loss_price")
|
def _ratio(v, default):
|
||||||
tp = trade.get("take_profit_2") or trade.get("take_profit_price") or trade.get("take_profit_1")
|
|
||||||
try:
|
|
||||||
sl = float(sl) if sl is not None else None
|
|
||||||
except Exception:
|
|
||||||
sl = None
|
|
||||||
try:
|
|
||||||
tp = float(tp) if tp is not None else None
|
|
||||||
except Exception:
|
|
||||||
tp = None
|
|
||||||
|
|
||||||
# 兼容旧数据库:如果 trades 表还没迁移 stop_loss_price / take_profit_price 字段,
|
|
||||||
# 则回退用 entry_price/quantity/leverage + 配置的 STOP_LOSS_PERCENT/TAKE_PROFIT_PERCENT 计算。
|
|
||||||
if not sl or not tp:
|
|
||||||
try:
|
try:
|
||||||
|
x = float(v)
|
||||||
|
if x > 1:
|
||||||
|
x = x / 100.0
|
||||||
|
if x < 0:
|
||||||
|
x = default
|
||||||
|
return x
|
||||||
|
except Exception:
|
||||||
|
return default
|
||||||
|
|
||||||
|
if open_trades:
|
||||||
|
try:
|
||||||
|
open_trades.sort(key=lambda x: int(x.get("id", 0) or 0), reverse=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
trade = open_trades[0]
|
||||||
|
sl = trade.get("stop_loss_price")
|
||||||
|
tp = trade.get("take_profit_2") or trade.get("take_profit_price") or trade.get("take_profit_1")
|
||||||
|
try:
|
||||||
|
sl = float(sl) if sl is not None else None
|
||||||
|
except Exception:
|
||||||
|
sl = None
|
||||||
|
try:
|
||||||
|
tp = float(tp) if tp is not None else None
|
||||||
|
except Exception:
|
||||||
|
tp = None
|
||||||
|
if entry_price <= 0 or qty <= 0:
|
||||||
entry_price = float(trade.get("entry_price") or 0)
|
entry_price = float(trade.get("entry_price") or 0)
|
||||||
qty = float(trade.get("quantity") or 0)
|
qty = float(trade.get("quantity") or 0)
|
||||||
lv = float(trade.get("leverage") or 0) or float(p0.get("leverage") or 0) or 10.0
|
lv = float(trade.get("leverage") or 0) or lv
|
||||||
|
|
||||||
|
# 无 DB 记录或 DB 中 sl/tp 为空:用币安持仓的 entry/quantity/leverage + 配置比例计算
|
||||||
|
if not sl or not tp:
|
||||||
|
try:
|
||||||
if entry_price <= 0 or qty <= 0 or lv <= 0:
|
if entry_price <= 0 or qty <= 0 or lv <= 0:
|
||||||
raise ValueError("entry_price/quantity/leverage invalid")
|
raise ValueError("entry_price/quantity/leverage invalid")
|
||||||
|
|
||||||
def _ratio(v, default):
|
|
||||||
try:
|
|
||||||
x = float(v)
|
|
||||||
# 兼容:若误存成 5(表示5%),则转为 0.05
|
|
||||||
if x > 1:
|
|
||||||
x = x / 100.0
|
|
||||||
if x < 0:
|
|
||||||
x = default
|
|
||||||
return x
|
|
||||||
except Exception:
|
|
||||||
return default
|
|
||||||
|
|
||||||
sl_pct = _ratio(TradingConfig.get_value("STOP_LOSS_PERCENT", 0.05), 0.05)
|
sl_pct = _ratio(TradingConfig.get_value("STOP_LOSS_PERCENT", 0.05), 0.05)
|
||||||
tp_pct = _ratio(TradingConfig.get_value("TAKE_PROFIT_PERCENT", 0.15), 0.15)
|
tp_pct = _ratio(TradingConfig.get_value("TAKE_PROFIT_PERCENT", 0.15), 0.15)
|
||||||
|
|
||||||
notional = entry_price * qty
|
notional = entry_price * qty
|
||||||
margin = notional / lv
|
margin = notional / lv
|
||||||
sl_amount = margin * sl_pct
|
sl_amount = margin * sl_pct
|
||||||
tp_amount = margin * tp_pct
|
tp_amount = margin * tp_pct
|
||||||
|
|
||||||
if side == "BUY":
|
if side == "BUY":
|
||||||
sl = entry_price - (sl_amount / qty)
|
sl = entry_price - (sl_amount / qty)
|
||||||
tp = entry_price + (tp_amount / qty)
|
tp = entry_price + (tp_amount / qty)
|
||||||
else:
|
else:
|
||||||
sl = entry_price + (sl_amount / qty)
|
sl = entry_price + (sl_amount / qty)
|
||||||
tp = entry_price - (tp_amount / qty)
|
tp = entry_price - (tp_amount / qty)
|
||||||
|
|
||||||
if not sl or not tp or sl <= 0 or tp <= 0:
|
if not sl or not tp or sl <= 0 or tp <= 0:
|
||||||
raise ValueError("computed sl/tp invalid")
|
raise ValueError("computed sl/tp invalid")
|
||||||
except Exception:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=400, detail=f"{symbol} 数据库缺少止损/止盈价,且无法回退计算,无法补挂")
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=f"{symbol} 无法确定止损止盈价(无 DB 记录且计算失败: {e}),请检查配置 STOP_LOSS_PERCENT/TAKE_PROFIT_PERCENT"
|
||||||
|
)
|
||||||
|
|
||||||
# 5) 取消旧的保护单(Algo 条件单),避免重复
|
# 5) 取消旧的保护单(Algo 条件单),避免重复
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user