fix: 详情页5门显示修undefined bug,表单加per-symbol推荐值,切换symbol自动填推荐

This commit is contained in:
root 2026-03-11 16:44:25 +00:00
parent 2e4c05b2e0
commit 89a6809c20
3 changed files with 95 additions and 23 deletions

View File

@ -33,12 +33,19 @@ export default function EditStrategyPage() {
weight_aux: s.weight_aux, weight_aux: s.weight_aux,
weight_momentum: s.weight_momentum, weight_momentum: s.weight_momentum,
entry_score: s.entry_score, entry_score: s.entry_score,
// 门1 波动率
gate_vol_enabled: s.gate_vol_enabled,
vol_atr_pct_min: s.vol_atr_pct_min,
// 门2 CVD共振
gate_cvd_enabled: s.gate_cvd_enabled ?? true,
// 门3 鲸鱼否决
gate_whale_enabled: s.gate_whale_enabled,
whale_usd_threshold: s.whale_usd_threshold,
whale_flow_pct: s.whale_flow_pct,
// 门4 OBI否决
gate_obi_enabled: s.gate_obi_enabled, gate_obi_enabled: s.gate_obi_enabled,
obi_threshold: s.obi_threshold, obi_threshold: s.obi_threshold,
gate_whale_enabled: s.gate_whale_enabled, // 门5 期现背离
whale_cvd_threshold: s.whale_cvd_threshold,
gate_vol_enabled: s.gate_vol_enabled,
atr_percentile_min: s.atr_percentile_min,
gate_spot_perp_enabled: s.gate_spot_perp_enabled, gate_spot_perp_enabled: s.gate_spot_perp_enabled,
spot_perp_threshold: s.spot_perp_threshold, spot_perp_threshold: s.spot_perp_threshold,
sl_atr_multiplier: s.sl_atr_multiplier, sl_atr_multiplier: s.sl_atr_multiplier,

View File

@ -59,12 +59,19 @@ interface StrategyDetail {
weight_aux: number; weight_aux: number;
weight_momentum: number; weight_momentum: number;
entry_score: number; entry_score: number;
// 门1 波动率
gate_vol_enabled: boolean;
vol_atr_pct_min: number;
// 门2 CVD共振
gate_cvd_enabled: boolean;
// 门3 鲸鱼否决
gate_whale_enabled: boolean;
whale_usd_threshold: number;
whale_flow_pct: number;
// 门4 OBI否决
gate_obi_enabled: boolean; gate_obi_enabled: boolean;
obi_threshold: number; obi_threshold: number;
gate_whale_enabled: boolean; // 门5 期现背离
whale_cvd_threshold: number;
gate_vol_enabled: boolean;
atr_percentile_min: number;
gate_spot_perp_enabled: boolean; gate_spot_perp_enabled: boolean;
spot_perp_threshold: number; spot_perp_threshold: number;
sl_atr_multiplier: number; sl_atr_multiplier: number;
@ -150,13 +157,14 @@ function ConfigTab({ detail, strategyId }: { detail: StrategyDetail; strategyId:
{row("入场阈值", `${detail.entry_score}`)} {row("入场阈值", `${detail.entry_score}`)}
</div> </div>
{/* 道 Gate */} {/* 道 Gate */}
<div className="bg-white border border-slate-200 rounded-xl p-4"> <div className="bg-white border border-slate-200 rounded-xl p-4">
<h4 className="text-xs font-semibold text-slate-600 mb-2"> (Gate)</h4> <h4 className="text-xs font-semibold text-slate-600 mb-2"> (Gate)</h4>
{gateRow("Gate1 OBI", detail.gate_obi_enabled, `${detail.obi_threshold}`)} {gateRow("门1 波动率", detail.gate_vol_enabled, `ATR% ≥ ${((detail.vol_atr_pct_min ?? 0) * 100).toFixed(2)}%`)}
{gateRow("Gate2 大单CVD", detail.gate_whale_enabled, `${detail.whale_cvd_threshold}`)} {gateRow("门2 CVD共振", detail.gate_cvd_enabled ?? true, "快慢CVD同向")}
{gateRow("Gate3 ATR%", detail.gate_vol_enabled, `${detail.atr_percentile_min}%`)} {gateRow("门3 鲸鱼否决", detail.gate_whale_enabled, `USD ≥ $${((detail.whale_usd_threshold ?? 50000) / 1000).toFixed(0)}k`)}
{gateRow("Gate4 现货溢价", detail.gate_spot_perp_enabled, `${detail.spot_perp_threshold}`)} {gateRow("门4 OBI否决", detail.gate_obi_enabled, `阈值 ${detail.obi_threshold}`)}
{gateRow("门5 期现背离", detail.gate_spot_perp_enabled, `溢价 ≤ ${((detail.spot_perp_threshold ?? 0.005) * 100).toFixed(2)}%`)}
</div> </div>
{/* 风控参数 */} {/* 风控参数 */}
@ -235,12 +243,14 @@ export default function StrategyDetailPage() {
weight_aux: s.weight_aux, weight_aux: s.weight_aux,
weight_momentum: s.weight_momentum, weight_momentum: s.weight_momentum,
entry_score: s.entry_score, entry_score: s.entry_score,
gate_vol_enabled: s.gate_vol_enabled,
vol_atr_pct_min: s.vol_atr_pct_min,
gate_cvd_enabled: s.gate_cvd_enabled,
gate_whale_enabled: s.gate_whale_enabled,
whale_usd_threshold: s.whale_usd_threshold,
whale_flow_pct: s.whale_flow_pct,
gate_obi_enabled: s.gate_obi_enabled, gate_obi_enabled: s.gate_obi_enabled,
obi_threshold: s.obi_threshold, obi_threshold: s.obi_threshold,
gate_whale_enabled: s.gate_whale_enabled,
whale_cvd_threshold: s.whale_cvd_threshold,
gate_vol_enabled: s.gate_vol_enabled,
atr_percentile_min: s.atr_percentile_min,
gate_spot_perp_enabled: s.gate_spot_perp_enabled, gate_spot_perp_enabled: s.gate_spot_perp_enabled,
spot_perp_threshold: s.spot_perp_threshold, spot_perp_threshold: s.spot_perp_threshold,
sl_atr_multiplier: s.sl_atr_multiplier, sl_atr_multiplier: s.sl_atr_multiplier,

View File

@ -73,6 +73,44 @@ export const DEFAULT_FORM: StrategyFormData = {
description: "", description: "",
}; };
// ─── Per-symbol 推荐值 ────────────────────────────────────────────────────────
// 来自 v53.json symbol_gates与 signal_engine.py 默认值保持一致
export const SYMBOL_RECOMMENDED: Record<string, Partial<StrategyFormData>> = {
BTCUSDT: {
vol_atr_pct_min: 0.002, // ATR需>价格0.2%
whale_usd_threshold: 100000, // 鲸鱼单>10万USD
whale_flow_pct: 0.5, // BTC鲸鱼流量>50%才否决
obi_threshold: 0.30, // OBI阈值宽松BTC流动性好
spot_perp_threshold: 0.003, // 期现溢价<0.3%
},
ETHUSDT: {
vol_atr_pct_min: 0.003, // ETH波动需更大
whale_usd_threshold: 50000,
whale_flow_pct: 0.5,
obi_threshold: 0.35,
spot_perp_threshold: 0.005,
},
SOLUSDT: {
vol_atr_pct_min: 0.004, // SOL波动更剧烈需更高阈值
whale_usd_threshold: 20000,
whale_flow_pct: 0.5,
obi_threshold: 0.45, // SOL OBI噪音多需更严
spot_perp_threshold: 0.008,
},
XRPUSDT: {
vol_atr_pct_min: 0.0025,
whale_usd_threshold: 30000,
whale_flow_pct: 0.5,
obi_threshold: 0.40,
spot_perp_threshold: 0.006,
},
};
export function applySymbolDefaults(form: StrategyFormData, symbol: string): StrategyFormData {
const rec = SYMBOL_RECOMMENDED[symbol] || SYMBOL_RECOMMENDED["BTCUSDT"];
return { ...form, symbol, ...rec };
}
// ─── Helper Components ──────────────────────────────────────────────────────── // ─── Helper Components ────────────────────────────────────────────────────────
function FieldLabel({ label, hint }: { label: string; hint?: string }) { function FieldLabel({ label, hint }: { label: string; hint?: string }) {
return ( return (
@ -256,7 +294,14 @@ export default function StrategyForm({ mode, initialData, strategyId, onSuccess,
<FieldLabel label="交易对" /> <FieldLabel label="交易对" />
<SelectInput <SelectInput
value={form.symbol} value={form.symbol}
onChange={(v) => set("symbol", v)} onChange={(v) => {
if (mode === "create") {
// 新建时切换币种自动填入推荐值
setForm((prev) => applySymbolDefaults(prev, v));
} else {
set("symbol", v);
}
}}
options={[ options={[
{ label: "BTC/USDT", value: "BTCUSDT" }, { label: "BTC/USDT", value: "BTCUSDT" },
{ label: "ETH/USDT", value: "ETHUSDT" }, { label: "ETH/USDT", value: "ETHUSDT" },
@ -376,13 +421,23 @@ export default function StrategyForm({ mode, initialData, strategyId, onSuccess,
<div className="bg-white border border-slate-200 rounded-xl p-4"> <div className="bg-white border border-slate-200 rounded-xl p-4">
<h3 className="text-sm font-semibold text-slate-700 mb-3">Gate</h3> <h3 className="text-sm font-semibold text-slate-700 mb-3">Gate</h3>
<div className="space-y-3"> <div className="space-y-3">
{/* 推荐值提示 */}
{(() => {
const rec = SYMBOL_RECOMMENDED[form.symbol];
if (!rec) return null;
return (
<div className="text-xs text-slate-500 bg-slate-50 rounded-lg px-3 py-2">
📌 {form.symbol.replace("USDT","")} ATR%{((rec.vol_atr_pct_min??0)*100).toFixed(2)}%${((rec.whale_usd_threshold??50000)/1000).toFixed(0)}kOBI阈值{rec.obi_threshold}
</div>
);
})()}
<GateRow <GateRow
label="门1波动率门 (ATR%价格)" label="门1波动率门 (ATR%价格)"
hint="ATR占价格比例低于阈值时不开仓过滤低波动时段" hint="ATR占价格比例低于阈值时不开仓过滤低波动时段"
enabled={form.gate_vol_enabled} enabled={form.gate_vol_enabled}
onToggle={() => set("gate_vol_enabled", !form.gate_vol_enabled)} onToggle={() => set("gate_vol_enabled", !form.gate_vol_enabled)}
> >
<FieldLabel label="ATR% 最低阈值" hint="如0.002=价格0.2%BTC默认0.002ETH默认0.003" /> <FieldLabel label="ATR% 最低阈值" hint={`推荐BTC=0.002, ETH=0.003, SOL=0.004, XRP=0.0025(当前${form.symbol.replace("USDT","")}推荐${SYMBOL_RECOMMENDED[form.symbol]?.vol_atr_pct_min??0.002}`} />
<NumberInput value={form.vol_atr_pct_min} onChange={(v) => set("vol_atr_pct_min", v)} min={0.0001} max={0.02} step={0.0005} /> <NumberInput value={form.vol_atr_pct_min} onChange={(v) => set("vol_atr_pct_min", v)} min={0.0001} max={0.02} step={0.0005} />
</GateRow> </GateRow>
<GateRow <GateRow
@ -397,9 +452,9 @@ export default function StrategyForm({ mode, initialData, strategyId, onSuccess,
enabled={form.gate_whale_enabled} enabled={form.gate_whale_enabled}
onToggle={() => set("gate_whale_enabled", !form.gate_whale_enabled)} onToggle={() => set("gate_whale_enabled", !form.gate_whale_enabled)}
> >
<FieldLabel label="大单USD阈值 (ALT)" hint="超过此USD金额视为鲸鱼单ETH默认5万BTC默认10万" /> <FieldLabel label="大单USD阈值 (ALT)" hint={`推荐BTC=10万, ETH=5万, SOL=2万, XRP=3万当前推荐$${((SYMBOL_RECOMMENDED[form.symbol]?.whale_usd_threshold??50000)/1000).toFixed(0)}k`} />
<NumberInput value={form.whale_usd_threshold} onChange={(v) => set("whale_usd_threshold", v)} min={1000} max={1000000} step={5000} /> <NumberInput value={form.whale_usd_threshold} onChange={(v) => set("whale_usd_threshold", v)} min={1000} max={1000000} step={5000} />
<FieldLabel label="鲸鱼CVD流量阈值 (BTC)" hint="0~1BTC鲸鱼净方向比例超过此值才否决默认0.5" /> <FieldLabel label="鲸鱼CVD流量阈值 (BTC)" hint="0~1BTC鲸鱼净方向比例超过此值才否决推荐0.5" />
<NumberInput value={form.whale_flow_pct} onChange={(v) => set("whale_flow_pct", v)} min={0} max={1} step={0.05} /> <NumberInput value={form.whale_flow_pct} onChange={(v) => set("whale_flow_pct", v)} min={0} max={1} step={0.05} />
</GateRow> </GateRow>
<GateRow <GateRow
@ -408,7 +463,7 @@ export default function StrategyForm({ mode, initialData, strategyId, onSuccess,
enabled={form.gate_obi_enabled} enabled={form.gate_obi_enabled}
onToggle={() => set("gate_obi_enabled", !form.gate_obi_enabled)} onToggle={() => set("gate_obi_enabled", !form.gate_obi_enabled)}
> >
<FieldLabel label="OBI 否决阈值" hint="0.1(宽松) ~ 0.9(严格)默认0.35" /> <FieldLabel label="OBI 否决阈值" hint={`推荐BTC=0.30(宽松), ETH=0.35, SOL=0.45(严格)(当前推荐${SYMBOL_RECOMMENDED[form.symbol]?.obi_threshold??0.35}`} />
<NumberInput value={form.obi_threshold} onChange={(v) => set("obi_threshold", v)} min={0.1} max={0.9} step={0.05} /> <NumberInput value={form.obi_threshold} onChange={(v) => set("obi_threshold", v)} min={0.1} max={0.9} step={0.05} />
</GateRow> </GateRow>
<GateRow <GateRow
@ -417,7 +472,7 @@ export default function StrategyForm({ mode, initialData, strategyId, onSuccess,
enabled={form.gate_spot_perp_enabled} enabled={form.gate_spot_perp_enabled}
onToggle={() => set("gate_spot_perp_enabled", !form.gate_spot_perp_enabled)} onToggle={() => set("gate_spot_perp_enabled", !form.gate_spot_perp_enabled)}
> >
<FieldLabel label="溢价率阈值" hint="0.0005~0.01溢价超过此值不开仓默认0.005" /> <FieldLabel label="溢价率阈值" hint={`推荐BTC=0.003, ETH=0.005, SOL=0.008(当前推荐${SYMBOL_RECOMMENDED[form.symbol]?.spot_perp_threshold??0.005}`} />
<NumberInput value={form.spot_perp_threshold} onChange={(v) => set("spot_perp_threshold", v)} min={0.0005} max={0.01} step={0.0005} /> <NumberInput value={form.spot_perp_threshold} onChange={(v) => set("spot_perp_threshold", v)} min={0.0005} max={0.01} step={0.0005} />
</GateRow> </GateRow>
</div> </div>