Support LIVE exchange funds and perp margin mode.
Hide sim equity when LIVE is selected; OKX funds bar uses exchange balances; add cross/isolated for perp only (options stay cash). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -228,6 +228,7 @@ export type PlanState = {
|
||||
premium_exit_multiple: number;
|
||||
exit_target_usdt: number;
|
||||
leverage: number;
|
||||
perp_margin_mode?: "cross" | "isolated";
|
||||
perp_qty_eth?: number;
|
||||
option_qty_eth?: number;
|
||||
min_option_hours: number;
|
||||
@@ -311,6 +312,7 @@ export type StrategySettings = {
|
||||
skip_weekends?: boolean;
|
||||
initial_equity?: number;
|
||||
leverage?: number;
|
||||
perp_margin_mode?: "cross" | "isolated";
|
||||
min_option_hours?: number;
|
||||
min_option_leverage?: number;
|
||||
atm_open_offset_enabled?: boolean;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { apiFetch } from "../api/client";
|
||||
export type FundsSummary = {
|
||||
ok: boolean;
|
||||
exchange: string;
|
||||
mode?: string;
|
||||
trading_day: string;
|
||||
total_trades: number;
|
||||
win_rate: number;
|
||||
@@ -53,22 +54,42 @@ function DualCcy({
|
||||
|
||||
export default function FundsBar() {
|
||||
const [s, setS] = useState<FundsSummary | null>(null);
|
||||
const [err, setErr] = useState("");
|
||||
|
||||
const load = useCallback(() => {
|
||||
apiFetch<FundsSummary>("/api/funds/summary")
|
||||
.then(setS)
|
||||
.catch(() => {
|
||||
/* 顶栏静默失败,避免刷屏 */
|
||||
.then((r) => {
|
||||
setS(r);
|
||||
setErr(r.ok ? "" : r.detail || "资金摘要不可用");
|
||||
})
|
||||
.catch((e) => {
|
||||
setErr(e instanceof Error ? e.message : String(e));
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
const t = window.setInterval(load, 5000);
|
||||
return () => window.clearInterval(t);
|
||||
const onRefresh = () => load();
|
||||
window.addEventListener("funds-refresh", onRefresh);
|
||||
return () => {
|
||||
window.clearInterval(t);
|
||||
window.removeEventListener("funds-refresh", onRefresh);
|
||||
};
|
||||
}, [load]);
|
||||
|
||||
if (!s?.ok) return null;
|
||||
if (!s?.ok) {
|
||||
if (!err) return null;
|
||||
return (
|
||||
<div className="funds-bar-shell">
|
||||
<div className="funds-bar-inner">
|
||||
<div className="funds-bar funds-bar--err" aria-label="资金摘要异常">
|
||||
<span className="meta">{err}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="funds-bar-shell">
|
||||
|
||||
@@ -71,6 +71,9 @@ export default function SettingsPage() {
|
||||
const [orderInterval, setOrderInterval] = useState(1);
|
||||
const [skipWeekends, setSkipWeekends] = useState(true);
|
||||
const [leverage, setLeverage] = useState(3);
|
||||
const [perpMarginMode, setPerpMarginMode] = useState<"cross" | "isolated">(
|
||||
"cross",
|
||||
);
|
||||
const [minHours, setMinHours] = useState(12);
|
||||
const [minOptLev, setMinOptLev] = useState(100);
|
||||
const [atmOffOn, setAtmOffOn] = useState(false);
|
||||
@@ -157,6 +160,9 @@ export default function SettingsPage() {
|
||||
setOrderInterval(s.live_order_interval_sec ?? 1);
|
||||
setSkipWeekends(s.skip_weekends !== false);
|
||||
setLeverage(s.leverage ?? 3);
|
||||
setPerpMarginMode(
|
||||
s.perp_margin_mode === "isolated" ? "isolated" : "cross",
|
||||
);
|
||||
setMinHours(s.min_option_hours ?? 12);
|
||||
setMinOptLev(s.min_option_leverage ?? 100);
|
||||
setAtmOffOn(s.atm_open_offset_enabled === true);
|
||||
@@ -292,7 +298,7 @@ export default function SettingsPage() {
|
||||
e.preventDefault();
|
||||
setStratOk("");
|
||||
setErr("");
|
||||
const isLive = (runtime?.mode ?? mode) === "LIVE";
|
||||
const isLive = mode === "LIVE";
|
||||
try {
|
||||
const body: Record<string, unknown> = {
|
||||
fee_rate: fee,
|
||||
@@ -303,6 +309,7 @@ export default function SettingsPage() {
|
||||
live_order_interval_sec: orderInterval,
|
||||
skip_weekends: skipWeekends,
|
||||
leverage,
|
||||
perp_margin_mode: perpMarginMode,
|
||||
min_option_hours: minHours,
|
||||
min_option_leverage: minOptLev,
|
||||
atm_open_offset_enabled: atmOffOn,
|
||||
@@ -375,6 +382,7 @@ export default function SettingsPage() {
|
||||
: `已切 LIVE,但未就绪:${r.live_ready_reason}`
|
||||
: "已切换 SIM,配置已写入 .env",
|
||||
);
|
||||
window.dispatchEvent(new Event("funds-refresh"));
|
||||
} catch (ex) {
|
||||
setErr(ex instanceof Error ? ex.message : String(ex));
|
||||
} finally {
|
||||
@@ -531,7 +539,7 @@ export default function SettingsPage() {
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
{(runtime?.mode ?? mode) !== "LIVE" ? (
|
||||
{mode !== "LIVE" ? (
|
||||
<div className="field">
|
||||
<label htmlFor="equity">模拟资金(USDT)</label>
|
||||
<input
|
||||
@@ -559,6 +567,22 @@ export default function SettingsPage() {
|
||||
onChange={(e) => setLeverage(Number(e.target.value))}
|
||||
/>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="perpMm">永续保证金模式</label>
|
||||
<select
|
||||
id="perpMm"
|
||||
className="mono"
|
||||
value={perpMarginMode}
|
||||
onChange={(e) =>
|
||||
setPerpMarginMode(
|
||||
e.target.value === "isolated" ? "isolated" : "cross",
|
||||
)
|
||||
}
|
||||
>
|
||||
<option value="cross">全仓(默认)</option>
|
||||
<option value="isolated">逐仓</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label htmlFor="perp">永续 ETH 数量</label>
|
||||
<input
|
||||
@@ -822,19 +846,23 @@ export default function SettingsPage() {
|
||||
>
|
||||
<ul className="settings-rules-list">
|
||||
<li>
|
||||
{(runtime?.mode ?? mode) === "LIVE"
|
||||
{mode === "LIVE"
|
||||
? "当前 LIVE:仓位/选约/出场影响真下单;模拟资金已隐藏。"
|
||||
: "当前 SIM:本地撮合;可改模拟资金与交易所行情源。"}
|
||||
</li>
|
||||
{stratSub === "position" ? (
|
||||
<>
|
||||
<li>交易所:有持仓时不可切换。切换后套用该所合约并重连行情。</li>
|
||||
{(runtime?.mode ?? mode) !== "LIVE" ? (
|
||||
{mode !== "LIVE" ? (
|
||||
<li>
|
||||
模拟资金:仅 SIM 显示。保存后重置权益(须无持仓)。默认
|
||||
10000。
|
||||
</li>
|
||||
) : null}
|
||||
<li>
|
||||
永续保证金模式:仅作用于永续(全仓/逐仓,默认全仓)。OKX
|
||||
期权始终为现金/逐仓(cash),不受此选项影响。
|
||||
</li>
|
||||
</>
|
||||
) : null}
|
||||
{stratSub === "select" ? (
|
||||
@@ -1168,6 +1196,7 @@ export default function SettingsPage() {
|
||||
}),
|
||||
});
|
||||
setFundsOk("兑换成功,顶部资金条将刷新");
|
||||
window.dispatchEvent(new Event("funds-refresh"));
|
||||
} catch (e) {
|
||||
setFundsErr(e instanceof Error ? e.message : String(e));
|
||||
} finally {
|
||||
@@ -1257,6 +1286,7 @@ export default function SettingsPage() {
|
||||
}),
|
||||
});
|
||||
setFundsOk("划转成功,顶部资金条将刷新");
|
||||
window.dispatchEvent(new Event("funds-refresh"));
|
||||
} catch (e) {
|
||||
setFundsErr(e instanceof Error ? e.message : String(e));
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user