1
This commit is contained in:
parent
d3ca06a8ad
commit
7abf7db2df
|
|
@ -229,6 +229,8 @@ const GlobalConfig = () => {
|
|||
altcoin: {
|
||||
name: '山寨币策略(推荐)',
|
||||
desc: '【安全推荐】总仓65%降低回撤,大盘-1%再屏蔽多单。3%风险/单,30%第一止盈/55%第二止盈,30%激活移动止损、10%保护。',
|
||||
// 只比这几项与数据库一致即视为选中,避免因缺项或格式差异永远不中
|
||||
signatureKeys: ['AUTO_TRADE_ONLY_TRENDING', 'RSI_EXTREME_REVERSE_ENABLED', 'USE_MARGIN_CAP_FOR_TP', 'USE_MARGIN_CAP_FOR_SL', 'MAX_POSITION_PERCENT', 'MAX_DAILY_ENTRIES', 'TOP_N_SYMBOLS', 'FIXED_RISK_PERCENT'],
|
||||
configs: {
|
||||
// 风险与止盈止损
|
||||
ATR_STOP_LOSS_MULTIPLIER: 3.0,
|
||||
|
|
@ -908,17 +910,24 @@ const GlobalConfig = () => {
|
|||
// 管理员全局配置页面:不依赖任何 account,直接管理全局配置表
|
||||
const isGlobalStrategyAccount = isAdmin
|
||||
|
||||
// 当前预设检测:与后端返回值比较,支持类型标准化(后端可能返回 string "8" / "true")
|
||||
// 预设检测:只比「特征键」且与数据库一致(宽松:数字容差、布尔兼容字符串、百分比支持 0.2 与 20 两种存法)
|
||||
const toNum = (v) => (typeof v === 'number' ? v : parseFloat(v))
|
||||
const toBool = (v) => (v === true || v === false ? v : (v === 'true' || String(v).toLowerCase() === 'true' || v === 1 || v === '1'))
|
||||
const toRatio = (v, key) => {
|
||||
const n = toNum(v)
|
||||
if (Number.isNaN(n)) return null
|
||||
if (key && (key.includes('PERCENT') || key.includes('PCT')) && n > 1) return n / 100
|
||||
return n
|
||||
}
|
||||
const valueMatches = (cur, exp, key) => {
|
||||
if (exp === true || exp === false) {
|
||||
const b = cur === true || cur === false ? cur : (cur === 'true' || String(cur).toLowerCase() === 'true')
|
||||
return b === exp
|
||||
}
|
||||
if (exp === true || exp === false) return toBool(cur) === exp
|
||||
if (typeof exp === 'number') {
|
||||
const n = typeof cur === 'number' ? cur : parseFloat(cur)
|
||||
if (Number.isNaN(n)) return false
|
||||
const tolerance = (key && (key.includes('PERCENT') || key.includes('PCT'))) ? 0.001 : 0.0001
|
||||
return Math.abs(n - exp) <= tolerance
|
||||
const r = key && (key.includes('PERCENT') || key.includes('PCT'))
|
||||
const a = r ? toRatio(cur, key) : toNum(cur)
|
||||
let b = exp
|
||||
if (r && exp > 1) b = exp / 100
|
||||
if (a == null || Number.isNaN(a)) return false
|
||||
return Math.abs(a - b) <= 0.002
|
||||
}
|
||||
return cur === exp
|
||||
}
|
||||
|
|
@ -926,21 +935,19 @@ const GlobalConfig = () => {
|
|||
if (configs && Object.keys(configs).length > 0 && presets) {
|
||||
try {
|
||||
for (const [presetKey, preset] of Object.entries(presets)) {
|
||||
const keysToCheck = preset.signatureKeys && preset.signatureKeys.length > 0
|
||||
? preset.signatureKeys
|
||||
: Object.keys(preset.configs)
|
||||
let match = true
|
||||
for (const [key, expectedValue] of Object.entries(preset.configs)) {
|
||||
for (const key of keysToCheck) {
|
||||
const currentConfig = configs[key]
|
||||
if (!currentConfig) continue // 后端未返回的 key 不参与匹配,避免因缺项导致永远不选中
|
||||
let cur = currentConfig.value
|
||||
let exp = expectedValue
|
||||
if (key.includes('PERCENT') || key.includes('PCT')) {
|
||||
if (typeof exp === 'number' && exp > 1) exp = exp / 100
|
||||
}
|
||||
if (!valueMatches(cur, exp, key)) {
|
||||
match = false
|
||||
break
|
||||
}
|
||||
if (!currentConfig) { match = false; break }
|
||||
const exp = preset.configs[key]
|
||||
if (exp === undefined) continue
|
||||
const cur = currentConfig.value
|
||||
if (!valueMatches(cur, exp, key)) { match = false; break }
|
||||
}
|
||||
if (match) {
|
||||
if (match && keysToCheck.length > 0) {
|
||||
currentPreset = presetKey
|
||||
break
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user