fix(key-monitor): repair trigger entry bugs in four exchange apps
Restore missing check_fib_key_monitors, fix gate preview and OKX add_key, and unify trigger execution error handling to avoid duplicate history writes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5421,18 +5421,30 @@ def _execute_trigger_entry_cross(conn, row):
|
|||||||
conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,))
|
conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
ok, err, det = _market_open_for_trigger_entry(
|
try:
|
||||||
conn,
|
ok, err, det = _market_open_for_trigger_entry(
|
||||||
symbol,
|
conn,
|
||||||
direction,
|
symbol,
|
||||||
ex_sym,
|
direction,
|
||||||
entry,
|
ex_sym,
|
||||||
sl,
|
entry,
|
||||||
tp,
|
sl,
|
||||||
breakeven_enabled=be_en,
|
tp,
|
||||||
time_close_enabled=tc_en,
|
breakeven_enabled=be_en,
|
||||||
time_close_hours=tc_h,
|
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:
|
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 "-"
|
rr_txt = format_wechat_scalar_2dp(det.get("planned_rr_fill")) if det.get("planned_rr_fill") is not None else "-"
|
||||||
msg = (
|
msg = (
|
||||||
@@ -5498,22 +5510,12 @@ def check_trigger_entry_key_monitors():
|
|||||||
_finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE)
|
_finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE)
|
||||||
continue
|
continue
|
||||||
if trigger_entry_reached(direction, mark, entry):
|
if trigger_entry_reached(direction, mark, entry):
|
||||||
try:
|
_execute_trigger_entry_cross(conn, r)
|
||||||
_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"
|
|
||||||
)
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def check_fib_key_monitors():
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
rows = conn.execute("SELECT * FROM key_monitors").fetchall()
|
rows = conn.execute("SELECT * FROM key_monitors").fetchall()
|
||||||
for r in rows:
|
for r in rows:
|
||||||
@@ -6857,6 +6859,7 @@ def api_price_snapshot():
|
|||||||
gate_metrics = ""
|
gate_metrics = ""
|
||||||
fib_gate_ok = True
|
fib_gate_ok = True
|
||||||
fb_gate_ok = True
|
fb_gate_ok = True
|
||||||
|
te_gate_ok = True
|
||||||
if is_fib:
|
if is_fib:
|
||||||
direction = (r["direction"] or "long").lower()
|
direction = (r["direction"] or "long").lower()
|
||||||
inval = fib_invalidate_by_mark(direction, price, r["upper"], r["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_summary = prev.get("summary") or "-"
|
||||||
gate_metrics = prev.get("metrics") 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:
|
elif (r["monitor_type"] or "").strip() in KEY_MONITOR_RS_TYPES:
|
||||||
try:
|
try:
|
||||||
prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"])
|
prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"])
|
||||||
@@ -6951,6 +6954,7 @@ def api_price_snapshot():
|
|||||||
"gate_ok": (
|
"gate_ok": (
|
||||||
fib_gate_ok if is_fib
|
fib_gate_ok if is_fib
|
||||||
else fb_gate_ok if is_fb
|
else fb_gate_ok if is_fb
|
||||||
|
else te_gate_ok if is_te
|
||||||
else bool(gate and gate.get("ok"))
|
else bool(gate and gate.get("ok"))
|
||||||
),
|
),
|
||||||
"gate_metrics": gate_metrics,
|
"gate_metrics": gate_metrics,
|
||||||
@@ -7512,40 +7516,40 @@ def add_key():
|
|||||||
if tc_en and not tc_h:
|
if tc_en and not tc_h:
|
||||||
tc_en = 0
|
tc_en = 0
|
||||||
if is_trigger_entry_key_monitor_type(mt):
|
if is_trigger_entry_key_monitor_type(mt):
|
||||||
if direction_sel not in ("long", "short"):
|
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()
|
|
||||||
conn.close()
|
conn.close()
|
||||||
conn = None
|
conn = None
|
||||||
if not ok_te:
|
flash("触价开仓请选择做多或做空")
|
||||||
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")
|
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):
|
if is_false_breakout_key_monitor_type(mt):
|
||||||
fb_sym = normalize_false_breakout_symbol(symbol)
|
fb_sym = normalize_false_breakout_symbol(symbol)
|
||||||
if not fb_sym:
|
if not fb_sym:
|
||||||
|
|||||||
+28
-24
@@ -5391,18 +5391,30 @@ def _execute_trigger_entry_cross(conn, row):
|
|||||||
conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,))
|
conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
ok, err, det = _market_open_for_trigger_entry(
|
try:
|
||||||
conn,
|
ok, err, det = _market_open_for_trigger_entry(
|
||||||
symbol,
|
conn,
|
||||||
direction,
|
symbol,
|
||||||
ex_sym,
|
direction,
|
||||||
entry,
|
ex_sym,
|
||||||
sl,
|
entry,
|
||||||
tp,
|
sl,
|
||||||
breakeven_enabled=be_en,
|
tp,
|
||||||
time_close_enabled=tc_en,
|
breakeven_enabled=be_en,
|
||||||
time_close_hours=tc_h,
|
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:
|
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 "-"
|
rr_txt = format_wechat_scalar_2dp(det.get("planned_rr_fill")) if det.get("planned_rr_fill") is not None else "-"
|
||||||
msg = (
|
msg = (
|
||||||
@@ -5468,17 +5480,7 @@ def check_trigger_entry_key_monitors():
|
|||||||
_finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE)
|
_finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE)
|
||||||
continue
|
continue
|
||||||
if trigger_entry_reached(direction, mark, entry):
|
if trigger_entry_reached(direction, mark, entry):
|
||||||
try:
|
_execute_trigger_entry_cross(conn, r)
|
||||||
_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"
|
|
||||||
)
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
@@ -6989,6 +6991,7 @@ def api_price_snapshot():
|
|||||||
gate_metrics = ""
|
gate_metrics = ""
|
||||||
fib_gate_ok = True
|
fib_gate_ok = True
|
||||||
fb_gate_ok = True
|
fb_gate_ok = True
|
||||||
|
te_gate_ok = True
|
||||||
if is_fib:
|
if is_fib:
|
||||||
direction = (r["direction"] or "long").lower()
|
direction = (r["direction"] or "long").lower()
|
||||||
inval = fib_invalidate_by_mark(direction, price, r["upper"], r["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_summary = prev.get("summary") or "-"
|
||||||
gate_metrics = prev.get("metrics") 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:
|
elif (r["monitor_type"] or "").strip() in KEY_MONITOR_RS_TYPES:
|
||||||
try:
|
try:
|
||||||
prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"])
|
prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"])
|
||||||
@@ -7087,6 +7090,7 @@ def api_price_snapshot():
|
|||||||
"gate_ok": (
|
"gate_ok": (
|
||||||
fib_gate_ok if is_fib
|
fib_gate_ok if is_fib
|
||||||
else fb_gate_ok if is_fb
|
else fb_gate_ok if is_fb
|
||||||
|
else te_gate_ok if is_te
|
||||||
else bool(gate and gate.get("ok"))
|
else bool(gate and gate.get("ok"))
|
||||||
),
|
),
|
||||||
"gate_metrics": gate_metrics,
|
"gate_metrics": gate_metrics,
|
||||||
|
|||||||
@@ -5391,18 +5391,30 @@ def _execute_trigger_entry_cross(conn, row):
|
|||||||
conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,))
|
conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
ok, err, det = _market_open_for_trigger_entry(
|
try:
|
||||||
conn,
|
ok, err, det = _market_open_for_trigger_entry(
|
||||||
symbol,
|
conn,
|
||||||
direction,
|
symbol,
|
||||||
ex_sym,
|
direction,
|
||||||
entry,
|
ex_sym,
|
||||||
sl,
|
entry,
|
||||||
tp,
|
sl,
|
||||||
breakeven_enabled=be_en,
|
tp,
|
||||||
time_close_enabled=tc_en,
|
breakeven_enabled=be_en,
|
||||||
time_close_hours=tc_h,
|
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:
|
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 "-"
|
rr_txt = format_wechat_scalar_2dp(det.get("planned_rr_fill")) if det.get("planned_rr_fill") is not None else "-"
|
||||||
msg = (
|
msg = (
|
||||||
@@ -5468,22 +5480,12 @@ def check_trigger_entry_key_monitors():
|
|||||||
_finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE)
|
_finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE)
|
||||||
continue
|
continue
|
||||||
if trigger_entry_reached(direction, mark, entry):
|
if trigger_entry_reached(direction, mark, entry):
|
||||||
try:
|
_execute_trigger_entry_cross(conn, r)
|
||||||
_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"
|
|
||||||
)
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def check_fib_key_monitors():
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
rows = conn.execute("SELECT * FROM key_monitors").fetchall()
|
rows = conn.execute("SELECT * FROM key_monitors").fetchall()
|
||||||
for r in rows:
|
for r in rows:
|
||||||
@@ -6989,6 +6991,7 @@ def api_price_snapshot():
|
|||||||
gate_metrics = ""
|
gate_metrics = ""
|
||||||
fib_gate_ok = True
|
fib_gate_ok = True
|
||||||
fb_gate_ok = True
|
fb_gate_ok = True
|
||||||
|
te_gate_ok = True
|
||||||
if is_fib:
|
if is_fib:
|
||||||
direction = (r["direction"] or "long").lower()
|
direction = (r["direction"] or "long").lower()
|
||||||
inval = fib_invalidate_by_mark(direction, price, r["upper"], r["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_summary = prev.get("summary") or "-"
|
||||||
gate_metrics = prev.get("metrics") 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:
|
elif (r["monitor_type"] or "").strip() in KEY_MONITOR_RS_TYPES:
|
||||||
try:
|
try:
|
||||||
prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"])
|
prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"])
|
||||||
@@ -7087,6 +7090,7 @@ def api_price_snapshot():
|
|||||||
"gate_ok": (
|
"gate_ok": (
|
||||||
fib_gate_ok if is_fib
|
fib_gate_ok if is_fib
|
||||||
else fb_gate_ok if is_fb
|
else fb_gate_ok if is_fb
|
||||||
|
else te_gate_ok if is_te
|
||||||
else bool(gate and gate.get("ok"))
|
else bool(gate and gate.get("ok"))
|
||||||
),
|
),
|
||||||
"gate_metrics": gate_metrics,
|
"gate_metrics": gate_metrics,
|
||||||
|
|||||||
+62
-25
@@ -1653,6 +1653,7 @@ def _count_opens_for_segment(conn, start_td, end_td, segment_key):
|
|||||||
"key_fib618": "斐波回调0.618",
|
"key_fib618": "斐波回调0.618",
|
||||||
"key_fib786": "斐波回调0.786",
|
"key_fib786": "斐波回调0.786",
|
||||||
"key_false_breakout": FALSE_BREAKOUT_MONITOR_TYPE,
|
"key_false_breakout": FALSE_BREAKOUT_MONITOR_TYPE,
|
||||||
|
"key_trigger": TRIGGER_ENTRY_MONITOR_TYPE,
|
||||||
}
|
}
|
||||||
kst = kst_map.get(segment_key)
|
kst = kst_map.get(segment_key)
|
||||||
if kst:
|
if kst:
|
||||||
@@ -4948,18 +4949,30 @@ def _execute_trigger_entry_cross(conn, row):
|
|||||||
conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,))
|
conn.execute("DELETE FROM key_monitors WHERE id=?", (kid,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
ok, err, det = _market_open_for_trigger_entry(
|
try:
|
||||||
conn,
|
ok, err, det = _market_open_for_trigger_entry(
|
||||||
symbol,
|
conn,
|
||||||
direction,
|
symbol,
|
||||||
ex_sym,
|
direction,
|
||||||
entry,
|
ex_sym,
|
||||||
sl,
|
entry,
|
||||||
tp,
|
sl,
|
||||||
breakeven_enabled=be_en,
|
tp,
|
||||||
time_close_enabled=tc_en,
|
breakeven_enabled=be_en,
|
||||||
time_close_hours=tc_h,
|
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:
|
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 "-"
|
rr_txt = format_wechat_scalar_2dp(det.get("planned_rr_fill")) if det.get("planned_rr_fill") is not None else "-"
|
||||||
msg = (
|
msg = (
|
||||||
@@ -5025,22 +5038,12 @@ def check_trigger_entry_key_monitors():
|
|||||||
_finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE)
|
_finalize_key_monitor_one_shot(conn, r, msg, TRIGGER_ENTRY_CLOSE_TP_INVALIDATE)
|
||||||
continue
|
continue
|
||||||
if trigger_entry_reached(direction, mark, entry):
|
if trigger_entry_reached(direction, mark, entry):
|
||||||
try:
|
_execute_trigger_entry_cross(conn, r)
|
||||||
_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"
|
|
||||||
)
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def check_fib_key_monitors():
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
rows = conn.execute("SELECT * FROM key_monitors").fetchall()
|
rows = conn.execute("SELECT * FROM key_monitors").fetchall()
|
||||||
for r in rows:
|
for r in rows:
|
||||||
@@ -6573,6 +6576,7 @@ def api_price_snapshot():
|
|||||||
gate_metrics = ""
|
gate_metrics = ""
|
||||||
fib_gate_ok = True
|
fib_gate_ok = True
|
||||||
fb_gate_ok = True
|
fb_gate_ok = True
|
||||||
|
te_gate_ok = True
|
||||||
if is_fib:
|
if is_fib:
|
||||||
direction = (r["direction"] or "long").lower()
|
direction = (r["direction"] or "long").lower()
|
||||||
inval = fib_invalidate_by_mark(direction, price, r["upper"], r["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_summary = prev.get("summary") or "-"
|
||||||
gate_metrics = prev.get("metrics") 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:
|
elif (r["monitor_type"] or "").strip() in KEY_MONITOR_RS_TYPES:
|
||||||
try:
|
try:
|
||||||
prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"])
|
prev = _key_rs_gate_preview(r["symbol"], r["upper"], r["lower"])
|
||||||
@@ -6671,6 +6675,7 @@ def api_price_snapshot():
|
|||||||
"gate_ok": (
|
"gate_ok": (
|
||||||
fib_gate_ok if is_fib
|
fib_gate_ok if is_fib
|
||||||
else fb_gate_ok if is_fb
|
else fb_gate_ok if is_fb
|
||||||
|
else te_gate_ok if is_te
|
||||||
else bool(gate and gate.get("ok"))
|
else bool(gate and gate.get("ok"))
|
||||||
),
|
),
|
||||||
"gate_metrics": gate_metrics,
|
"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
|
tc_h = parse_time_close_hours_form(d.get("time_close_hours")) if tc_en else None
|
||||||
if tc_en and not tc_h:
|
if tc_en and not tc_h:
|
||||||
tc_en = 0
|
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):
|
if is_false_breakout_key_monitor_type(mt):
|
||||||
fb_sym = normalize_false_breakout_symbol(symbol)
|
fb_sym = normalize_false_breakout_symbol(symbol)
|
||||||
if not fb_sym:
|
if not fb_sym:
|
||||||
|
|||||||
Reference in New Issue
Block a user