修改okx推送
This commit is contained in:
+113
-58
@@ -293,6 +293,22 @@ def send_wechat_msg(content):
|
||||
pass
|
||||
|
||||
|
||||
_BREAKEVEN_EXCHANGE_WARNED_IDS = set()
|
||||
|
||||
|
||||
def _send_breakeven_exchange_warn_once(order_id, message):
|
||||
"""移动保本同步交易所失败:同一笔监控单只推送一次,避免轮询刷屏。"""
|
||||
oid = int(order_id)
|
||||
if oid in _BREAKEVEN_EXCHANGE_WARNED_IDS:
|
||||
return
|
||||
_BREAKEVEN_EXCHANGE_WARNED_IDS.add(oid)
|
||||
send_wechat_msg(message)
|
||||
|
||||
|
||||
def _clear_breakeven_exchange_warn(order_id):
|
||||
_BREAKEVEN_EXCHANGE_WARNED_IDS.discard(int(order_id))
|
||||
|
||||
|
||||
def _wechat_account_label():
|
||||
return (os.getenv("OKX_ACCOUNT_LABEL") or "okx实盘子账户").strip()
|
||||
|
||||
@@ -308,15 +324,25 @@ def _wechat_trading_capital_text(fallback=None):
|
||||
except Exception:
|
||||
trading_capital = None
|
||||
if trading_capital is not None:
|
||||
return f"{round(float(trading_capital), 4)}U"
|
||||
return f"{round(float(trading_capital), 2)}U"
|
||||
if fallback is not None:
|
||||
try:
|
||||
return f"{round(float(fallback), 4)}U"
|
||||
return f"{round(float(fallback), 2)}U"
|
||||
except Exception:
|
||||
pass
|
||||
return "-"
|
||||
|
||||
|
||||
def format_wechat_scalar_2dp(value):
|
||||
"""企业微信推送:数值统一两位小数(与交易所 tick 无关)。"""
|
||||
if value in (None, ""):
|
||||
return "-"
|
||||
try:
|
||||
return f"{float(value):.2f}"
|
||||
except (TypeError, ValueError):
|
||||
return str(value)
|
||||
|
||||
|
||||
def build_wechat_close_message(
|
||||
symbol,
|
||||
direction,
|
||||
@@ -332,29 +358,40 @@ def build_wechat_close_message(
|
||||
session_capital_fallback=None,
|
||||
):
|
||||
hold_txt = format_hold_minutes(calc_hold_minutes(hold_seconds)) if hold_seconds is not None else "-"
|
||||
ep = format_price_for_symbol(symbol, trigger_price)
|
||||
cp = format_price_for_symbol(symbol, current_price)
|
||||
tp = format_price_for_symbol(symbol, take_profit)
|
||||
sl = format_wechat_scalar_2dp(stop_loss)
|
||||
cap_txt = _wechat_trading_capital_text(session_capital_fallback)
|
||||
try:
|
||||
if pnl_amount is not None:
|
||||
pv = float(pnl_amount)
|
||||
pnl_disp = f"{'+' if pv > 0 else ''}{round(pv, 2)} U"
|
||||
else:
|
||||
pnl_disp = "-"
|
||||
except (TypeError, ValueError):
|
||||
pnl_disp = "-"
|
||||
|
||||
lines = [
|
||||
f"# ✅ {symbol} 实盘平仓记录",
|
||||
f"**账户:{_wechat_account_label()}**",
|
||||
f"📉 {symbol} 平仓完成",
|
||||
f"💼 账户:{_wechat_account_label()}",
|
||||
"",
|
||||
"---",
|
||||
"🧾 平仓概要",
|
||||
f"🔖 平仓单号:{close_order_id or '-'}",
|
||||
f"📌 方向:{_wechat_direction_text(direction)}",
|
||||
f"📌 平仓结果:{result or '-'}",
|
||||
f"💰 本单盈亏:{pnl_disp}",
|
||||
f"⏱ 持仓时长:{hold_txt}",
|
||||
f"💵 交易账户资金:{cap_txt}",
|
||||
"",
|
||||
"### 平仓基础信息",
|
||||
f"- 方向:**{_wechat_direction_text(direction)}**",
|
||||
f"- 平仓结果:**{result or '-'}**",
|
||||
f"- 交易所平仓ID:`{close_order_id or '-'}`",
|
||||
f"- 持仓时长:`{hold_txt}`",
|
||||
f"- 本单盈亏:`{round(float(pnl_amount), 4) if pnl_amount is not None else '-'}U`",
|
||||
f"- 交易账户资金:`{_wechat_trading_capital_text(session_capital_fallback)}`",
|
||||
"",
|
||||
"---",
|
||||
"",
|
||||
"### 价格信息",
|
||||
f"- 入场价:`{trigger_price if trigger_price is not None else '-'}`",
|
||||
f"- 平仓参考价:`{current_price if current_price is not None else '-'}`",
|
||||
f"- 止盈/止损:`{take_profit if take_profit is not None else '-'}` / `{stop_loss if stop_loss is not None else '-'}`",
|
||||
"🎯 价位(计划)",
|
||||
f"开仓成交价:{ep}",
|
||||
f"离场参考价:{cp}",
|
||||
f"止盈价位:{tp}",
|
||||
f"止损价位:{sl}",
|
||||
]
|
||||
if extra_note:
|
||||
lines.extend(["", f"*备注:{extra_note}*"])
|
||||
lines.extend(["", "📎 备注", extra_note])
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@@ -371,7 +408,7 @@ def build_wechat_breakeven_message(symbol, direction, arm_txt, now_rr, locked_r,
|
||||
f"- 类型:**{arm_txt}**",
|
||||
f"- 当前RR:`{round(float(now_rr), 2)}R`",
|
||||
f"- 锁定RR:`{round(float(locked_r), 2)}R`",
|
||||
f"- 新保护位:`{new_sl}`",
|
||||
f"- 新保护位:`{format_wechat_scalar_2dp(new_sl)}`",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -2262,12 +2299,12 @@ def auto_transfer_once_per_day():
|
||||
if from_balance is not None and from_balance < needed:
|
||||
conn.execute(
|
||||
"INSERT INTO transfer_logs (transfer_type, transfer_day, amount, from_account, to_account, status, message) VALUES (?,?,?,?,?,?,?)",
|
||||
("auto_daily", transfer_day, needed, AUTO_TRANSFER_FROM, AUTO_TRANSFER_TO, "failed", f"{AUTO_TRANSFER_FROM}账户USDT不足,需{needed}U,当前{round(from_balance,4)}U")
|
||||
("auto_daily", transfer_day, needed, AUTO_TRANSFER_FROM, AUTO_TRANSFER_TO, "failed", f"{AUTO_TRANSFER_FROM}账户USDT不足,需{round(needed, 2)}U,当前{round(from_balance, 2)}U")
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
send_wechat_msg(
|
||||
f"自动划转失败:{AUTO_TRANSFER_FROM}余额不足,需{needed}U,当前{round(from_balance,4)}U\n"
|
||||
f"自动划转失败:{AUTO_TRANSFER_FROM}余额不足,需{round(needed, 2)}U,当前{round(from_balance, 2)}U\n"
|
||||
f"账簿日(UTC):{transfer_day}|触发时刻(北京):{app_now_str()}"
|
||||
)
|
||||
return
|
||||
@@ -2281,13 +2318,13 @@ def auto_transfer_once_per_day():
|
||||
conn.close()
|
||||
if ok:
|
||||
send_wechat_msg(
|
||||
f"自动划转成功:补足到{target_amount}U,实际划转{needed}U "
|
||||
f"自动划转成功:补足到{round(float(target_amount), 2)}U,实际划转{round(needed, 2)}U "
|
||||
f"{AUTO_TRANSFER_FROM}->{AUTO_TRANSFER_TO}\n"
|
||||
f"账簿日(UTC):{transfer_day}|触发时刻(北京):{app_now_str()}"
|
||||
)
|
||||
else:
|
||||
send_wechat_msg(
|
||||
f"自动划转失败:计划补足到{target_amount}U,需划转{needed}U\n原因:{msg}\n"
|
||||
f"自动划转失败:计划补足到{round(float(target_amount), 2)}U,需划转{round(needed, 2)}U\n原因:{msg}\n"
|
||||
f"账簿日(UTC):{transfer_day}|触发时刻(北京):{app_now_str()}"
|
||||
)
|
||||
|
||||
@@ -4301,7 +4338,7 @@ def _finalize_fib_key_fill(conn, row):
|
||||
base_amount,
|
||||
oid,
|
||||
)
|
||||
rr_txt = f"{planned_rr:.4f}" if planned_rr is not None else "-"
|
||||
rr_txt = format_wechat_scalar_2dp(planned_rr) if planned_rr is not None else "-"
|
||||
succ = (
|
||||
f"# ✅ {symbol} 斐波限价成交\n"
|
||||
f"**账户:{_wechat_account_label()}**\n"
|
||||
@@ -4309,7 +4346,7 @@ def _finalize_fib_key_fill(conn, row):
|
||||
f"- 类型:{typ}|{_wechat_direction_text(direction)}\n"
|
||||
f"- 订单 ID:**{new_order_id}**\n"
|
||||
f"- 成交价:{format_price_for_symbol(symbol, trigger_price)}\n"
|
||||
f"- 止损:{sl}|止盈:{format_price_for_symbol(symbol, tp)}\n"
|
||||
f"- 止损:{format_wechat_scalar_2dp(sl)}|止盈:{format_price_for_symbol(symbol, tp)}\n"
|
||||
f"- 计划 RR:{rr_txt}:1\n"
|
||||
f"- {'已挂交易所 TP/SL' if tpsl_attached else 'TP/SL 未挂上'}\n"
|
||||
)
|
||||
@@ -4515,7 +4552,7 @@ def check_key_monitors():
|
||||
if plan_tuple:
|
||||
E, sl_raw, tp_raw, box_h = plan_tuple
|
||||
planned_rr = calc_rr_ratio(direction, E, sl_raw, tp_raw)
|
||||
rr_txt = f"{planned_rr:.4f}" if planned_rr is not None else "-"
|
||||
rr_txt = format_wechat_scalar_2dp(planned_rr) if planned_rr is not None else "-"
|
||||
op_lines = [
|
||||
f"录入方案:{sl_tp_mode_label(sl_tp_mode)}|移动保本:{'开' if be_on else '关'}",
|
||||
sl_tp_plan_summary_text(
|
||||
@@ -4523,7 +4560,7 @@ def check_key_monitors():
|
||||
outside_pct=KEY_STOP_OUTSIDE_BREAKOUT_PCT,
|
||||
trend_outside_pct=KEY_TREND_STOP_OUTSIDE_PCT,
|
||||
),
|
||||
f"计划 SL:`{round(sl_raw, 8)}`|计划 TP:`{round(tp_raw, 8)}`|计划 RR(E):{rr_txt}:1",
|
||||
f"计划 SL:`{format_wechat_scalar_2dp(sl_raw)}`|计划 TP:`{format_price_for_symbol(sym, tp_raw)}`|计划 RR(E):{rr_txt}:1",
|
||||
"说明:OKX 本实例为提醒模式,不自动市价开仓;请按方案自行下单。",
|
||||
]
|
||||
else:
|
||||
@@ -4560,6 +4597,7 @@ def check_key_monitors():
|
||||
"\n".join(
|
||||
[
|
||||
f"# 🧾 {r['symbol']} 关键位监控结束",
|
||||
f"**账户:{_wechat_account_label()}**",
|
||||
"",
|
||||
f"- 原因:已满 {max_n} 次提醒",
|
||||
"- 状态:已自动结束并记入历史",
|
||||
@@ -4614,6 +4652,7 @@ def check_order_monitors():
|
||||
direction == "long" and new_sl > float(stop_loss)
|
||||
)
|
||||
if should_move:
|
||||
was_armed = breakeven_armed
|
||||
ex_sym = resolve_monitor_exchange_symbol(r)
|
||||
new_sl = round_price_to_exchange(ex_sym, new_sl)
|
||||
tp_ex = float(take_profit or 0)
|
||||
@@ -4623,13 +4662,15 @@ def check_order_monitors():
|
||||
try:
|
||||
replace_active_monitor_tpsl_on_exchange(r, new_sl, tp_ex)
|
||||
synced_ex = True
|
||||
_clear_breakeven_exchange_warn(pid)
|
||||
except Exception as e:
|
||||
print(
|
||||
f"[breakeven] exchange tpsl replace failed order={pid} {sym}: {e}",
|
||||
flush=True,
|
||||
)
|
||||
send_wechat_msg(
|
||||
f"⚠️ {sym} 移动保本止损未同步交易所:{friendly_okx_error(e)}"
|
||||
_send_breakeven_exchange_warn_once(
|
||||
pid,
|
||||
f"⚠️ {sym} 移动保本止损未同步交易所:{friendly_okx_error(e)}",
|
||||
)
|
||||
elif ok_live:
|
||||
print(
|
||||
@@ -4642,18 +4683,20 @@ def check_order_monitors():
|
||||
(new_sl, new_sl, pid),
|
||||
)
|
||||
stop_loss = new_sl
|
||||
arm_txt = "保本止盈" if not breakeven_armed else "移动止盈"
|
||||
be_msg = build_wechat_breakeven_message(
|
||||
sym,
|
||||
direction,
|
||||
arm_txt,
|
||||
now_rr,
|
||||
locked_r,
|
||||
new_sl,
|
||||
)
|
||||
if ok_live:
|
||||
be_msg += "\n- 交易所:已先撤后挂止盈止损"
|
||||
send_wechat_msg(be_msg)
|
||||
breakeven_armed = 1
|
||||
if not was_armed:
|
||||
arm_txt = "保本止盈"
|
||||
be_msg = build_wechat_breakeven_message(
|
||||
sym,
|
||||
direction,
|
||||
arm_txt,
|
||||
now_rr,
|
||||
locked_r,
|
||||
new_sl,
|
||||
)
|
||||
if ok_live:
|
||||
be_msg += "\n- 交易所:已先撤后挂止盈止损"
|
||||
send_wechat_msg(be_msg)
|
||||
|
||||
res = None
|
||||
# 做多
|
||||
@@ -6198,14 +6241,26 @@ def add_order():
|
||||
|
||||
_, trading_capital_after = get_exchange_capitals(force=True)
|
||||
account_base_display = (
|
||||
round(float(trading_capital_after), 4)
|
||||
round(float(trading_capital_after), 2)
|
||||
if trading_capital_after is not None
|
||||
else round(float(capital_base), 4)
|
||||
else round(float(capital_base), 2)
|
||||
)
|
||||
account_name = (os.getenv("OKX_ACCOUNT_LABEL") or "okx实盘子账户").strip()
|
||||
dir_text = "多头(long)" if direction == "long" else "空头(short)"
|
||||
order_state_text = "交易所止盈止损已挂单" if tpsl_attached else "未挂单(已拦截)"
|
||||
order_state_text = (
|
||||
"已在交易所挂条件委托(止盈、止损各一张触发单)"
|
||||
if tpsl_attached
|
||||
else "条件委托未挂上(已拦截)"
|
||||
)
|
||||
rr_show = planned_rr if planned_rr is not None else "-"
|
||||
try:
|
||||
rr_show_fmt = f"{float(planned_rr):.2f}" if planned_rr is not None else None
|
||||
except (TypeError, ValueError):
|
||||
rr_show_fmt = None
|
||||
rr_line = f"RR {rr_show_fmt} : 1" if rr_show_fmt is not None else f"RR {rr_show} : 1"
|
||||
ep_wx = format_price_for_symbol(symbol, trigger_price)
|
||||
sl_wx = format_wechat_scalar_2dp(stop_loss)
|
||||
tp_wx = format_price_for_symbol(symbol, take_profit)
|
||||
be_wx = format_price_for_symbol(symbol, breakeven_price)
|
||||
style_zh = "Swing 波段" if trade_style == "swing" else "Trend 趋势"
|
||||
wx_lines = [
|
||||
f"📈 {symbol} 开仓成功",
|
||||
@@ -6213,22 +6268,22 @@ def add_order():
|
||||
"🧾 订单基础信息",
|
||||
f"🔖 交易所订单 ID:{open_order_id}",
|
||||
f"📈 交易风格:{style_zh}",
|
||||
f"⚠️ 单笔风控风险:{risk_percent}% ≈ {round(float(risk_amount_final), 4)} U",
|
||||
f"⚠️ 单笔风控风险:{risk_percent}% ≈ {round(float(risk_amount_final), 2)} U",
|
||||
"📊 仓位配置详情",
|
||||
f"账户基数:{account_base_display} USDT",
|
||||
f"合约杠杆:{leverage} 倍",
|
||||
f"名义仓位:{notional_value} USDT",
|
||||
f"名义仓位:{format_wechat_scalar_2dp(notional_value)} USDT",
|
||||
f"仓位占比:{position_ratio}%",
|
||||
f"合约张数:{amount} 张",
|
||||
f"合约张数:{format_wechat_scalar_2dp(amount)} 张",
|
||||
f"折算标的:{base_amount} {journal_coin_from_symbol(symbol)}",
|
||||
"🎯 价位 & 盈亏比",
|
||||
f"开仓成交价:{trigger_price}",
|
||||
f"止损价位:{stop_loss}",
|
||||
f"止盈价位:{take_profit}",
|
||||
f"计划盈亏比:RR {rr_show} : 1",
|
||||
f"移动保本位:{breakeven_rr_trigger}R → {breakeven_price}",
|
||||
f"开仓成交价:{ep_wx}",
|
||||
f"止损价位:{sl_wx}",
|
||||
f"止盈价位:{tp_wx}",
|
||||
f"计划盈亏比:{rr_line}",
|
||||
f"移动保本位:{breakeven_rr_trigger}R → {be_wx}",
|
||||
"📌 状态统计",
|
||||
f"✅ 止盈止损:{order_state_text}",
|
||||
f"✅ 条件委托:{order_state_text}",
|
||||
f"📅 当日开仓次数:{opens_today_after} / {DAILY_OPEN_ALERT_THRESHOLD} 次(风控阈值提醒)",
|
||||
]
|
||||
if chart_url:
|
||||
@@ -6236,8 +6291,8 @@ def add_order():
|
||||
send_wechat_msg("\n".join(wx_lines))
|
||||
|
||||
flash_lines = [
|
||||
f"实盘开单成功:风格 {trade_style};风险 {risk_percent}%≈{risk_amount_final}U;基数 {margin_capital}U,杠杆 {leverage}x,名义仓位 {notional_value}U,仓位占比 {position_ratio}%,合约张数 {amount}(折算标的 {base_amount}),"
|
||||
f"计划RR {planned_rr if planned_rr is not None else '-'};止盈止损已挂交易所",
|
||||
f"实盘开单成功:风格 {trade_style};风险 {risk_percent}%≈{round(float(risk_amount_final), 2)}U;基数 {round(float(margin_capital), 2)}U,杠杆 {leverage}x,名义仓位 {format_wechat_scalar_2dp(notional_value)}U,仓位占比 {position_ratio}%,合约张数 {format_wechat_scalar_2dp(amount)}(折算标的 {base_amount}),"
|
||||
f"计划RR {format_wechat_scalar_2dp(planned_rr) if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
||||
f"本交易日累计开仓:{opens_today_after}",
|
||||
]
|
||||
if chart_url:
|
||||
|
||||
Reference in New Issue
Block a user