This commit is contained in:
薇薇安 2026-01-31 10:12:09 +08:00
parent 6e23c924b2
commit aaca165f55
2 changed files with 50 additions and 12 deletions

View File

@ -356,6 +356,18 @@ async def get_global_configs(
# 添加更多核心策略配置的默认值(确保前端能显示所有重要配置)
ADDITIONAL_STRATEGY_DEFAULTS = {
"BETA_FILTER_ENABLED": {
"value": True,
"type": "boolean",
"category": "strategy",
"description": "大盘共振过滤BTC/ETH 下跌时屏蔽多单",
},
"BETA_FILTER_THRESHOLD": {
"value": -0.005,
"type": "number",
"category": "strategy",
"description": "大盘共振阈值(比例,如 -0.005 表示 -0.5%",
},
"USE_ATR_STOP_LOSS": {
"value": True,
"type": "boolean",

View File

@ -7,6 +7,26 @@ import './GlobalConfig.css'
import './ConfigPanel.css' // ConfigPanel
// ConfigPanel ConfigItem
// 使 RSI 010024h 25 25% 01
const NUMBER_AS_IS_KEYS = new Set([
'MAX_RSI_FOR_LONG',
'MIN_RSI_FOR_SHORT',
'MAX_CHANGE_PERCENT_FOR_LONG',
'MAX_CHANGE_PERCENT_FOR_SHORT',
])
// 便
const KEY_LABELS = {
MAX_RSI_FOR_LONG: '做多 RSI 上限',
MIN_RSI_FOR_SHORT: '做空 RSI 下限',
MAX_CHANGE_PERCENT_FOR_LONG: '做多 24h 涨跌幅上限(%)',
MAX_CHANGE_PERCENT_FOR_SHORT: '做空 24h 涨跌幅上限(%)',
TAKE_PROFIT_1_PERCENT: '第一目标止盈(%)',
SCAN_EXTRA_SYMBOLS_FOR_SUPPLEMENT: '智能补单候选数',
SYMBOL_LOSS_COOLDOWN_ENABLED: '连续亏损冷却',
SYMBOL_MAX_CONSECUTIVE_LOSSES: '连续亏损次数阈值',
SYMBOL_LOSS_COOLDOWN_SEC: '冷却时间(秒)',
}
const ConfigItem = ({ label, config, onUpdate, disabled }) => {
const isPercentKey = label.includes('PERCENT') || label.includes('PCT')
const PCT_LIKE_KEYS = new Set([
@ -16,7 +36,8 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
'FIXED_RISK_PERCENT', // 0.02 = 2%
])
const isPctLike = PCT_LIKE_KEYS.has(label)
const isRatioPercentKey = isPercentKey && !isPctLike
const isNumberAsIs = NUMBER_AS_IS_KEYS.has(label)
const displayLabel = KEY_LABELS[label] || label
const formatPercent = (n) => {
if (typeof n !== 'number' || isNaN(n)) return ''
@ -24,6 +45,11 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
}
const getInitialDisplayValue = (val) => {
if (config.type === 'number' && isNumberAsIs) {
if (val === null || val === undefined || val === '') return ''
const numVal = typeof val === 'string' ? parseFloat(val) : val
return isNaN(numVal) ? '' : String(numVal)
}
if (config.type === 'number' && isPercentKey) {
if (val === null || val === undefined || val === '') {
return ''
@ -32,13 +58,9 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
if (isNaN(numVal)) {
return ''
}
// 0.300.30
// >1
if (isPctLike) {
// pct-like""<=1<=1%
return formatPercent(numVal <= 0.05 ? numVal * 100 : numVal)
}
// 0.30>1
return formatPercent(numVal <= 1 ? numVal : numVal / 100)
}
return val === null || val === undefined ? '' : val
@ -63,21 +85,26 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
if (!isEditing) return
let finalValue = localValue
if (config.type === 'number') {
if (isPercentKey) {
if (isNumberAsIs) {
const numVal = parseFloat(localValue)
if (isNaN(numVal)) {
setLocalValue(getInitialDisplayValue(config.value))
setIsEditing(false)
return
}
finalValue = numVal
} else if (isPercentKey) {
const numVal = parseFloat(localValue)
if (isNaN(numVal)) {
setLocalValue(getInitialDisplayValue(config.value))
setIsEditing(false)
return
}
// 0.30
// 0-1
if (numVal < 0 || numVal > 1) {
setLocalValue(getInitialDisplayValue(config.value))
setIsEditing(false)
return
}
// 使0.30
finalValue = numVal
} else {
finalValue = parseFloat(localValue)
@ -101,7 +128,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
return (
<div className="config-item">
<div className="config-item-header">
<label>{label}</label>
<label>{displayLabel}</label>
</div>
<div className="config-input-wrapper">
{config.type === 'boolean' ? (
@ -124,10 +151,9 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
value={displayValue === '' ? '' : String(displayValue)}
onChange={(e) => {
let newValue = e.target.value
if (config.type === 'number') {
if (config.type === 'number' && !isNumberAsIs) {
if (isPercentKey) {
const numValue = parseFloat(newValue)
// 0-1
if (newValue !== '' && !isNaN(numValue) && (numValue < 0 || numValue > 1)) {
return
}