diff --git a/crypto_monitor_binance/app.py b/crypto_monitor_binance/app.py index d2cb523..2d26f1f 100644 --- a/crypto_monitor_binance/app.py +++ b/crypto_monitor_binance/app.py @@ -5421,18 +5421,30 @@ def _execute_trigger_entry_cross(conn, row): conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,)) conn.commit() - ok, err, det = _market_open_for_trigger_entry( - conn, - symbol, - direction, - ex_sym, - entry, - sl, - tp, - breakeven_enabled=be_en, - time_close_enabled=tc_en, - time_close_hours=tc_h, - ) + try: + ok, err, det = _market_open_for_trigger_entry( + conn, + symbol, + direction, + ex_sym, + entry, + sl, + tp, + breakeven_enabled=be_en, + time_close_enabled=tc_en, + time_close_hours=tc_h, + ) + except Exception as e: + fail_msg = friendly_exchange_error(e) + send_wechat_msg( + f"# ❌ {symbol} 触价开仓异常\n" + f"**账户:{_wechat_account_label()}**\n" + f"- 计划入场:{format_price_for_symbol(symbol, entry)}\n" + f"- 原因:{fail_msg}\n" + ) + insert_key_monitor_history(conn, row, 0, fail_msg, TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED) + return False, fail_msg + if ok and det: rr_txt = format_wechat_scalar_2dp(det.get("planned_rr_fill")) if det.get("planned_rr_fill") is not None else "-" msg = ( @@ -5498,22 +5510,12 @@ def check_trigger_entry_key_monitors(): _finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE) continue if trigger_entry_reached(direction, mark, entry): - try: - _execute_trigger_entry_cross(conn, r) - except Exception as e: - fail_msg = friendly_exchange_error(e) - try: - insert_key_monitor_history(conn, r, 0, fail_msg, TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED) - except Exception: - pass - send_wechat_msg( - f"# ❌ {symbol} 触价开仓异常\n**账户:{_wechat_account_label()}**\n- {fail_msg}\n" - ) + _execute_trigger_entry_cross(conn, r) conn.commit() conn.close() - +def check_fib_key_monitors(): conn = get_db() rows = conn.execute("SELECT * FROM key_monitors").fetchall() for r in rows: @@ -6857,6 +6859,7 @@ def api_price_snapshot(): gate_metrics = "" fib_gate_ok = True fb_gate_ok = True + te_gate_ok = True if is_fib: direction = (r["direction"] or "long").lower() inval = fib_invalidate_by_mark(direction, price, r["upper"], r["lower"]) @@ -6895,7 +6898,7 @@ def api_price_snapshot(): ) gate_summary = prev.get("summary") or "-" gate_metrics = prev.get("metrics") or "" - fib_gate_ok = bool(prev.get("gate_ok")) + te_gate_ok = bool(prev.get("gate_ok")) elif (r["monitor_type"] or "").strip() in KEY_MONITOR_RS_TYPES: try: prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"]) @@ -6951,6 +6954,7 @@ def api_price_snapshot(): "gate_ok": ( fib_gate_ok if is_fib else fb_gate_ok if is_fb + else te_gate_ok if is_te else bool(gate and gate.get("ok")) ), "gate_metrics": gate_metrics, @@ -7512,40 +7516,40 @@ def add_key(): if tc_en and not tc_h: tc_en = 0 if is_trigger_entry_key_monitor_type(mt): - if direction_sel not in ("long", "short"): - conn.close() - conn = None - flash("触价开仓请选择做多或做空") - return redirect("/key_monitor") - try: - entry_px = float(d.get("trigger_entry") or 0) - sl_px = float(d.get("trigger_sl") or 0) - tp_px = float(d.get("trigger_tp") or 0) - except (TypeError, ValueError): - entry_px = sl_px = tp_px = 0 - if entry_px <= 0 or sl_px <= 0 or tp_px <= 0: - conn.close() - conn = None - flash("触价开仓须填写有效的入场价、止损价、止盈价") - return redirect("/key_monitor") - ok_te, err_te = _add_trigger_entry_key_monitor( - conn, symbol, direction_sel, entry_px, sl_px, tp_px, breakeven_enabled=be_flag, - time_close_enabled=tc_en, time_close_hours=tc_h, - ) - conn.commit() + if direction_sel not in ("long", "short"): conn.close() conn = None - if not ok_te: - flash(err_te or "触价开仓监控添加失败") - return redirect("/key_monitor") - flash( - f"触价开仓已添加({symbol} 日成交量排名 {rank}/{total})" - f"|有效期 {TRIGGER_ENTRY_VALIDITY_HOURS}h" - f"|标记价触达入场价后下一轮询市价开仓" - f"|移动保本:{'开' if be_flag else '关'}" - + (f"|{time_close_label(tc_h)}" if tc_en else "") - ) + flash("触价开仓请选择做多或做空") return redirect("/key_monitor") + try: + entry_px = float(d.get("trigger_entry") or 0) + sl_px = float(d.get("trigger_sl") or 0) + tp_px = float(d.get("trigger_tp") or 0) + except (TypeError, ValueError): + entry_px = sl_px = tp_px = 0 + if entry_px <= 0 or sl_px <= 0 or tp_px <= 0: + conn.close() + conn = None + flash("触价开仓须填写有效的入场价、止损价、止盈价") + return redirect("/key_monitor") + ok_te, err_te = _add_trigger_entry_key_monitor( + conn, symbol, direction_sel, entry_px, sl_px, tp_px, breakeven_enabled=be_flag, + time_close_enabled=tc_en, time_close_hours=tc_h, + ) + conn.commit() + conn.close() + conn = None + if not ok_te: + flash(err_te or "触价开仓监控添加失败") + return redirect("/key_monitor") + flash( + f"触价开仓已添加({symbol} 日成交量排名 {rank}/{total})" + f"|有效期 {TRIGGER_ENTRY_VALIDITY_HOURS}h" + f"|标记价触达入场价后下一轮询市价开仓" + f"|移动保本:{'开' if be_flag else '关'}" + + (f"|{time_close_label(tc_h)}" if tc_en else "") + ) + return redirect("/key_monitor") if is_false_breakout_key_monitor_type(mt): fb_sym = normalize_false_breakout_symbol(symbol) if not fb_sym: diff --git a/crypto_monitor_gate/app.py b/crypto_monitor_gate/app.py index 72b7505..9aa9072 100644 --- a/crypto_monitor_gate/app.py +++ b/crypto_monitor_gate/app.py @@ -5391,18 +5391,30 @@ def _execute_trigger_entry_cross(conn, row): conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,)) conn.commit() - ok, err, det = _market_open_for_trigger_entry( - conn, - symbol, - direction, - ex_sym, - entry, - sl, - tp, - breakeven_enabled=be_en, - time_close_enabled=tc_en, - time_close_hours=tc_h, - ) + try: + ok, err, det = _market_open_for_trigger_entry( + conn, + symbol, + direction, + ex_sym, + entry, + sl, + tp, + breakeven_enabled=be_en, + time_close_enabled=tc_en, + time_close_hours=tc_h, + ) + except Exception as e: + fail_msg = friendly_exchange_error(e) + send_wechat_msg( + f"# ❌ {symbol} 触价开仓异常\n" + f"**账户:{_wechat_account_label()}**\n" + f"- 计划入场:{format_price_for_symbol(symbol, entry)}\n" + f"- 原因:{fail_msg}\n" + ) + insert_key_monitor_history(conn, row, 0, fail_msg, TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED) + return False, fail_msg + if ok and det: rr_txt = format_wechat_scalar_2dp(det.get("planned_rr_fill")) if det.get("planned_rr_fill") is not None else "-" msg = ( @@ -5468,17 +5480,7 @@ def check_trigger_entry_key_monitors(): _finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE) continue if trigger_entry_reached(direction, mark, entry): - try: - _execute_trigger_entry_cross(conn, r) - except Exception as e: - fail_msg = friendly_exchange_error(e) - try: - insert_key_monitor_history(conn, r, 0, fail_msg, TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED) - except Exception: - pass - send_wechat_msg( - f"# ❌ {symbol} 触价开仓异常\n**账户:{_wechat_account_label()}**\n- {fail_msg}\n" - ) + _execute_trigger_entry_cross(conn, r) conn.commit() conn.close() @@ -6989,6 +6991,7 @@ def api_price_snapshot(): gate_metrics = "" fib_gate_ok = True fb_gate_ok = True + te_gate_ok = True if is_fib: direction = (r["direction"] or "long").lower() inval = fib_invalidate_by_mark(direction, price, r["upper"], r["lower"]) @@ -7027,7 +7030,7 @@ def api_price_snapshot(): ) gate_summary = prev.get("summary") or "-" gate_metrics = prev.get("metrics") or "" - fib_gate_ok = bool(prev.get("gate_ok")) + te_gate_ok = bool(prev.get("gate_ok")) elif (r["monitor_type"] or "").strip() in KEY_MONITOR_RS_TYPES: try: prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"]) @@ -7087,6 +7090,7 @@ def api_price_snapshot(): "gate_ok": ( fib_gate_ok if is_fib else fb_gate_ok if is_fb + else te_gate_ok if is_te else bool(gate and gate.get("ok")) ), "gate_metrics": gate_metrics, diff --git a/crypto_monitor_gate_bot/app.py b/crypto_monitor_gate_bot/app.py index 2dd9b07..0d75a82 100644 --- a/crypto_monitor_gate_bot/app.py +++ b/crypto_monitor_gate_bot/app.py @@ -5391,18 +5391,30 @@ def _execute_trigger_entry_cross(conn, row): conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,)) conn.commit() - ok, err, det = _market_open_for_trigger_entry( - conn, - symbol, - direction, - ex_sym, - entry, - sl, - tp, - breakeven_enabled=be_en, - time_close_enabled=tc_en, - time_close_hours=tc_h, - ) + try: + ok, err, det = _market_open_for_trigger_entry( + conn, + symbol, + direction, + ex_sym, + entry, + sl, + tp, + breakeven_enabled=be_en, + time_close_enabled=tc_en, + time_close_hours=tc_h, + ) + except Exception as e: + fail_msg = friendly_exchange_error(e) + send_wechat_msg( + f"# ❌ {symbol} 触价开仓异常\n" + f"**账户:{_wechat_account_label()}**\n" + f"- 计划入场:{format_price_for_symbol(symbol, entry)}\n" + f"- 原因:{fail_msg}\n" + ) + insert_key_monitor_history(conn, row, 0, fail_msg, TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED) + return False, fail_msg + if ok and det: rr_txt = format_wechat_scalar_2dp(det.get("planned_rr_fill")) if det.get("planned_rr_fill") is not None else "-" msg = ( @@ -5468,22 +5480,12 @@ def check_trigger_entry_key_monitors(): _finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE) continue if trigger_entry_reached(direction, mark, entry): - try: - _execute_trigger_entry_cross(conn, r) - except Exception as e: - fail_msg = friendly_exchange_error(e) - try: - insert_key_monitor_history(conn, r, 0, fail_msg, TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED) - except Exception: - pass - send_wechat_msg( - f"# ❌ {symbol} 触价开仓异常\n**账户:{_wechat_account_label()}**\n- {fail_msg}\n" - ) + _execute_trigger_entry_cross(conn, r) conn.commit() conn.close() - +def check_fib_key_monitors(): conn = get_db() rows = conn.execute("SELECT * FROM key_monitors").fetchall() for r in rows: @@ -6989,6 +6991,7 @@ def api_price_snapshot(): gate_metrics = "" fib_gate_ok = True fb_gate_ok = True + te_gate_ok = True if is_fib: direction = (r["direction"] or "long").lower() inval = fib_invalidate_by_mark(direction, price, r["upper"], r["lower"]) @@ -7027,7 +7030,7 @@ def api_price_snapshot(): ) gate_summary = prev.get("summary") or "-" gate_metrics = prev.get("metrics") or "" - fib_gate_ok = bool(prev.get("gate_ok")) + te_gate_ok = bool(prev.get("gate_ok")) elif (r["monitor_type"] or "").strip() in KEY_MONITOR_RS_TYPES: try: prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"]) @@ -7087,6 +7090,7 @@ def api_price_snapshot(): "gate_ok": ( fib_gate_ok if is_fib else fb_gate_ok if is_fb + else te_gate_ok if is_te else bool(gate and gate.get("ok")) ), "gate_metrics": gate_metrics, diff --git a/crypto_monitor_okx/app.py b/crypto_monitor_okx/app.py index e24cd48..e75df06 100644 --- a/crypto_monitor_okx/app.py +++ b/crypto_monitor_okx/app.py @@ -1653,6 +1653,7 @@ def _count_opens_for_segment(conn, start_td, end_td, segment_key): "key_fib618": "斐波回调0.618", "key_fib786": "斐波回调0.786", "key_false_breakout": FALSE_BREAKOUT_MONITOR_TYPE, + "key_trigger": TRIGGER_ENTRY_MONITOR_TYPE, } kst = kst_map.get(segment_key) if kst: @@ -4948,18 +4949,30 @@ def _execute_trigger_entry_cross(conn, row): conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,)) conn.commit() - ok, err, det = _market_open_for_trigger_entry( - conn, - symbol, - direction, - ex_sym, - entry, - sl, - tp, - breakeven_enabled=be_en, - time_close_enabled=tc_en, - time_close_hours=tc_h, - ) + try: + ok, err, det = _market_open_for_trigger_entry( + conn, + symbol, + direction, + ex_sym, + entry, + sl, + tp, + breakeven_enabled=be_en, + time_close_enabled=tc_en, + time_close_hours=tc_h, + ) + except Exception as e: + fail_msg = friendly_exchange_error(e) + send_wechat_msg( + f"# ❌ {symbol} 触价开仓异常\n" + f"**账户:{_wechat_account_label()}**\n" + f"- 计划入场:{format_price_for_symbol(symbol, entry)}\n" + f"- 原因:{fail_msg}\n" + ) + insert_key_monitor_history(conn, row, 0, fail_msg, TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED) + return False, fail_msg + if ok and det: rr_txt = format_wechat_scalar_2dp(det.get("planned_rr_fill")) if det.get("planned_rr_fill") is not None else "-" msg = ( @@ -5025,22 +5038,12 @@ def check_trigger_entry_key_monitors(): _finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE) continue if trigger_entry_reached(direction, mark, entry): - try: - _execute_trigger_entry_cross(conn, r) - except Exception as e: - fail_msg = friendly_exchange_error(e) - try: - insert_key_monitor_history(conn, r, 0, fail_msg, TRIGGER_ENTRY_CLOSE_EXCHANGE_FAILED) - except Exception: - pass - send_wechat_msg( - f"# ❌ {symbol} 触价开仓异常\n**账户:{_wechat_account_label()}**\n- {fail_msg}\n" - ) + _execute_trigger_entry_cross(conn, r) conn.commit() conn.close() - +def check_fib_key_monitors(): conn = get_db() rows = conn.execute("SELECT * FROM key_monitors").fetchall() for r in rows: @@ -6573,6 +6576,7 @@ def api_price_snapshot(): gate_metrics = "" fib_gate_ok = True fb_gate_ok = True + te_gate_ok = True if is_fib: direction = (r["direction"] or "long").lower() inval = fib_invalidate_by_mark(direction, price, r["upper"], r["lower"]) @@ -6611,7 +6615,7 @@ def api_price_snapshot(): ) gate_summary = prev.get("summary") or "-" gate_metrics = prev.get("metrics") or "" - fib_gate_ok = bool(prev.get("gate_ok")) + te_gate_ok = bool(prev.get("gate_ok")) elif (r["monitor_type"] or "").strip() in KEY_MONITOR_RS_TYPES: try: prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"]) @@ -6671,6 +6675,7 @@ def api_price_snapshot(): "gate_ok": ( fib_gate_ok if is_fib else fb_gate_ok if is_fb + else te_gate_ok if is_te else bool(gate and gate.get("ok")) ), "gate_metrics": gate_metrics, @@ -7256,6 +7261,38 @@ def add_key(): tc_h = parse_time_close_hours_form(d.get("time_close_hours")) if tc_en else None if tc_en and not tc_h: tc_en = 0 + if is_trigger_entry_key_monitor_type(mt): + if direction_sel not in ("long", "short"): + conn.close() + flash("触价开仓请选择做多或做空") + return redirect("/key_monitor") + try: + entry_px = float(d.get("trigger_entry") or 0) + sl_px = float(d.get("trigger_sl") or 0) + tp_px = float(d.get("trigger_tp") or 0) + except (TypeError, ValueError): + entry_px = sl_px = tp_px = 0 + if entry_px <= 0 or sl_px <= 0 or tp_px <= 0: + conn.close() + flash("触价开仓须填写有效的入场价、止损价、止盈价") + return redirect("/key_monitor") + ok_te, err_te = _add_trigger_entry_key_monitor( + conn, symbol, direction_sel, entry_px, sl_px, tp_px, breakeven_enabled=be_flag, + time_close_enabled=tc_en, time_close_hours=tc_h, + ) + conn.commit() + conn.close() + if not ok_te: + flash(err_te or "触价开仓监控添加失败") + return redirect("/key_monitor") + flash( + f"触价开仓已添加({symbol} 日成交量排名 {rank}/{total})" + f"|有效期 {TRIGGER_ENTRY_VALIDITY_HOURS}h" + f"|标记价触达入场价后下一轮询市价开仓" + f"|移动保本:{'开' if be_flag else '关'}" + + (f"|{time_close_label(tc_h)}" if tc_en else "") + ) + return redirect("/key_monitor") if is_false_breakout_key_monitor_type(mt): fb_sym = normalize_false_breakout_symbol(symbol) if not fb_sym: