修复前端

This commit is contained in:
dekun
2026-05-22 11:29:34 +08:00
parent 371dec6999
commit 427f94e0e8
4 changed files with 246 additions and 114 deletions
+123 -97
View File
@@ -6343,112 +6343,138 @@ def api_key_kline():
@app.route("/add_key", methods=["POST"])
@login_required
def add_key():
d = request.form
symbol = normalize_symbol_input(d.get("symbol"))
if not symbol:
flash("symbol 不能为空")
return redirect("/key_monitor")
direction_sel = (d.get("direction") or "").strip().lower()
if direction_sel not in ("long", "short"):
flash("请选择做多或做空")
return redirect("/key_monitor")
mt = (d.get("type") or "").strip()
allowed_types = (
tuple(KEY_MONITOR_AUTO_TYPES)
+ tuple(KEY_MONITOR_ALERT_ONLY_TYPES)
+ tuple(FIB_KEY_MONITOR_TYPES)
)
if mt not in allowed_types:
flash("监控类型无效")
return redirect("/key_monitor")
rank, total = _daily_volume_rank(symbol)
if rank is None:
flash("日成交量排名读取失败,请稍后重试")
return redirect("/key_monitor")
if rank > KEY_DAILY_VOLUME_RANK_MAX:
flash(f"{symbol} 当前日成交量排名为 {rank}/{total},不在前{KEY_DAILY_VOLUME_RANK_MAX},已拒绝添加关键位")
return redirect("/key_monitor")
conn = get_db()
if mt in KEY_MONITOR_AUTO_TYPES:
occupied = get_active_position_count(conn)
if occupied >= MAX_ACTIVE_POSITIONS:
conn.close()
conn = None
try:
d = request.form
symbol = normalize_symbol_input(d.get("symbol"))
if not symbol:
flash("symbol 不能为空")
return redirect("/key_monitor")
direction_sel = (d.get("direction") or "").strip().lower()
if direction_sel not in ("long", "short"):
flash("请选择做多或做空")
return redirect("/key_monitor")
mt = (d.get("type") or "").strip()
allowed_types = (
tuple(KEY_MONITOR_AUTO_TYPES)
+ tuple(KEY_MONITOR_ALERT_ONLY_TYPES)
+ tuple(FIB_KEY_MONITOR_TYPES)
)
if mt not in allowed_types:
flash("监控类型无效")
return redirect("/key_monitor")
rank, total = _daily_volume_rank(symbol)
if rank is None:
flash("日成交量排名读取失败,请稍后重试")
return redirect("/key_monitor")
if rank > KEY_DAILY_VOLUME_RANK_MAX:
flash(
f"当前持仓已达上限({occupied}/{MAX_ACTIVE_POSITIONS}):无法添加「箱体突破 / 收敛突破」。"
"请平仓后再试,或使用「关键阻力位/关键支撑位」(仅单次提醒)。"
f"{symbol} 当前日成交量排名为 {rank}/{total},不在前{KEY_DAILY_VOLUME_RANK_MAX},已拒绝添加关键位"
)
return redirect("/key_monitor")
ex_sym_key = normalize_exchange_symbol(symbol)
try:
ensure_markets_loaded()
except Exception:
pass
upper_px = round_price_to_exchange(ex_sym_key, float(d["upper"]))
lower_px = round_price_to_exchange(ex_sym_key, float(d["lower"]))
be_flag = parse_breakeven_enabled_form(d.get("breakeven_enabled"))
if is_fib_key_monitor_type(mt):
ok_fib, err_fib = _add_fib_key_monitor(
conn, symbol, direction_sel, mt, upper_px, lower_px, breakeven_enabled=be_flag,
conn = get_db()
if mt in KEY_MONITOR_AUTO_TYPES:
occupied = get_active_position_count(conn)
if occupied >= MAX_ACTIVE_POSITIONS:
conn.close()
conn = None
flash(
f"当前持仓已达上限({occupied}/{MAX_ACTIVE_POSITIONS}):无法添加「箱体突破 / 收敛突破」。"
"请平仓后再试,或使用「关键阻力位/关键支撑位」(仅单次提醒)。"
)
return redirect("/key_monitor")
ex_sym_key = normalize_exchange_symbol(symbol)
try:
ensure_markets_loaded()
except Exception:
pass
try:
upper_raw = float(d.get("upper") or 0)
lower_raw = float(d.get("lower") or 0)
except (TypeError, ValueError):
conn.close()
conn = None
flash("上下沿须为有效数字")
return redirect("/key_monitor")
upper_px = round_price_to_exchange(ex_sym_key, upper_raw)
lower_px = round_price_to_exchange(ex_sym_key, lower_raw)
be_flag = parse_breakeven_enabled_form(d.get("breakeven_enabled"))
if is_fib_key_monitor_type(mt):
ok_fib, err_fib = _add_fib_key_monitor(
conn, symbol, direction_sel, mt, upper_px, lower_px, breakeven_enabled=be_flag,
)
conn.commit()
conn.close()
conn = None
if not ok_fib:
flash(err_fib or "斐波监控添加失败")
return redirect("/key_monitor")
flash(
f"斐波监控已添加,限价单已挂出({symbol} 日成交量排名 {rank}/{total}"
f"|移动保本:{'' if be_flag else ''}"
)
return redirect("/key_monitor")
sl_tp_mode = "standard"
manual_tp = None
if mt in KEY_MONITOR_AUTO_TYPES:
sl_tp_mode = normalize_sl_tp_mode(d.get("sl_tp_mode"))
if sl_tp_mode == "trend_manual":
try:
manual_tp = float(d.get("manual_take_profit") or 0)
except (TypeError, ValueError):
manual_tp = 0
if manual_tp <= 0:
conn.close()
conn = None
flash("趋势单方案须填写有效止盈价")
return redirect("/key_monitor")
if direction_sel == "long" and manual_tp <= upper_px:
conn.close()
conn = None
flash("做多趋势单:止盈价应高于上沿(阻力)")
return redirect("/key_monitor")
if direction_sel == "short" and manual_tp >= lower_px:
conn.close()
conn = None
flash("做空趋势单:止盈价应低于下沿(支撑)")
return redirect("/key_monitor")
mtpx = round_price_to_exchange(ex_sym_key, manual_tp)
if mtpx is not None:
manual_tp = float(mtpx)
conn.execute(
"INSERT INTO key_monitors "
"(symbol,monitor_type,direction,upper,lower,sl_tp_mode,manual_take_profit,breakeven_enabled) "
"VALUES (?,?,?,?,?,?,?,?)",
(symbol, mt, direction_sel, upper_px, lower_px, sl_tp_mode, manual_tp, be_flag),
)
conn.commit()
conn.close()
if not ok_fib:
flash(err_fib or "斐波监控添加失败")
return redirect("/key_monitor")
flash(
f"斐波监控已添加,限价单已挂出({symbol} 日成交量排名 {rank}/{total}"
f"|移动保本:{'' if be_flag else ''}"
)
conn = None
ctr = False
try:
coin4h_status, _, _ = _status_by_ema55(symbol, "4h")
ctr = (direction_sel == "long" and coin4h_status == "空头") or (
direction_sel == "short" and coin4h_status == "多头"
)
except Exception:
pass
extra = ""
if mt in KEY_MONITOR_AUTO_TYPES:
extra = f"|方案:{sl_tp_mode_label(sl_tp_mode)}|移动保本:{'' if be_flag else ''}"
flash(f"添加成功({symbol} 日成交量排名 {rank}/{total}{extra}")
if ctr:
flash(
"⚠️ 4h EMA55 提示:当前与所选方向逆势;「箱体突破/收敛突破」在条件满足时仍会按计划自动市价开仓,请注意仓位。"
)
return redirect("/key_monitor")
sl_tp_mode = "standard"
manual_tp = None
if mt in KEY_MONITOR_AUTO_TYPES:
sl_tp_mode = normalize_sl_tp_mode(d.get("sl_tp_mode"))
if sl_tp_mode == "trend_manual":
except Exception as e:
if conn is not None:
try:
manual_tp = float(d.get("manual_take_profit") or 0)
except (TypeError, ValueError):
manual_tp = 0
if manual_tp <= 0:
conn.close()
flash("趋势单方案须填写有效止盈价")
return redirect("/key_monitor")
if direction_sel == "long" and manual_tp <= upper_px:
conn.close()
flash("做多趋势单:止盈价应高于上沿(阻力)")
return redirect("/key_monitor")
if direction_sel == "short" and manual_tp >= lower_px:
conn.close()
flash("做空趋势单:止盈价应低于下沿(支撑)")
return redirect("/key_monitor")
mtpx = round_price_to_exchange(ex_sym_key, manual_tp)
if mtpx is not None:
manual_tp = float(mtpx)
conn.execute(
"INSERT INTO key_monitors "
"(symbol,monitor_type,direction,upper,lower,sl_tp_mode,manual_take_profit,breakeven_enabled) "
"VALUES (?,?,?,?,?,?,?,?)",
(symbol, mt, direction_sel, upper_px, lower_px, sl_tp_mode, manual_tp, be_flag),
)
conn.commit()
conn.close()
ctr = False
try:
coin4h_status, _, _ = _status_by_ema55(symbol, "4h")
ctr = (direction_sel == "long" and coin4h_status == "空头") or (
direction_sel == "short" and coin4h_status == "多头"
)
except Exception:
pass
extra = ""
if mt in KEY_MONITOR_AUTO_TYPES:
extra = f"|方案:{sl_tp_mode_label(sl_tp_mode)}|移动保本:{'' if be_flag else ''}"
flash(f"添加成功({symbol} 日成交量排名 {rank}/{total}{extra}")
if ctr:
flash(
"⚠️ 4h EMA55 提示:当前与所选方向逆势;「箱体突破/收敛突破」在条件满足时仍会按计划自动市价开仓,请注意仓位。"
)
return redirect("/key_monitor")
except Exception:
pass
flash(f"添加关键位失败:{e}")
return redirect("/key_monitor")
@app.route("/add_order", methods=["POST"])
@login_required