Collapse field hints into a default-folded 规则说明 on strategy and runtime settings.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+105
-41
@@ -1,4 +1,4 @@
|
||||
import { FormEvent, useEffect, useState } from "react";
|
||||
import { FormEvent, ReactNode, useEffect, useState } from "react";
|
||||
import {
|
||||
changeCredentials,
|
||||
getUsername,
|
||||
@@ -15,9 +15,38 @@ type StratSub =
|
||||
| "exit"
|
||||
| "pace";
|
||||
|
||||
function RulesFold({
|
||||
open,
|
||||
onToggle,
|
||||
children,
|
||||
}: {
|
||||
open: boolean;
|
||||
onToggle: () => void;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div className={`settings-rules ${open ? "open" : ""}`}>
|
||||
<button
|
||||
type="button"
|
||||
className="settings-rules-toggle"
|
||||
aria-expanded={open}
|
||||
onClick={onToggle}
|
||||
>
|
||||
<span>规则说明</span>
|
||||
<span className="settings-rules-chevron" aria-hidden>
|
||||
{open ? "▾" : "▸"}
|
||||
</span>
|
||||
</button>
|
||||
{open ? <div className="settings-rules-body">{children}</div> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SettingsPage() {
|
||||
const [tab, setTab] = useState<Tab>("strategy");
|
||||
const [stratSub, setStratSub] = useState<StratSub>("position");
|
||||
const [stratRulesOpen, setStratRulesOpen] = useState(false);
|
||||
const [runtimeRulesOpen, setRuntimeRulesOpen] = useState(false);
|
||||
|
||||
const [newUsername, setNewUsername] = useState(getUsername() || "admin");
|
||||
const [currentPassword, setCurrentPassword] = useState("");
|
||||
@@ -247,11 +276,6 @@ export default function SettingsPage() {
|
||||
|
||||
{tab === "strategy" ? (
|
||||
<div className="card settings-card">
|
||||
<p className="settings-lead">
|
||||
{(runtime?.mode ?? mode) === "LIVE"
|
||||
? "当前 LIVE:仓位/选约/出场影响真下单;模拟资金已隐藏。"
|
||||
: "当前 SIM:本地撮合;可改模拟资金与交易所行情源。"}
|
||||
</p>
|
||||
{stratOk ? <div className="settings-ok">{stratOk}</div> : null}
|
||||
{err && tab === "strategy" ? <div className="err">{err}</div> : null}
|
||||
|
||||
@@ -301,9 +325,6 @@ export default function SettingsPage() {
|
||||
币安(USDT 永续 + 欧洲期权)
|
||||
</option>
|
||||
</select>
|
||||
<p className="settings-hint">
|
||||
有持仓时不可切换。切换后套用该所合约并重连行情。
|
||||
</p>
|
||||
</div>
|
||||
{(runtime?.mode ?? mode) !== "LIVE" ? (
|
||||
<div className="field">
|
||||
@@ -319,9 +340,6 @@ export default function SettingsPage() {
|
||||
setInitialEquity(Number(e.target.value))
|
||||
}
|
||||
/>
|
||||
<p className="settings-hint">
|
||||
仅 SIM 显示。保存后重置权益(须无持仓)。默认 10000。
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="field">
|
||||
@@ -405,9 +423,6 @@ export default function SettingsPage() {
|
||||
<option value="0">关闭(默认)</option>
|
||||
<option value="1">开启</option>
|
||||
</select>
|
||||
<p className="settings-hint">
|
||||
关闭时不限制 |ATM − 现价|;开启后超过下方点数则不开仓。
|
||||
</p>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="atmoff">开仓 ATM 最大偏差(点)</label>
|
||||
@@ -421,9 +436,6 @@ export default function SettingsPage() {
|
||||
value={maxAtmOff}
|
||||
onChange={(e) => setMaxAtmOff(Number(e.target.value))}
|
||||
/>
|
||||
<p className="settings-hint">
|
||||
仅开关开启时生效。币安行权价较粗时可能长时间无开仓机会。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -491,9 +503,6 @@ export default function SettingsPage() {
|
||||
value={closeDevPct}
|
||||
onChange={(e) => setCloseDevPct(Number(e.target.value))}
|
||||
/>
|
||||
<p className="settings-hint">
|
||||
主要用于 SIM 流动性闸门;LIVE 以交易所能否成交为准。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -530,9 +539,6 @@ export default function SettingsPage() {
|
||||
setOrderInterval(Number(e.target.value))
|
||||
}
|
||||
/>
|
||||
<p className="settings-hint">
|
||||
LIVE 私有下单/查单间隔,默认 1s。范围 0.2–30。
|
||||
</p>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="skipWe">周六日跳过开仓(上海时区)</label>
|
||||
@@ -561,6 +567,53 @@ export default function SettingsPage() {
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
<RulesFold
|
||||
open={stratRulesOpen}
|
||||
onToggle={() => setStratRulesOpen((v) => !v)}
|
||||
>
|
||||
<ul className="settings-rules-list">
|
||||
<li>
|
||||
{(runtime?.mode ?? mode) === "LIVE"
|
||||
? "当前 LIVE:仓位/选约/出场影响真下单;模拟资金已隐藏。"
|
||||
: "当前 SIM:本地撮合;可改模拟资金与交易所行情源。"}
|
||||
</li>
|
||||
{stratSub === "position" ? (
|
||||
<>
|
||||
<li>交易所:有持仓时不可切换。切换后套用该所合约并重连行情。</li>
|
||||
{(runtime?.mode ?? mode) !== "LIVE" ? (
|
||||
<li>
|
||||
模拟资金:仅 SIM 显示。保存后重置权益(须无持仓)。默认
|
||||
10000。
|
||||
</li>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
{stratSub === "select" ? (
|
||||
<>
|
||||
<li>
|
||||
开仓 ATM 偏差限制:关闭时不限制 |ATM −
|
||||
现价|;开启后超过下方点数则不开仓。
|
||||
</li>
|
||||
<li>
|
||||
开仓 ATM 最大偏差:仅开关开启时生效。币安行权价较粗时可能长时间无开仓机会。
|
||||
</li>
|
||||
</>
|
||||
) : null}
|
||||
{stratSub === "exit" ? (
|
||||
<li>
|
||||
平仓买一/标记最大偏差:主要用于 SIM
|
||||
流动性闸门;LIVE 以交易所能否成交为准。
|
||||
</li>
|
||||
) : null}
|
||||
{stratSub === "pace" ? (
|
||||
<li>
|
||||
实盘下单最小间隔:LIVE 私有下单/查单间隔,默认 1s。范围
|
||||
0.2–30。
|
||||
</li>
|
||||
) : null}
|
||||
</ul>
|
||||
</RulesFold>
|
||||
|
||||
<div className="settings-actions">
|
||||
<button className="btn" type="submit">
|
||||
保存策略
|
||||
@@ -572,10 +625,6 @@ export default function SettingsPage() {
|
||||
|
||||
{tab === "runtime" ? (
|
||||
<div className="card settings-card">
|
||||
<p className="settings-lead">
|
||||
SIM = 本地撮合;LIVE = 当前所选交易所真下单(OKX / 币安均已接入)。密钥只写入服务器{" "}
|
||||
<span className="mono">.env</span>,接口不回传明文。OKX 期权常需账户有 USDC;币安多为 USDT。
|
||||
</p>
|
||||
{runtimeOk ? <div className="settings-ok">{runtimeOk}</div> : null}
|
||||
{err && tab === "runtime" ? <div className="err">{err}</div> : null}
|
||||
<form onSubmit={onSaveRuntime}>
|
||||
@@ -595,15 +644,6 @@ export default function SettingsPage() {
|
||||
<option value="SIM">SIM 本地模拟</option>
|
||||
<option value="LIVE">LIVE 实盘</option>
|
||||
</select>
|
||||
<p className="settings-hint">
|
||||
当前:{runtime?.mode || "—"} · 交易所 {runtime?.exchange || "—"} ·{" "}
|
||||
{runtime?.mode === "LIVE"
|
||||
? runtime.live_ready
|
||||
? "LIVE 就绪"
|
||||
: `未就绪(${runtime.live_ready_reason})`
|
||||
: "SIM"}
|
||||
。有持仓时不可切换模式。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -697,13 +737,37 @@ export default function SettingsPage() {
|
||||
onChange={(e) => setBnSecret(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<p className="settings-hint">
|
||||
留空保存=不覆盖已有密钥。交易所选币安且 LIVE 时用此密钥真下单(无
|
||||
Passphrase)。
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<RulesFold
|
||||
open={runtimeRulesOpen}
|
||||
onToggle={() => setRuntimeRulesOpen((v) => !v)}
|
||||
>
|
||||
<ul className="settings-rules-list">
|
||||
<li>
|
||||
SIM = 本地撮合;LIVE =
|
||||
当前所选交易所真下单(OKX / 币安均已接入)。密钥只写入服务器{" "}
|
||||
<span className="mono">.env</span>
|
||||
,接口不回传明文。OKX 期权常需账户有 USDC;币安多为 USDT。
|
||||
</li>
|
||||
<li>
|
||||
当前:{runtime?.mode || "—"} · 交易所{" "}
|
||||
{runtime?.exchange || "—"} ·{" "}
|
||||
{runtime?.mode === "LIVE"
|
||||
? runtime.live_ready
|
||||
? "LIVE 就绪"
|
||||
: `未就绪(${runtime.live_ready_reason})`
|
||||
: "SIM"}
|
||||
。有持仓时不可切换模式。
|
||||
</li>
|
||||
<li>
|
||||
密钥留空保存 = 不覆盖已有配置。交易所选币安且 LIVE
|
||||
时用币安密钥真下单(无 Passphrase)。
|
||||
</li>
|
||||
</ul>
|
||||
</RulesFold>
|
||||
|
||||
<div className="settings-actions">
|
||||
<button className="btn" type="submit" disabled={loading}>
|
||||
{loading ? "保存中…" : "保存模式与密钥"}
|
||||
|
||||
@@ -472,6 +472,60 @@ input {
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.settings-rules {
|
||||
margin: 4px 0 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: var(--input);
|
||||
}
|
||||
|
||||
.settings-rules-toggle {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
padding: 10px 12px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.settings-rules-toggle:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.settings-rules.open .settings-rules-toggle {
|
||||
color: var(--text);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.settings-rules-chevron {
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.settings-rules-body {
|
||||
padding: 10px 12px 12px;
|
||||
}
|
||||
|
||||
.settings-rules-list {
|
||||
margin: 0;
|
||||
padding-left: 18px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.settings-rules-list li + li {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.settings-actions {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user