修复滚仓
This commit is contained in:
@@ -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
@@ -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,
|
||||||
|
|||||||
+40
-28
@@ -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
|
||||||
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)
|
flash(msg)
|
||||||
return redirect(url_for("strategy_trading_page"))
|
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]:
|
def _roll_execute(cfg: dict, data: dict) -> tuple[bool, str]:
|
||||||
ok_live, reason = cfg["ensure_live_ready"]()
|
get_db = cfg["get_db"]
|
||||||
if not ok_live:
|
conn = None
|
||||||
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"])
|
|
||||||
try:
|
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":
|
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]:
|
||||||
|
|||||||
Reference in New Issue
Block a user