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:
@@ -115,9 +115,13 @@ async def funds_summary(_user: Annotated[str, Depends(require_user)]) -> dict[st
|
|||||||
trading_usdt = bal.get("trading_usdt")
|
trading_usdt = bal.get("trading_usdt")
|
||||||
funding_usdc = bal.get("funding_usdc")
|
funding_usdc = bal.get("funding_usdc")
|
||||||
trading_usdc = bal.get("trading_usdc")
|
trading_usdc = bal.get("trading_usdc")
|
||||||
parts = [funding_usdt, trading_usdt, funding_usdc, trading_usdc]
|
r = float(rate) if rate and rate > 0 else 1.0
|
||||||
vals = [float(x) for x in parts if x is not None]
|
total = round(
|
||||||
total = round(sum(vals), 2) if vals else None
|
(funding_usdt or 0.0)
|
||||||
|
+ (trading_usdt or 0.0)
|
||||||
|
+ ((funding_usdc or 0.0) + (trading_usdc or 0.0)) * r,
|
||||||
|
2,
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {
|
return {
|
||||||
"ok": False,
|
"ok": False,
|
||||||
@@ -128,11 +132,13 @@ async def funds_summary(_user: Annotated[str, Depends(require_user)]) -> dict[st
|
|||||||
finally:
|
finally:
|
||||||
client.close()
|
client.close()
|
||||||
else:
|
else:
|
||||||
# 非 OKX LIVE:回退本地账本
|
# 非 OKX LIVE:暂无统一资金接口,不回退模拟账本(避免实盘显示假资金)
|
||||||
led = Ledger(db).snapshot()
|
return {
|
||||||
trading_usdt = float(led["equity"])
|
"ok": False,
|
||||||
total = trading_usdt
|
"mode": mode,
|
||||||
|
"exchange": exchange,
|
||||||
|
"detail": f"{exchange} 实盘资金摘要暂未接入,请用 OKX 或交易所 App 查看",
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
"ok": True,
|
"ok": True,
|
||||||
"mode": mode,
|
"mode": mode,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ KEYS = (
|
|||||||
"skip_weekends",
|
"skip_weekends",
|
||||||
"initial_equity",
|
"initial_equity",
|
||||||
"leverage",
|
"leverage",
|
||||||
|
"perp_margin_mode",
|
||||||
"min_option_hours",
|
"min_option_hours",
|
||||||
"min_option_leverage",
|
"min_option_leverage",
|
||||||
"atm_open_offset_enabled",
|
"atm_open_offset_enabled",
|
||||||
@@ -61,6 +62,7 @@ class StrategySettingsBody(BaseModel):
|
|||||||
skip_weekends: bool | None = None
|
skip_weekends: bool | None = None
|
||||||
initial_equity: float | None = Field(default=None, ge=1000, le=10_000_000)
|
initial_equity: float | None = Field(default=None, ge=1000, le=10_000_000)
|
||||||
leverage: float | None = Field(default=None, ge=1, le=125)
|
leverage: float | None = Field(default=None, ge=1, le=125)
|
||||||
|
perp_margin_mode: str | None = Field(default=None, pattern="^(cross|isolated)$")
|
||||||
min_option_hours: float | None = Field(default=None, ge=1, le=720)
|
min_option_hours: float | None = Field(default=None, ge=1, le=720)
|
||||||
min_option_leverage: float | None = Field(default=None, ge=1, le=10000)
|
min_option_leverage: float | None = Field(default=None, ge=1, le=10000)
|
||||||
atm_open_offset_enabled: bool | None = None
|
atm_open_offset_enabled: bool | None = None
|
||||||
@@ -117,6 +119,20 @@ def _read_settings() -> dict:
|
|||||||
db.get_setting("initial_equity", str(s.initial_equity)) or s.initial_equity
|
db.get_setting("initial_equity", str(s.initial_equity)) or s.initial_equity
|
||||||
),
|
),
|
||||||
"leverage": float(db.get_setting("leverage", str(s.leverage)) or s.leverage),
|
"leverage": float(db.get_setting("leverage", str(s.leverage)) or s.leverage),
|
||||||
|
"perp_margin_mode": (
|
||||||
|
mm
|
||||||
|
if (
|
||||||
|
mm := str(
|
||||||
|
db.get_setting("perp_margin_mode", s.perp_margin_mode)
|
||||||
|
or s.perp_margin_mode
|
||||||
|
or "cross"
|
||||||
|
)
|
||||||
|
.strip()
|
||||||
|
.lower()
|
||||||
|
)
|
||||||
|
in ("cross", "isolated")
|
||||||
|
else "cross"
|
||||||
|
),
|
||||||
"min_option_hours": float(
|
"min_option_hours": float(
|
||||||
db.get_setting("min_option_hours", str(s.min_option_hours))
|
db.get_setting("min_option_hours", str(s.min_option_hours))
|
||||||
or s.min_option_hours
|
or s.min_option_hours
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ class Settings(BaseSettings):
|
|||||||
live_order_interval_sec: float = 1.0 # LIVE 私有下单/查单最小间隔(秒)
|
live_order_interval_sec: float = 1.0 # LIVE 私有下单/查单最小间隔(秒)
|
||||||
skip_weekends: bool = True # 上海时区周六日禁止新开仓(已有仓仍可平)
|
skip_weekends: bool = True # 上海时区周六日禁止新开仓(已有仓仍可平)
|
||||||
leverage: float = 3.0 # 永续杠杆
|
leverage: float = 3.0 # 永续杠杆
|
||||||
|
# 永续保证金模式:cross=全仓(默认)| isolated=逐仓;期权仍固定 cash(OKX 逐仓/现金)
|
||||||
|
perp_margin_mode: str = "cross"
|
||||||
min_option_hours: float = 12.0 # 期权最小剩余小时
|
min_option_hours: float = 12.0 # 期权最小剩余小时
|
||||||
min_option_leverage: float = 100.0 # 现价/卖一权利金 下限
|
min_option_leverage: float = 100.0 # 现价/卖一权利金 下限
|
||||||
atm_open_offset_enabled: bool = False # 开仓 ATM 偏差限制开关(默认关)
|
atm_open_offset_enabled: bool = False # 开仓 ATM 偏差限制开关(默认关)
|
||||||
|
|||||||
@@ -37,6 +37,16 @@ class OkxLiveExecutor(Matcher):
|
|||||||
self._trade = OkxTradeClient()
|
self._trade = OkxTradeClient()
|
||||||
return self._trade
|
return self._trade
|
||||||
|
|
||||||
|
def _perp_margin_mode(self) -> str:
|
||||||
|
"""永续全仓/逐仓;期权始终 cash,不受此设置影响。"""
|
||||||
|
s = get_settings()
|
||||||
|
raw = str(
|
||||||
|
self.ledger.get_setting_str("perp_margin_mode", s.perp_margin_mode)
|
||||||
|
or s.perp_margin_mode
|
||||||
|
or "cross"
|
||||||
|
).strip().lower()
|
||||||
|
return "isolated" if raw == "isolated" else "cross"
|
||||||
|
|
||||||
def _guard_live(self) -> str | None:
|
def _guard_live(self) -> str | None:
|
||||||
ok, reason = live_ready()
|
ok, reason = live_ready()
|
||||||
if not ok:
|
if not ok:
|
||||||
@@ -145,9 +155,10 @@ class OkxLiveExecutor(Matcher):
|
|||||||
else:
|
else:
|
||||||
side, pos_side = "sell", "short"
|
side, pos_side = "sell", "short"
|
||||||
leverage = self.ledger.get_setting_float("leverage", s.leverage)
|
leverage = self.ledger.get_setting_float("leverage", s.leverage)
|
||||||
|
mgn = self._perp_margin_mode()
|
||||||
try:
|
try:
|
||||||
client.set_leverage(
|
client.set_leverage(
|
||||||
perp_inst, leverage, mgn_mode="cross", pos_side=pos_side
|
perp_inst, leverage, mgn_mode=mgn, pos_side=pos_side
|
||||||
)
|
)
|
||||||
except Exception as e_lev:
|
except Exception as e_lev:
|
||||||
logger.warning("okx set_leverage failed: %s", e_lev)
|
logger.warning("okx set_leverage failed: %s", e_lev)
|
||||||
@@ -155,7 +166,7 @@ class OkxLiveExecutor(Matcher):
|
|||||||
inst_id=perp_inst,
|
inst_id=perp_inst,
|
||||||
side=side,
|
side=side,
|
||||||
sz=str(perp_sz),
|
sz=str(perp_sz),
|
||||||
td_mode="cross",
|
td_mode=mgn,
|
||||||
pos_side=pos_side,
|
pos_side=pos_side,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -642,7 +653,7 @@ class OkxLiveExecutor(Matcher):
|
|||||||
inst_id=perp_inst,
|
inst_id=perp_inst,
|
||||||
side=side,
|
side=side,
|
||||||
sz=str(perp_sz),
|
sz=str(perp_sz),
|
||||||
td_mode="cross",
|
td_mode=self._perp_margin_mode(),
|
||||||
pos_side=pos_side,
|
pos_side=pos_side,
|
||||||
reduce_only=True,
|
reduce_only=True,
|
||||||
)
|
)
|
||||||
@@ -927,7 +938,7 @@ class OkxLiveExecutor(Matcher):
|
|||||||
inst_id=perp_inst,
|
inst_id=perp_inst,
|
||||||
side=side,
|
side=side,
|
||||||
sz=str(perp_sz),
|
sz=str(perp_sz),
|
||||||
td_mode="cross",
|
td_mode=self._perp_margin_mode(),
|
||||||
pos_side=pos_side,
|
pos_side=pos_side,
|
||||||
reduce_only=True,
|
reduce_only=True,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ class Database:
|
|||||||
"skip_weekends": str(s.skip_weekends),
|
"skip_weekends": str(s.skip_weekends),
|
||||||
"max_rounds": str(s.max_rounds),
|
"max_rounds": str(s.max_rounds),
|
||||||
"leverage": str(s.leverage),
|
"leverage": str(s.leverage),
|
||||||
|
"perp_margin_mode": str(s.perp_margin_mode),
|
||||||
"min_option_hours": str(s.min_option_hours),
|
"min_option_hours": str(s.min_option_hours),
|
||||||
"min_option_leverage": str(s.min_option_leverage),
|
"min_option_leverage": str(s.min_option_leverage),
|
||||||
"atm_open_offset_enabled": str(s.atm_open_offset_enabled),
|
"atm_open_offset_enabled": str(s.atm_open_offset_enabled),
|
||||||
|
|||||||
@@ -83,6 +83,13 @@ class StrategyEngine:
|
|||||||
rest_sec = self.ledger.get_setting_int("rest_seconds", s.rest_seconds)
|
rest_sec = self.ledger.get_setting_int("rest_seconds", s.rest_seconds)
|
||||||
skip_weekends = self.ledger.get_setting_bool("skip_weekends", s.skip_weekends)
|
skip_weekends = self.ledger.get_setting_bool("skip_weekends", s.skip_weekends)
|
||||||
leverage = self.ledger.get_setting_float("leverage", s.leverage)
|
leverage = self.ledger.get_setting_float("leverage", s.leverage)
|
||||||
|
perp_mm = str(
|
||||||
|
self.ledger.get_setting_str("perp_margin_mode", s.perp_margin_mode)
|
||||||
|
or s.perp_margin_mode
|
||||||
|
or "cross"
|
||||||
|
).strip().lower()
|
||||||
|
if perp_mm not in ("cross", "isolated"):
|
||||||
|
perp_mm = "cross"
|
||||||
min_hours = self.ledger.get_setting_float("min_option_hours", s.min_option_hours)
|
min_hours = self.ledger.get_setting_float("min_option_hours", s.min_option_hours)
|
||||||
min_opt_lev = self.ledger.get_setting_float(
|
min_opt_lev = self.ledger.get_setting_float(
|
||||||
"min_option_leverage", s.min_option_leverage
|
"min_option_leverage", s.min_option_leverage
|
||||||
@@ -140,6 +147,7 @@ class StrategyEngine:
|
|||||||
"premium_exit_multiple": prem_mult,
|
"premium_exit_multiple": prem_mult,
|
||||||
"exit_target_usdt": exit_amt,
|
"exit_target_usdt": exit_amt,
|
||||||
"leverage": leverage,
|
"leverage": leverage,
|
||||||
|
"perp_margin_mode": perp_mm,
|
||||||
"perp_qty_eth": perp_qty,
|
"perp_qty_eth": perp_qty,
|
||||||
"option_qty_eth": opt_qty,
|
"option_qty_eth": opt_qty,
|
||||||
"min_option_hours": min_hours,
|
"min_option_hours": min_hours,
|
||||||
|
|||||||
+4
-2
@@ -32,10 +32,12 @@ ATM **期权买方** + **反向永续**;净利达标兑现,未达标拖到
|
|||||||
|
|
||||||
| 项 | 建议 |
|
| 项 | 建议 |
|
||||||
|----|------|
|
|----|------|
|
||||||
| 永续 | 全仓 `cross`;双向持仓(hedge)与软件 `posSide` 对齐 |
|
| 永续 | 设置页可选 **全仓 `cross`(默认)/ 逐仓 `isolated`**;双向持仓(hedge)与软件 `posSide` 对齐 |
|
||||||
| 期权 | **买卖模式 / cash**(买方付权利金);尽量 **逐仓/独立**,便于远虚残留不挡下一组 |
|
| 期权 | 固定 **cash**(买方付权利金),**不受**永续保证金模式选项影响 |
|
||||||
| API | Key + Secret + **Passphrase**;IP 白名单;交易权限最小化 |
|
| API | Key + Secret + **Passphrase**;IP 白名单;交易权限最小化 |
|
||||||
|
|
||||||
|
实盘顶部资金条(总资金 / 资金账户 / 交易账户)直接读 OKX;SIM 才显示本地模拟资金。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. 标准仓与缩放
|
## 3. 标准仓与缩放
|
||||||
|
|||||||
@@ -5,6 +5,16 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-29 — 实盘资金读交易所;永续全仓/逐仓
|
||||||
|
|
||||||
|
### 变更
|
||||||
|
|
||||||
|
1. 选择 LIVE 时立即隐藏「模拟资金」(跟表单模式,不必等保存后的 runtime)。
|
||||||
|
2. LIVE 资金条总资金/资金账户/交易账户读 OKX;总资金按 USDT 等值(USDC×汇率);划转/兑换后立即刷新顶栏。
|
||||||
|
3. 策略仓位增加「永续保证金模式」:全仓(默认)/ 逐仓;仅永续;OKX 期权仍固定 cash。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-07-29 — 顶栏名称/导航去背景
|
## 2026-07-29 — 顶栏名称/导航去背景
|
||||||
|
|
||||||
### 变更
|
### 变更
|
||||||
|
|||||||
+2
-1
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
**平仓顺序**:同样先平期权(买一薄)→ 再瞬时平永续。平期权期间永续对冲先留着;永续盘口失败则回滚期权入账。
|
**平仓顺序**:同样先平期权(买一薄)→ 再瞬时平永续。平期权期间永续对冲先留着;永续盘口失败则回滚期权入账。
|
||||||
|
|
||||||
永续杠杆默认 **3×**(可配)。同时最多 **1 组**仓,禁止叠仓开下一组。
|
永续杠杆默认 **3×**(可配)。永续保证金模式默认 **全仓**(可改逐仓);期权保证金模式固定买方现金/逐仓意图。同时最多 **1 组**仓,禁止叠仓开下一组。
|
||||||
|
|
||||||
### 2.1 开仓方向
|
### 2.1 开仓方向
|
||||||
|
|
||||||
@@ -331,6 +331,7 @@
|
|||||||
| `perp_qty_eth` | 1 | 仓位 |
|
| `perp_qty_eth` | 1 | 仓位 |
|
||||||
| `option_qty_eth` | 2 | 仓位 |
|
| `option_qty_eth` | 2 | 仓位 |
|
||||||
| `leverage` | 3 | 永续 |
|
| `leverage` | 3 | 永续 |
|
||||||
|
| `perp_margin_mode` | cross | 永续全仓/逐仓(期权不受影响) |
|
||||||
| `fee_rate` | 0.0005 | 成本 |
|
| `fee_rate` | 0.0005 | 成本 |
|
||||||
| `exit_mode` | fixed_usdt | 出场 |
|
| `exit_mode` | fixed_usdt | 出场 |
|
||||||
| `net_profit_target` | 15 | 出场 |
|
| `net_profit_target` | 15 | 出场 |
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ export type PlanState = {
|
|||||||
premium_exit_multiple: number;
|
premium_exit_multiple: number;
|
||||||
exit_target_usdt: number;
|
exit_target_usdt: number;
|
||||||
leverage: number;
|
leverage: number;
|
||||||
|
perp_margin_mode?: "cross" | "isolated";
|
||||||
perp_qty_eth?: number;
|
perp_qty_eth?: number;
|
||||||
option_qty_eth?: number;
|
option_qty_eth?: number;
|
||||||
min_option_hours: number;
|
min_option_hours: number;
|
||||||
@@ -311,6 +312,7 @@ export type StrategySettings = {
|
|||||||
skip_weekends?: boolean;
|
skip_weekends?: boolean;
|
||||||
initial_equity?: number;
|
initial_equity?: number;
|
||||||
leverage?: number;
|
leverage?: number;
|
||||||
|
perp_margin_mode?: "cross" | "isolated";
|
||||||
min_option_hours?: number;
|
min_option_hours?: number;
|
||||||
min_option_leverage?: number;
|
min_option_leverage?: number;
|
||||||
atm_open_offset_enabled?: boolean;
|
atm_open_offset_enabled?: boolean;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { apiFetch } from "../api/client";
|
|||||||
export type FundsSummary = {
|
export type FundsSummary = {
|
||||||
ok: boolean;
|
ok: boolean;
|
||||||
exchange: string;
|
exchange: string;
|
||||||
|
mode?: string;
|
||||||
trading_day: string;
|
trading_day: string;
|
||||||
total_trades: number;
|
total_trades: number;
|
||||||
win_rate: number;
|
win_rate: number;
|
||||||
@@ -53,22 +54,42 @@ function DualCcy({
|
|||||||
|
|
||||||
export default function FundsBar() {
|
export default function FundsBar() {
|
||||||
const [s, setS] = useState<FundsSummary | null>(null);
|
const [s, setS] = useState<FundsSummary | null>(null);
|
||||||
|
const [err, setErr] = useState("");
|
||||||
|
|
||||||
const load = useCallback(() => {
|
const load = useCallback(() => {
|
||||||
apiFetch<FundsSummary>("/api/funds/summary")
|
apiFetch<FundsSummary>("/api/funds/summary")
|
||||||
.then(setS)
|
.then((r) => {
|
||||||
.catch(() => {
|
setS(r);
|
||||||
/* 顶栏静默失败,避免刷屏 */
|
setErr(r.ok ? "" : r.detail || "资金摘要不可用");
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
setErr(e instanceof Error ? e.message : String(e));
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
load();
|
load();
|
||||||
const t = window.setInterval(load, 5000);
|
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]);
|
}, [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 (
|
return (
|
||||||
<div className="funds-bar-shell">
|
<div className="funds-bar-shell">
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ export default function SettingsPage() {
|
|||||||
const [orderInterval, setOrderInterval] = useState(1);
|
const [orderInterval, setOrderInterval] = useState(1);
|
||||||
const [skipWeekends, setSkipWeekends] = useState(true);
|
const [skipWeekends, setSkipWeekends] = useState(true);
|
||||||
const [leverage, setLeverage] = useState(3);
|
const [leverage, setLeverage] = useState(3);
|
||||||
|
const [perpMarginMode, setPerpMarginMode] = useState<"cross" | "isolated">(
|
||||||
|
"cross",
|
||||||
|
);
|
||||||
const [minHours, setMinHours] = useState(12);
|
const [minHours, setMinHours] = useState(12);
|
||||||
const [minOptLev, setMinOptLev] = useState(100);
|
const [minOptLev, setMinOptLev] = useState(100);
|
||||||
const [atmOffOn, setAtmOffOn] = useState(false);
|
const [atmOffOn, setAtmOffOn] = useState(false);
|
||||||
@@ -157,6 +160,9 @@ export default function SettingsPage() {
|
|||||||
setOrderInterval(s.live_order_interval_sec ?? 1);
|
setOrderInterval(s.live_order_interval_sec ?? 1);
|
||||||
setSkipWeekends(s.skip_weekends !== false);
|
setSkipWeekends(s.skip_weekends !== false);
|
||||||
setLeverage(s.leverage ?? 3);
|
setLeverage(s.leverage ?? 3);
|
||||||
|
setPerpMarginMode(
|
||||||
|
s.perp_margin_mode === "isolated" ? "isolated" : "cross",
|
||||||
|
);
|
||||||
setMinHours(s.min_option_hours ?? 12);
|
setMinHours(s.min_option_hours ?? 12);
|
||||||
setMinOptLev(s.min_option_leverage ?? 100);
|
setMinOptLev(s.min_option_leverage ?? 100);
|
||||||
setAtmOffOn(s.atm_open_offset_enabled === true);
|
setAtmOffOn(s.atm_open_offset_enabled === true);
|
||||||
@@ -292,7 +298,7 @@ export default function SettingsPage() {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setStratOk("");
|
setStratOk("");
|
||||||
setErr("");
|
setErr("");
|
||||||
const isLive = (runtime?.mode ?? mode) === "LIVE";
|
const isLive = mode === "LIVE";
|
||||||
try {
|
try {
|
||||||
const body: Record<string, unknown> = {
|
const body: Record<string, unknown> = {
|
||||||
fee_rate: fee,
|
fee_rate: fee,
|
||||||
@@ -303,6 +309,7 @@ export default function SettingsPage() {
|
|||||||
live_order_interval_sec: orderInterval,
|
live_order_interval_sec: orderInterval,
|
||||||
skip_weekends: skipWeekends,
|
skip_weekends: skipWeekends,
|
||||||
leverage,
|
leverage,
|
||||||
|
perp_margin_mode: perpMarginMode,
|
||||||
min_option_hours: minHours,
|
min_option_hours: minHours,
|
||||||
min_option_leverage: minOptLev,
|
min_option_leverage: minOptLev,
|
||||||
atm_open_offset_enabled: atmOffOn,
|
atm_open_offset_enabled: atmOffOn,
|
||||||
@@ -375,6 +382,7 @@ export default function SettingsPage() {
|
|||||||
: `已切 LIVE,但未就绪:${r.live_ready_reason}`
|
: `已切 LIVE,但未就绪:${r.live_ready_reason}`
|
||||||
: "已切换 SIM,配置已写入 .env",
|
: "已切换 SIM,配置已写入 .env",
|
||||||
);
|
);
|
||||||
|
window.dispatchEvent(new Event("funds-refresh"));
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
setErr(ex instanceof Error ? ex.message : String(ex));
|
setErr(ex instanceof Error ? ex.message : String(ex));
|
||||||
} finally {
|
} finally {
|
||||||
@@ -531,7 +539,7 @@ export default function SettingsPage() {
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{(runtime?.mode ?? mode) !== "LIVE" ? (
|
{mode !== "LIVE" ? (
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<label htmlFor="equity">模拟资金(USDT)</label>
|
<label htmlFor="equity">模拟资金(USDT)</label>
|
||||||
<input
|
<input
|
||||||
@@ -559,6 +567,22 @@ export default function SettingsPage() {
|
|||||||
onChange={(e) => setLeverage(Number(e.target.value))}
|
onChange={(e) => setLeverage(Number(e.target.value))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</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">
|
<div className="field">
|
||||||
<label htmlFor="perp">永续 ETH 数量</label>
|
<label htmlFor="perp">永续 ETH 数量</label>
|
||||||
<input
|
<input
|
||||||
@@ -822,19 +846,23 @@ export default function SettingsPage() {
|
|||||||
>
|
>
|
||||||
<ul className="settings-rules-list">
|
<ul className="settings-rules-list">
|
||||||
<li>
|
<li>
|
||||||
{(runtime?.mode ?? mode) === "LIVE"
|
{mode === "LIVE"
|
||||||
? "当前 LIVE:仓位/选约/出场影响真下单;模拟资金已隐藏。"
|
? "当前 LIVE:仓位/选约/出场影响真下单;模拟资金已隐藏。"
|
||||||
: "当前 SIM:本地撮合;可改模拟资金与交易所行情源。"}
|
: "当前 SIM:本地撮合;可改模拟资金与交易所行情源。"}
|
||||||
</li>
|
</li>
|
||||||
{stratSub === "position" ? (
|
{stratSub === "position" ? (
|
||||||
<>
|
<>
|
||||||
<li>交易所:有持仓时不可切换。切换后套用该所合约并重连行情。</li>
|
<li>交易所:有持仓时不可切换。切换后套用该所合约并重连行情。</li>
|
||||||
{(runtime?.mode ?? mode) !== "LIVE" ? (
|
{mode !== "LIVE" ? (
|
||||||
<li>
|
<li>
|
||||||
模拟资金:仅 SIM 显示。保存后重置权益(须无持仓)。默认
|
模拟资金:仅 SIM 显示。保存后重置权益(须无持仓)。默认
|
||||||
10000。
|
10000。
|
||||||
</li>
|
</li>
|
||||||
) : null}
|
) : null}
|
||||||
|
<li>
|
||||||
|
永续保证金模式:仅作用于永续(全仓/逐仓,默认全仓)。OKX
|
||||||
|
期权始终为现金/逐仓(cash),不受此选项影响。
|
||||||
|
</li>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
{stratSub === "select" ? (
|
{stratSub === "select" ? (
|
||||||
@@ -1168,6 +1196,7 @@ export default function SettingsPage() {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
setFundsOk("兑换成功,顶部资金条将刷新");
|
setFundsOk("兑换成功,顶部资金条将刷新");
|
||||||
|
window.dispatchEvent(new Event("funds-refresh"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setFundsErr(e instanceof Error ? e.message : String(e));
|
setFundsErr(e instanceof Error ? e.message : String(e));
|
||||||
} finally {
|
} finally {
|
||||||
@@ -1257,6 +1286,7 @@ export default function SettingsPage() {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
setFundsOk("划转成功,顶部资金条将刷新");
|
setFundsOk("划转成功,顶部资金条将刷新");
|
||||||
|
window.dispatchEvent(new Event("funds-refresh"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setFundsErr(e instanceof Error ? e.message : String(e));
|
setFundsErr(e instanceof Error ? e.message : String(e));
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user