diff --git a/app.py b/app.py index 670e619..92051e8 100644 --- a/app.py +++ b/app.py @@ -5680,6 +5680,15 @@ def system_guide_page(): return render_main_page("system_guide") +@app.route("/live_guide") +@login_required +def live_guide_page(): + redir = redirect_to_embed_shell_if_enabled("live_guide") + if redir is not None: + return redir + return render_main_page("live_guide") + + @app.route("/env_config") @login_required def env_config_page(): diff --git a/docs/实盘说明.md b/docs/实盘说明.md new file mode 100644 index 0000000..39d4efa --- /dev/null +++ b/docs/实盘说明.md @@ -0,0 +1,84 @@ +# 交易所实盘说明(OKX) + +本页说明如何把本实例从模拟盘切到真实交易:API 权限、OKX 账户模式、以及实例 `.env` 关键项。币本位期权开仓会先用 USDT 买 ETH/BTC,再开期权,因此 **现货交易权限** 与 **合约模式** 缺一不可。 + +## 一、创建 OKX API Key + +1. 登录 OKX → **个人中心 → API** → 创建 API Key。 +2. 权限务必勾选 **交易(Trade)**。币本位开仓会走现货买币,只开合约/期权权限不够。 +3. 若有细分权限,请同时打开 **现货(Spot)**。 +4. 建议开启 **IP 白名单**,填入本实例服务器出口 IP。 +5. 保存后得到:`API Key` / `Secret Key` / `Passphrase`,填入本实例 env(见下文)。 + +常见报错: + +| 现象 | 原因 | 处理 | +| --- | --- | --- | +| `50123` This API Key does not have trading permission for the Crypto | Key 无现货/交易权限 | 编辑 Key,勾选交易与现货后重试 | +| `未授权` / Bridge 探测失败 | 中控 Token 或客户端未部署接口 | 核对实例 Bridge Token;客户端需已部署 `/api/hub/version` | + +## 二、OKX 账户模式 + +交易页 → **账户模式**(首次切换须在网页/App 手动确认)。 + +| 账户模式 | 是否推荐 | 说明 | +| --- | --- | --- | +| 仅现货 / 简单模式 | 否 | 无法正常开期权 | +| **合约模式(现货和合约)** | **推荐** | 现货用 `cash`,与当前程序一致 | +| 跨币种保证金 | 可用但不推荐 | 现货须 `cross`,程序目前按合约模式写 `cash`,会报 `tdMode` 错 | +| 组合保证金 | 可用但不推荐 | 同上,现货也须 `cross` | + +推荐流程:先切到 **合约模式** → 再在本实例点「买币并开仓」。 + +相关报错: + +| 现象 | 原因 | 处理 | +| --- | --- | --- | +| You can't complete this request under your current account mode (`51010`) | 账户模式不支持本次下单 | 改为合约模式 | +| Parameter tdMode error | 跨币种/组合下仍用 `cash` 下现货 | 改回合约模式,或等待程序支持按模式自动选 `tdMode` | + +## 三、实例 env 配置 + +在顶栏 **env配置**(或改服务器 `.env` 后重启)中设置: + +### 1. 实盘开关与密钥 + +- `LIVE_TRADING_ENABLED=true`:允许实盘下单。 +- `OKX_API_KEY` / `OKX_API_SECRET` / `OKX_API_PASSPHRASE`:上一步创建的密钥(期权与永续共用,不必单独配期权 Key)。 +- `SIM_DEFAULT_MODE=live`:运行模式切到实盘(顶栏显示 `okx_live`)。也可在运行时由系统把 `trading.mode` 写成 `live`。 + +切到实盘后: + +- 顶栏「交易账户 / 总资金」只显示交易所真实余额;未充值时应为 `—` 或 `0`,不会再残留模拟盘数字。 +- 模拟钱包余额不会带到实盘。 + +### 2. 期权相关(币本位) + +- `OKX_OPTIONS_ENABLED=true`:启用期权模块。 +- `OKX_OPTIONS_MARGIN_MODE=coin`:币本位(用 ETH/BTC 付权利金)。 +- `OKX_OPTIONS_MAX_ACTIVE_POSITIONS`:期权持仓上限(笔);`0`=不限制;`1`=同时最多 1 个合约(同合约加仓不占新笔数)。 +- `OKX_OPTIONS_SPOT_BUY_BUFFER`:现货买入相对权利金的缓冲倍数(如 `1.05`)。 +- 目标平仓门控:`OKX_OPTIONS_CLOSE_GATE_MODE`、`OKX_OPTIONS_CLOSE_RECYCLE_MULT_COIN`、`OKX_OPTIONS_CLOSE_HOLD_SECONDS` 等(见 env 页「期权账户」分组)。 + +保存后按提示 **保存并重启**(或 PM2 重启),再刷新页面确认顶栏为 `okx_live`。 + +## 四、开仓前自检清单 + +1. OKX 账户模式 = **合约模式**。 +2. API Key 有 **交易 + 现货**,IP 白名单正确。 +3. `.env`:`LIVE_TRADING_ENABLED=true`,密钥已填,模式为 `live`。 +4. 交易账户有足够 **USDT**(买币)以及开期权所需的标的币/保证金。 +5. 期权持仓上限、全仓复利等规则符合预期。 + +## 五、翻倍离场与指数离场(实盘同样生效) + +后台监控轮询实盘持仓,达标后按买一限价平仓: + +- **翻倍离场**:买一可回收 ≥ 开仓权利金 × (1 + 倍数) 时平仓。 +- **指数离场**:标的指数到位后触发,但仍须通过「目标平仓门控」(权利金倍数持续若干秒等)。 + +开仓时勾选/填写对应出场条件,并保证实例进程在跑。 + +## 六、中控远程更新注意 + +中控「系统更新 → 客户端远程更新」依赖实例的 `/api/hub/version` 与 `/api/hub/update`。若版本列报「非 JSON / 404」,请先在该实例服务器手动 `git pull` 并重启一次,再在中控刷新版本。 diff --git a/lib/common/static/instance_embed.js b/lib/common/static/instance_embed.js index f8ae3ad..d6fd85e 100644 --- a/lib/common/static/instance_embed.js +++ b/lib/common/static/instance_embed.js @@ -16,6 +16,7 @@ records: "/records", stats: "/stats", risk_policy: "/risk_policy", + live_guide: "/live_guide", system_guide: "/system_guide", env_config: "/env_config", settings: "/settings", @@ -361,6 +362,7 @@ const hideTopBar = tab === "settings" || tab === "risk_policy" || + tab === "live_guide" || tab === "system_guide" || tab === "env_config" || tab === "options_review"; diff --git a/lib/common/static/instance_mobile_nav.js b/lib/common/static/instance_mobile_nav.js index 4402a89..6f7c5fb 100644 --- a/lib/common/static/instance_mobile_nav.js +++ b/lib/common/static/instance_mobile_nav.js @@ -102,6 +102,7 @@ records: "/records", stats: "/stats", risk_policy: "/risk_policy", + live_guide: "/live_guide", system_guide: "/system_guide", env_config: "/env_config", settings: "/settings", diff --git a/lib/common/static/instance_settings_prefs.js b/lib/common/static/instance_settings_prefs.js index ecc4eb3..8d61b39 100644 --- a/lib/common/static/instance_settings_prefs.js +++ b/lib/common/static/instance_settings_prefs.js @@ -47,6 +47,7 @@ "options-review": "show_nav_options_review", options_review: "show_nav_options_review", risk_policy: "show_nav_risk_policy", + live_guide: "show_nav_live_guide", system_guide: "show_nav_system_guide", env_config: "show_nav_env_config", }; @@ -87,6 +88,7 @@ "options-review": "show_nav_options_review", options_review: "show_nav_options_review", risk_policy: "show_nav_risk_policy", + live_guide: "show_nav_live_guide", system_guide: "show_nav_system_guide", env_config: "show_nav_env_config", }; diff --git a/lib/instance/instance_display_prefs_lib.py b/lib/instance/instance_display_prefs_lib.py index 2976f36..f310ad8 100644 --- a/lib/instance/instance_display_prefs_lib.py +++ b/lib/instance/instance_display_prefs_lib.py @@ -17,6 +17,7 @@ DEFAULT_INSTANCE_DISPLAY: dict[str, bool] = { "show_nav_records": False, # 永续交易记录与复盘已移除 "show_nav_stats": False, "show_nav_risk_policy": True, + "show_nav_live_guide": True, "show_nav_system_guide": False, "show_nav_env_config": True, "show_nav_options": True, @@ -38,6 +39,7 @@ DISPLAY_LABELS: dict[str, str] = { "show_nav_records": "交易记录与复盘", "show_nav_stats": "统计分析", "show_nav_risk_policy": "风控说明", + "show_nav_live_guide": "实盘说明", "show_nav_system_guide": "系统说明", "show_nav_env_config": "env配置", "show_nav_options": "期权", @@ -59,6 +61,7 @@ NAV_TAB_ALLOWED: dict[str, str] = { "records": "show_nav_records", "stats": "show_nav_stats", "risk_policy": "show_nav_risk_policy", + "live_guide": "show_nav_live_guide", "system_guide": "show_nav_system_guide", "env_config": "show_nav_env_config", "options": "show_nav_options", @@ -122,6 +125,7 @@ def display_meta_for_ui() -> list[dict[str, Any]]: "show_nav_account_ledger", "show_nav_key_monitor", "show_nav_risk_policy", + "show_nav_live_guide", "show_nav_system_guide", "show_nav_env_config", "show_nav_options", diff --git a/lib/instance/instance_embed_lib.py b/lib/instance/instance_embed_lib.py index 29ab729..1bcc624 100644 --- a/lib/instance/instance_embed_lib.py +++ b/lib/instance/instance_embed_lib.py @@ -17,6 +17,7 @@ EMBED_TABS: tuple[str, ...] = ( "options", "options_review", "risk_policy", + "live_guide", "system_guide", "env_config", "settings", @@ -34,6 +35,7 @@ PATH_TO_EMBED_TAB: dict[str, str] = { "/options/review": "options_review", "/hedge-plan": "options", # 对冲计划已移除,旧链接落到期权 "/risk_policy": "risk_policy", + "/live_guide": "live_guide", "/system_guide": "system_guide", "/env_config": "env_config", "/settings": "settings", diff --git a/lib/instance/instance_live_guide_lib.py b/lib/instance/instance_live_guide_lib.py new file mode 100644 index 0000000..83b83f6 --- /dev/null +++ b/lib/instance/instance_live_guide_lib.py @@ -0,0 +1,68 @@ +"""实例「实盘说明」:加载 Markdown,生成 h2 目录与带锚点正文.""" +from __future__ import annotations + +import re +from functools import lru_cache +from html import escape +from pathlib import Path +from typing import Any + +from lib.common.markdown_html_lib import render_markdown_html +from lib.paths import REPO_ROOT + + +def live_guide_md_path() -> Path: + return REPO_ROOT / "docs" / "实盘说明.md" + + +def _slugify(text: str) -> str: + raw = re.sub(r"<[^>]+>", "", text or "") + raw = re.sub(r"\s+", "-", raw.strip()) + raw = re.sub(r"[^\w\u4e00-\u9fff\-]+", "", raw) + return raw[:80] or "section" + + +def _inject_h2_ids(html: str) -> tuple[str, list[dict[str, str]]]: + toc: list[dict[str, str]] = [] + used: dict[str, int] = {} + + def repl(m: re.Match[str]) -> str: + inner = m.group(1) + base = _slugify(inner) + n = used.get(base, 0) + 1 + used[base] = n + hid = base if n == 1 else f"{base}-{n}" + toc.append({"id": hid, "title": re.sub(r"<[^>]+>", "", inner).strip()}) + return f'
OKX API、账户模式与实例 env。可在系统设置 → 导航显示中关闭顶栏入口。
+