Show okx_sim/okx_live and gate live API fields by matching mode.

In sim, hide LIVE/API keys and expose simulated fund settings in env UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-14 18:35:08 +08:00
parent bd742a2e43
commit e7aa724a3b
9 changed files with 150 additions and 20 deletions
+3
View File
@@ -100,6 +100,9 @@ HOT_RELOAD_EXACT = frozenset({
"OKX_OPTIONS_BUDGET_BUFFER",
"OKX_TRADE_MODE",
"SIM_DEFAULT_MODE",
"SIM_INITIAL_EQUITY_USDT",
"SIM_INITIAL_USDC",
"SIM_FEE_RATE",
"MAX_ACTIVE_HEDGE_PLANS",
"HEDGE_PLAN_LIVE_ORDER",
"HEDGE_PLAN_OPTION_PRIMARY",
+69 -4
View File
@@ -17,12 +17,42 @@ from lib.env.env_schema import (
)
# 各所「交易所与实盘」字段(顺序即页面顺序)
_OKX_LIVE_ONLY_KEYS = frozenset(
{
"LIVE_TRADING_ENABLED",
"OKX_API_KEY",
"OKX_API_SECRET",
"OKX_API_PASSPHRASE",
}
)
_SIM_FUNDS_SECTION: dict[str, Any] = {
"title": "模拟资金",
"fields": [
(
"SIM_INITIAL_EQUITY_USDT",
"初始权益 USDT",
"重置模拟钱包时写入资金账户 USDT;改完需在系统设置「模拟资金」点重置才生效",
),
(
"SIM_INITIAL_USDC",
"初始 USDC",
"重置时写入期权侧 USDC;改完需重置才生效",
),
(
"SIM_FEE_RATE",
"模拟手续费率",
"如 0.0005=万五;撮合立即按此费率扣费",
),
],
}
_EXCHANGE_LIVE_FIELDS: dict[str, list[tuple[str, str, str]]] = {
"okx": [
(
"SIM_DEFAULT_MODE",
"撮合模式",
"sim=本地模拟资金(公开行情撮合,不下真实单); live=实盘账户.保存后立即切换",
"sim=本地模拟资金; live=实盘.保存后立即切换;sim 下隐藏 API/实盘开关",
),
("LIVE_TRADING_ENABLED", "开启实盘下单", "仅 live 模式下生效;关闭时即使 live 也不向交易所发单"),
("OKX_API_KEY", "API Key", "账户 API(永续+期权共用)"),
@@ -372,15 +402,41 @@ def _hedge_fields_for_mode(mode: str) -> list[tuple[str, str, str]]:
return []
def _trading_mode_for_env_ui() -> str:
try:
from lib.sim.mode_lib import peek_persisted_trading_mode, default_trading_mode
return peek_persisted_trading_mode() or default_trading_mode()
except Exception:
return "sim"
def _okx_exchange_fields_for_trading_mode(trading_mode: str) -> list[tuple[str, str, str]]:
fields = list(_EXCHANGE_LIVE_FIELDS["okx"])
tm = (trading_mode or "").strip().lower()
if tm == "sim":
return [f for f in fields if f[0] not in _OKX_LIVE_ONLY_KEYS]
return fields
def ui_sections_for_exchange(
exchange_key: str,
*,
mode: str | None = None,
trading_mode: str | None = None,
) -> list[dict[str, Any]]:
ex = (exchange_key or "").strip().lower()
sections: list[dict[str, Any]] = []
live_fields = _EXCHANGE_LIVE_FIELDS.get(ex, _EXCHANGE_LIVE_FIELDS["okx"])
tm = (trading_mode or "").strip().lower()
if not tm:
tm = _trading_mode_for_env_ui() if ex == "okx" else "live"
if ex == "okx":
live_fields = _okx_exchange_fields_for_trading_mode(tm)
else:
live_fields = _EXCHANGE_LIVE_FIELDS.get(ex, _EXCHANGE_LIVE_FIELDS["okx"])
sections.append({"title": "交易所与实盘", "fields": live_fields})
if ex == "okx" and tm == "sim":
sections.append(_SIM_FUNDS_SECTION)
sections.extend(_SHARED_SECTIONS)
if ex in _MODE_SECTION.get("exchanges", frozenset()):
from lib.hedge_plan.okx_trade_mode_lib import normalize_okx_trade_mode
@@ -406,7 +462,11 @@ def ui_allowed_keys(exchange_key: str) -> frozenset[str]:
ex = (exchange_key or "").strip().lower()
if ex == "okx":
keys.add("OKX_TRADE_MODE")
# 允许写入遗留键,避免旧自动化/手改失败;页面不再展示
keys.add("SIM_DEFAULT_MODE")
# 切模式后同请求可能带上对侧字段,始终放行
keys.update(_OKX_LIVE_ONLY_KEYS)
for item in _SIM_FUNDS_SECTION["fields"]:
keys.add(item[0])
for item in _HEDGE_PLAN_SECTION["fields"]:
keys.add(item[0])
for item in _OPTIONS_SECTION["fields"]:
@@ -422,9 +482,14 @@ def build_env_ui_payload(
schema = _schema_field_map(example_path)
env_lines = read_env_lines(env_path)
values = env_get_all(env_lines)
trading_mode = ""
if (exchange_key or "").strip().lower() == "okx":
trading_mode = _effective_env_value("SIM_DEFAULT_MODE", values, "sim") or _trading_mode_for_env_ui()
groups: list[dict[str, Any]] = []
for sec in ui_sections_for_exchange(
exchange_key, mode=values.get("OKX_TRADE_MODE") or ""
exchange_key,
mode=values.get("OKX_TRADE_MODE") or "",
trading_mode=trading_mode,
):
fields = [
_build_field(key, label, note, schema, values)