修复滚仓

This commit is contained in:
dekun
2026-05-28 13:27:02 +08:00
parent aa92952b2d
commit a1b3b5d478
3 changed files with 66 additions and 33 deletions
+3
View File
@@ -2267,6 +2267,9 @@ def friendly_okx_error(err, available_usdt=None):
return f"交易所下单失败:{clean}" return f"交易所下单失败:{clean}"
friendly_exchange_error = friendly_okx_error
def get_exchange_capitals(force=False): def get_exchange_capitals(force=False):
ok_live, _ = ensure_okx_live_ready() ok_live, _ = ensure_okx_live_ready()
if not ok_live: if not ok_live:
+23 -5
View File
@@ -97,9 +97,14 @@ def build_strategy_config(
def limit_add(ex_sym, direction, amount, price, leverage): def limit_add(ex_sym, direction, amount, price, leverage):
m.exchange.set_leverage(int(leverage), ex_sym) m.exchange.set_leverage(int(leverage), ex_sym)
side = "buy" if direction == "long" else "sell" side = "buy" if direction == "long" else "sell"
params = {} if hasattr(m, "build_okx_order_params"):
if hasattr(m, "build_gate_order_params"): params = m.build_okx_order_params(direction, reduce_only=False)
elif hasattr(m, "build_binance_order_params"):
params = m.build_binance_order_params(direction, reduce_only=False)
elif hasattr(m, "build_gate_order_params"):
params = m.build_gate_order_params(direction, reduce_only=False) params = m.build_gate_order_params(direction, reduce_only=False)
else:
params = {}
return m.exchange.create_order(ex_sym, "limit", side, float(amount), float(price), params or None) return m.exchange.create_order(ex_sym, "limit", side, float(amount), float(price), params or None)
def replace_tpsl(ex_sym, direction, sl, tp, order_row): def replace_tpsl(ex_sym, direction, sl, tp, order_row):
@@ -116,6 +121,21 @@ def build_strategy_config(
except Exception: except Exception:
return 0 return 0
def friendly_error(err):
fn = getattr(m, "friendly_exchange_error", None) or getattr(
m, "friendly_okx_error", None
)
if not callable(fn):
return str(err)
try:
snap = m.get_available_trading_usdt()
except Exception:
snap = None
try:
return fn(err, available_usdt=snap)
except TypeError:
return fn(err)
note = trend_disabled_note or ( note = trend_disabled_note or (
"趋势回调(自动补仓)请在 Gate 趋势机器人实例使用:/strategy/trend" "趋势回调(自动补仓)请在 Gate 趋势机器人实例使用:/strategy/trend"
) )
@@ -138,9 +158,7 @@ def build_strategy_config(
"ensure_live_ready": m.ensure_exchange_live_ready, "ensure_live_ready": m.ensure_exchange_live_ready,
"default_risk_percent": float(getattr(m, "RISK_PERCENT", 2)), "default_risk_percent": float(getattr(m, "RISK_PERCENT", 2)),
"default_leverage": m.infer_leverage, "default_leverage": m.infer_leverage,
"friendly_error": lambda e: m.friendly_exchange_error(e, available_usdt=m.get_available_trading_usdt()) "friendly_error": friendly_error,
if "friendly_exchange_error" in dir(m)
else str(e),
"app_now_str": m.app_now_str, "app_now_str": m.app_now_str,
"resolve_fill_price": m.resolve_order_entry_price, "resolve_fill_price": m.resolve_order_entry_price,
"price_fmt": m.format_price_for_symbol, "price_fmt": m.format_price_for_symbol,
+18 -6
View File
@@ -66,7 +66,12 @@ def register_strategy_trading(app: Flask, cfg: dict[str, Any]) -> None:
@app.route("/strategy/roll/execute", methods=["POST"]) @app.route("/strategy/roll/execute", methods=["POST"])
def strategy_roll_execute(): def strategy_roll_execute():
data = request.form data = request.form
try:
ok, msg = _roll_execute(cfg, data) ok, msg = _roll_execute(cfg, data)
except Exception as e:
fe = cfg.get("friendly_error")
msg = fe(e) if callable(fe) else str(e)
ok = False
flash(msg) flash(msg)
return redirect(url_for("strategy_trading_page")) return redirect(url_for("strategy_trading_page"))
@@ -170,6 +175,9 @@ def _roll_preview_response(cfg: dict, data: dict, json_mode: bool = False) -> di
def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]: def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]:
get_db = cfg["get_db"]
conn = None
try:
ok_live, reason = cfg["ensure_live_ready"]() ok_live, reason = cfg["ensure_live_ready"]()
if not ok_live: if not ok_live:
return False, reason or "实盘未就绪" return False, reason or "实盘未就绪"
@@ -184,17 +192,18 @@ def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]:
amount = cfg["amount_to_precision"](ex_sym, float(preview["add_amount_raw"])) amount = cfg["amount_to_precision"](ex_sym, float(preview["add_amount_raw"]))
if amount is None or amount <= 0: if amount is None or amount <= 0:
return False, "加仓张数低于交易所最小精度" return False, "加仓张数低于交易所最小精度"
leverage = int(data.get("leverage") or 0) or int(cfg.get("default_leverage", lambda s: 5)(symbol)) lev_fn = cfg.get("default_leverage")
if not callable(lev_fn):
lev_fn = lambda _s: 5
leverage = int(data.get("leverage") or 0) or int(lev_fn(symbol))
conn = get_db() conn = get_db()
init_strategy_tables(conn) init_strategy_tables(conn)
mon = _get_active_monitor(conn, cfg, symbol, direction) mon = _get_active_monitor(conn, cfg, symbol, direction)
if not mon: if not mon:
conn.close()
return False, "监控单已不存在" return False, "监控单已不存在"
rg, legs_done = _get_or_create_roll_group_meta(conn, mon) rg, legs_done = _get_or_create_roll_group_meta(conn, mon)
new_sl = float(preview["new_stop_loss"]) new_sl = float(preview["new_stop_loss"])
tp0 = float(preview["initial_take_profit"]) tp0 = float(preview["initial_take_profit"])
try:
if add_mode == "market": if add_mode == "market":
order = cfg["market_add"](ex_sym, direction, amount, leverage) order = cfg["market_add"](ex_sym, direction, amount, leverage)
fill = float(cfg.get("resolve_fill_price", lambda o, s, p: p)(order, ex_sym, preview["add_price"]) or preview["add_price"]) fill = float(cfg.get("resolve_fill_price", lambda o, s, p: p)(order, ex_sym, preview["add_price"]) or preview["add_price"])
@@ -228,7 +237,6 @@ def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]:
(legs_done + 1, cfg["app_now_str"](), rg["id"]), (legs_done + 1, cfg["app_now_str"](), rg["id"]),
) )
conn.commit() conn.commit()
conn.close()
return True, f"已挂限价加仓单 #{oid},成交后请在页面点「同步持仓并更新止损」" return True, f"已挂限价加仓单 #{oid},成交后请在页面点「同步持仓并更新止损」"
cfg["replace_tpsl"](ex_sym, direction, new_sl, tp0, mon) cfg["replace_tpsl"](ex_sym, direction, new_sl, tp0, mon)
conn.execute( conn.execute(
@@ -260,12 +268,16 @@ def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]:
(new_sl, mon["id"]), (new_sl, mon["id"]),
) )
conn.commit() conn.commit()
conn.close()
return True, f"滚仓第 {legs_done + 1} 腿已市价成交,交易所止损已更新,止盈仍为首仓 {tp0}" return True, f"滚仓第 {legs_done + 1} 腿已市价成交,交易所止损已更新,止盈仍为首仓 {tp0}"
except Exception as e: except Exception as e:
conn.close()
fe = cfg.get("friendly_error") fe = cfg.get("friendly_error")
return False, fe(e) if callable(fe) else str(e) return False, fe(e) if callable(fe) else str(e)
finally:
if conn is not None:
try:
conn.close()
except Exception:
pass
def _get_active_monitor(conn, cfg: dict, symbol: str, direction: str) -> Optional[dict]: def _get_active_monitor(conn, cfg: dict, symbol: str, direction: str) -> Optional[dict]: