From a1b3b5d4787f7017dd102c759b8dbd1c7a2eb8a5 Mon Sep 17 00:00:00 2001 From: dekun Date: Thu, 28 May 2026 13:27:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=BB=9A=E4=BB=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crypto_monitor_okx/app.py | 3 ++ strategy_config.py | 28 +++++++++++++--- strategy_register.py | 68 +++++++++++++++++++++++---------------- 3 files changed, 66 insertions(+), 33 deletions(-) diff --git a/crypto_monitor_okx/app.py b/crypto_monitor_okx/app.py index 6807b43..7ebfbc7 100644 --- a/crypto_monitor_okx/app.py +++ b/crypto_monitor_okx/app.py @@ -2267,6 +2267,9 @@ def friendly_okx_error(err, available_usdt=None): return f"交易所下单失败:{clean}" +friendly_exchange_error = friendly_okx_error + + def get_exchange_capitals(force=False): ok_live, _ = ensure_okx_live_ready() if not ok_live: diff --git a/strategy_config.py b/strategy_config.py index c505466..79823e5 100644 --- a/strategy_config.py +++ b/strategy_config.py @@ -97,9 +97,14 @@ def build_strategy_config( def limit_add(ex_sym, direction, amount, price, leverage): m.exchange.set_leverage(int(leverage), ex_sym) side = "buy" if direction == "long" else "sell" - params = {} - if hasattr(m, "build_gate_order_params"): + if hasattr(m, "build_okx_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) + else: + params = {} 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): @@ -116,6 +121,21 @@ def build_strategy_config( except Exception: 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 ( "趋势回调(自动补仓)请在 Gate 趋势机器人实例使用:/strategy/trend" ) @@ -138,9 +158,7 @@ def build_strategy_config( "ensure_live_ready": m.ensure_exchange_live_ready, "default_risk_percent": float(getattr(m, "RISK_PERCENT", 2)), "default_leverage": m.infer_leverage, - "friendly_error": lambda e: m.friendly_exchange_error(e, available_usdt=m.get_available_trading_usdt()) - if "friendly_exchange_error" in dir(m) - else str(e), + "friendly_error": friendly_error, "app_now_str": m.app_now_str, "resolve_fill_price": m.resolve_order_entry_price, "price_fmt": m.format_price_for_symbol, diff --git a/strategy_register.py b/strategy_register.py index d18ded1..7fbc0e7 100644 --- a/strategy_register.py +++ b/strategy_register.py @@ -66,7 +66,12 @@ def register_strategy_trading(app: Flask, cfg: dict[str, Any]) -> None: @app.route("/strategy/roll/execute", methods=["POST"]) def strategy_roll_execute(): data = request.form - ok, msg = _roll_execute(cfg, data) + try: + 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) return redirect(url_for("strategy_trading_page")) @@ -170,31 +175,35 @@ def _roll_preview_response(cfg: dict, data: dict, json_mode: bool = False) -> di def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]: - ok_live, reason = cfg["ensure_live_ready"]() - if not ok_live: - return False, reason or "实盘未就绪" - prev = _roll_preview_response(cfg, data) - if not prev.get("ok"): - return False, prev.get("msg") or "预览失败" - preview = prev["preview"] - symbol = cfg["normalize_symbol_input"](data.get("symbol") or "") - direction = preview["direction"] - ex_sym = cfg["normalize_exchange_symbol"](symbol) - add_mode = preview["add_mode"] - amount = cfg["amount_to_precision"](ex_sym, float(preview["add_amount_raw"])) - if amount is None or amount <= 0: - return False, "加仓张数低于交易所最小精度" - leverage = int(data.get("leverage") or 0) or int(cfg.get("default_leverage", lambda s: 5)(symbol)) - conn = get_db() - init_strategy_tables(conn) - mon = _get_active_monitor(conn, cfg, symbol, direction) - if not mon: - conn.close() - return False, "监控单已不存在" - rg, legs_done = _get_or_create_roll_group_meta(conn, mon) - new_sl = float(preview["new_stop_loss"]) - tp0 = float(preview["initial_take_profit"]) + get_db = cfg["get_db"] + conn = None try: + ok_live, reason = cfg["ensure_live_ready"]() + if not ok_live: + return False, reason or "实盘未就绪" + prev = _roll_preview_response(cfg, data) + if not prev.get("ok"): + return False, prev.get("msg") or "预览失败" + preview = prev["preview"] + symbol = cfg["normalize_symbol_input"](data.get("symbol") or "") + direction = preview["direction"] + ex_sym = cfg["normalize_exchange_symbol"](symbol) + add_mode = preview["add_mode"] + amount = cfg["amount_to_precision"](ex_sym, float(preview["add_amount_raw"])) + if amount is None or amount <= 0: + return False, "加仓张数低于交易所最小精度" + 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() + init_strategy_tables(conn) + mon = _get_active_monitor(conn, cfg, symbol, direction) + if not mon: + return False, "监控单已不存在" + rg, legs_done = _get_or_create_roll_group_meta(conn, mon) + new_sl = float(preview["new_stop_loss"]) + tp0 = float(preview["initial_take_profit"]) if add_mode == "market": 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"]) @@ -228,7 +237,6 @@ def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]: (legs_done + 1, cfg["app_now_str"](), rg["id"]), ) conn.commit() - conn.close() return True, f"已挂限价加仓单 #{oid},成交后请在页面点「同步持仓并更新止损」" cfg["replace_tpsl"](ex_sym, direction, new_sl, tp0, mon) conn.execute( @@ -260,12 +268,16 @@ def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]: (new_sl, mon["id"]), ) conn.commit() - conn.close() return True, f"滚仓第 {legs_done + 1} 腿已市价成交,交易所止损已更新,止盈仍为首仓 {tp0}" except Exception as e: - conn.close() fe = cfg.get("friendly_error") 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]: