import { FormEvent, useEffect, useState } from "react"; import { changeCredentials, getUsername, setSession, apiFetch, StrategySettings, } from "../api/client"; type Tab = "strategy" | "account"; export default function SettingsPage() { const [tab, setTab] = useState("strategy"); const [newUsername, setNewUsername] = useState(getUsername() || "admin"); const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const [err, setErr] = useState(""); const [ok, setOk] = useState(""); const [loading, setLoading] = useState(false); const [fee, setFee] = useState(0.0005); const [exitMode, setExitMode] = useState<"fixed_usdt" | "premium_multiple">( "fixed_usdt", ); const [netTarget, setNetTarget] = useState(15); const [premMult, setPremMult] = useState(1); const [rest, setRest] = useState(300); const [skipWeekends, setSkipWeekends] = useState(true); const [leverage, setLeverage] = useState(3); const [minHours, setMinHours] = useState(12); const [minOptLev, setMinOptLev] = useState(100); const [closeDevPct, setCloseDevPct] = useState(30); const [perpQty, setPerpQty] = useState(1); const [optQty, setOptQty] = useState(2); const [initialEquity, setInitialEquity] = useState(10000); const [exchange, setExchange] = useState<"okx" | "binance">("okx"); const [stratOk, setStratOk] = useState(""); useEffect(() => { apiFetch("/api/settings/strategy") .then((s) => { setFee(s.fee_rate); setExitMode(s.exit_mode === "premium_multiple" ? "premium_multiple" : "fixed_usdt"); setNetTarget(s.net_profit_target ?? 15); setPremMult(s.premium_exit_multiple ?? 1); setRest(s.rest_seconds); setSkipWeekends(s.skip_weekends !== false); setLeverage(s.leverage ?? 3); setMinHours(s.min_option_hours ?? 12); setMinOptLev(s.min_option_leverage ?? 100); setCloseDevPct(s.close_bid_mark_max_pct ?? 30); setPerpQty(s.perp_qty_eth ?? 1); setOptQty(s.option_qty_eth ?? 2); setInitialEquity(s.initial_equity ?? 10000); setExchange(s.exchange === "binance" ? "binance" : "okx"); }) .catch(() => undefined); }, []); async function onSaveCreds(e: FormEvent) { e.preventDefault(); setErr(""); setOk(""); if (newPassword !== confirmPassword) { setErr("两次输入的新密码不一致"); return; } if (newPassword.length < 4) { setErr("新密码至少 4 位"); return; } setLoading(true); try { const res = await changeCredentials({ current_password: currentPassword, new_username: newUsername.trim(), new_password: newPassword, }); setSession(res.token, res.username); setCurrentPassword(""); setNewPassword(""); setConfirmPassword(""); setOk("用户名/密码已更新"); } catch (ex) { setErr(ex instanceof Error ? ex.message : String(ex)); } finally { setLoading(false); } } async function onSaveStrategy(e: FormEvent) { e.preventDefault(); setStratOk(""); setErr(""); try { await apiFetch("/api/settings/strategy", { method: "PUT", body: JSON.stringify({ fee_rate: fee, exit_mode: exitMode, net_profit_target: netTarget, premium_exit_multiple: premMult, rest_seconds: rest, skip_weekends: skipWeekends, leverage, min_option_hours: minHours, min_option_leverage: minOptLev, close_bid_mark_max_pct: closeDevPct, perp_qty_eth: perpQty, option_qty_eth: optQty, initial_equity: initialEquity, exchange, }), }); setStratOk( "策略参数已保存(切换交易所/改模拟资金需无持仓;切换后会重连行情)", ); } catch (ex) { setErr(ex instanceof Error ? ex.message : String(ex)); } } return (

系统设置

{tab === "strategy" ? (

无开仓时间窗;可切换 OKX / 币安行情(SIM 本地撮合);周六日可跳过开仓;出场按净盈利或到期全平。

{stratOk ?
{stratOk}
: null} {err && tab === "strategy" ?
{err}
: null}

交易所

有持仓时不可切换。切换后自动套用该所合约并重连公共行情。

资金

setInitialEquity(Number(e.target.value))} />

保存后将权益重置为该金额(须无持仓)。默认 10000。

setLeverage(Number(e.target.value))} />
setPerpQty(Number(e.target.value))} />
setOptQty(Number(e.target.value))} />

选约

setMinHours(Number(e.target.value))} />
setMinOptLev(Number(e.target.value))} />

出场与风控

{exitMode === "fixed_usdt" ? (
setNetTarget(Number(e.target.value))} />
) : (
setPremMult(Number(e.target.value))} />
)}
setCloseDevPct(Number(e.target.value))} />
setRest(Number(e.target.value))} />
setFee(Number(e.target.value))} />
) : (
{err ?
{err}
: null} {ok ?
{ok}
: null}
setNewUsername(e.target.value)} required />
setCurrentPassword(e.target.value)} required />
setNewPassword(e.target.value)} required />
setConfirmPassword(e.target.value)} required />
)}
); }