修复okx

This commit is contained in:
dekun
2026-05-25 07:21:29 +08:00
parent 1a21295646
commit 80cc26ef27
3 changed files with 299 additions and 172 deletions
+91 -6
View File
@@ -143,6 +143,7 @@ TRADING_DAY_RESET_HOUR = int(os.getenv("TRADING_DAY_RESET_HOUR", "8"))
TRADING_DAY_RESET_OPEN_GUARD_ENABLED = os.getenv(
"TRADING_DAY_RESET_OPEN_GUARD_ENABLED", "true"
).lower() in ("1", "true", "yes", "on")
RUNTIME_KEY_OPEN_GUARD = "trading_day_reset_open_guard_enabled"
APP_TIMEZONE = os.getenv("APP_TIMEZONE", "Asia/Shanghai")
@@ -1064,6 +1065,11 @@ def init_db():
(id INTEGER PRIMARY KEY AUTOINCREMENT, transfer_type TEXT, transfer_day TEXT,
amount REAL, from_account TEXT, to_account TEXT, status TEXT, message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
c.execute(
"""CREATE TABLE IF NOT EXISTS app_runtime_settings
(key TEXT PRIMARY KEY, value TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"""
)
c.execute('''DROP INDEX IF EXISTS idx_transfer_logs_unique_day''')
c.execute('''CREATE UNIQUE INDEX IF NOT EXISTS idx_transfer_logs_auto_daily_unique
ON transfer_logs(transfer_type, transfer_day)
@@ -2233,8 +2239,45 @@ def auto_transfer_once_per_day():
)
def trading_day_reset_allows_new_open(now):
if not TRADING_DAY_RESET_OPEN_GUARD_ENABLED:
def get_trading_day_reset_open_guard_enabled(conn=None):
"""True=启用整点限制(默认 8:00 前禁止新开仓/登记监控)。"""
owns = conn is None
if owns:
conn = get_db()
try:
row = conn.execute(
"SELECT value FROM app_runtime_settings WHERE key=?",
(RUNTIME_KEY_OPEN_GUARD,),
).fetchone()
if row is not None:
return str(row[0]).lower() in ("1", "true", "yes", "on")
except Exception:
pass
finally:
if owns:
conn.close()
return TRADING_DAY_RESET_OPEN_GUARD_ENABLED
def set_trading_day_reset_open_guard_enabled(enabled: bool, conn=None):
owns = conn is None
if owns:
conn = get_db()
try:
conn.execute(
"INSERT INTO app_runtime_settings(key, value, updated_at) VALUES (?,?,?) "
"ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at",
(RUNTIME_KEY_OPEN_GUARD, "1" if enabled else "0", app_now_str()),
)
if owns:
conn.commit()
finally:
if owns:
conn.close()
def trading_day_reset_allows_new_open(now, conn=None):
if not get_trading_day_reset_open_guard_enabled(conn):
return True
return now.hour >= TRADING_DAY_RESET_HOUR
@@ -3821,33 +3864,39 @@ def _finalize_fib_key_fill(conn, row):
live_amt = get_live_position_contracts(ex_sym, direction)
amount = float(live_amt or 0)
if amount <= 0:
send_wechat_msg(
msg = (
f"# ❌ {symbol} 斐波成交后处理失败\n"
f"**账户:{_wechat_account_label()}**\n"
f"- 无法取得持仓/下单数量,未挂 TP/SL\n"
)
send_wechat_msg(msg)
_finalize_key_monitor_one_shot(conn, row, msg, "fib_fill_no_amount")
return
ok, reason = precheck_risk(conn, symbol, direction)
if not ok:
send_wechat_msg(
msg = (
f"# ❌ {symbol} 斐波成交后风控拒绝\n"
f"**账户:{_wechat_account_label()}**\n"
f"- 类型:{typ}\n"
f"- 原因:{reason}\n"
f"- 请手动处理仓位与挂单\n"
)
send_wechat_msg(msg)
_finalize_key_monitor_one_shot(conn, row, msg, "fib_risk_rejected")
return
tpsl_attached = False
try:
_okx_place_tp_sl_orders(ex_sym, direction, amount, sl, tp)
tpsl_attached = True
except Exception as e:
send_wechat_msg(
msg = (
f"# ❌ {symbol} 斐波成交后挂 TP/SL 失败\n"
f"**账户:{_wechat_account_label()}**\n"
f"- 错误:{friendly_okx_error(e)}\n"
f"- 请手动补挂止盈止损\n"
)
send_wechat_msg(msg)
_finalize_key_monitor_one_shot(conn, row, msg, "fib_tpsl_failed")
return
contract_size = get_contract_size(ex_sym)
base_amount = round(float(amount) * contract_size, 8)
@@ -4624,7 +4673,9 @@ def render_main_page(page="trade"):
)
rate = round(win/total*100,2) if total else 0
active_count = len(order_list)
can_trade = trading_day_reset_allows_new_open(now) and active_count < MAX_ACTIVE_POSITIONS
open_guard_enabled = get_trading_day_reset_open_guard_enabled(conn)
open_guard_blocks_now = open_guard_enabled and now.hour < TRADING_DAY_RESET_HOUR
can_trade = trading_day_reset_allows_new_open(now, conn) and active_count < MAX_ACTIVE_POSITIONS
key_gate_rule_text = (
f"【箱体/收敛】{KLINE_TIMEFRAME} 两根闭合K|突破越过关键位 > {KEY_BREAKOUT_AMP_MIN_PCT}%"
f"确认K收于箱外|量能>前{KEY_VOLUME_MA_BARS}均量×{KEY_VOLUME_RATIO_MIN}"
@@ -4661,6 +4712,8 @@ def render_main_page(page="trade"):
btc_leverage=BTC_LEVERAGE,
alt_leverage=ALT_LEVERAGE,
reset_hour=TRADING_DAY_RESET_HOUR,
open_guard_enabled=open_guard_enabled,
open_guard_blocks_now=open_guard_blocks_now,
balance_refresh_seconds=BALANCE_REFRESH_SECONDS,
auto_transfer_enabled=AUTO_TRANSFER_ENABLED,
auto_transfer_amount=AUTO_TRANSFER_AMOUNT,
@@ -4744,7 +4797,9 @@ def api_account_snapshot():
current_capital = round(trading_capital, FUNDS_DECIMALS) if trading_capital is not None else round(local_current_capital, FUNDS_DECIMALS)
recommended_capital = get_recommended_capital(current_capital)
active_count = get_active_position_count(conn)
open_guard_enabled = get_trading_day_reset_open_guard_enabled(conn)
conn.close()
open_guard_blocks_now = open_guard_enabled and now.hour < TRADING_DAY_RESET_HOUR
can_trade = trading_day_reset_allows_new_open(now) and active_count < MAX_ACTIVE_POSITIONS
available_trading_usdt = get_available_trading_usdt()
return jsonify({
@@ -4755,11 +4810,41 @@ def api_account_snapshot():
"active_count": active_count,
"max_active_positions": MAX_ACTIVE_POSITIONS,
"can_trade": can_trade,
"open_guard_enabled": open_guard_enabled,
"open_guard_blocks_now": open_guard_blocks_now,
"reset_hour": TRADING_DAY_RESET_HOUR,
"manual_min_planned_rr": MANUAL_MIN_PLANNED_RR,
"trading_day": trading_day,
})
@app.route("/api/settings/open_guard", methods=["POST"])
@login_required
def api_settings_open_guard():
data = request.get_json(silent=True) or {}
raw = data.get("enabled")
if raw is None:
raw = request.form.get("enabled")
if raw is None:
return jsonify({"ok": False, "msg": "缺少 enabled 参数"}), 400
enabled = str(raw).lower() in ("1", "true", "yes", "on")
set_trading_day_reset_open_guard_enabled(enabled)
now = app_now()
conn = get_db()
active_count = get_active_position_count(conn)
guard_on = get_trading_day_reset_open_guard_enabled(conn)
conn.close()
can_trade = trading_day_reset_allows_new_open(now) and active_count < MAX_ACTIVE_POSITIONS
return jsonify(
{
"ok": True,
"open_guard_enabled": guard_on,
"can_trade": can_trade,
"reset_hour": TRADING_DAY_RESET_HOUR,
}
)
@app.route("/api/price_snapshot")
@login_required
def api_price_snapshot():