This commit is contained in:
薇薇安 2026-02-09 17:39:15 +08:00
parent d16bb53e60
commit 78d1c3ac37
2 changed files with 156 additions and 2 deletions

View File

@ -831,6 +831,130 @@ async def check_config_feasibility(
raise HTTPException(status_code=500, detail=f"检查配置可行性失败: {str(e)}")
@router.put("/global/{key}")
async def update_global_config(
key: str,
item: ConfigUpdate,
user: Dict[str, Any] = Depends(get_current_user),
):
"""更新单个全局策略配置(仅管理员)"""
if (user.get("role") or "user") != "admin":
raise HTTPException(status_code=403, detail="仅管理员可修改全局策略配置")
try:
from database.models import GlobalStrategyConfig
# 验证配置值
config_type = item.type or "string"
if config_type == 'number':
try:
float(item.value)
except (ValueError, TypeError):
raise HTTPException(status_code=400, detail=f"Invalid number value for {key}")
elif config_type == 'boolean':
if not isinstance(item.value, bool):
if isinstance(item.value, str):
item.value = item.value.lower() in ('true', '1', 'yes', 'on')
else:
item.value = bool(item.value)
# 特殊验证百分比配置应该在0-1之间
if ('PERCENT' in key or 'PCT' in key) and config_type == 'number':
if not (0 <= float(item.value) <= 1):
raise HTTPException(
status_code=400,
detail=f"{key} must be between 0 and 1 (0% to 100%)"
)
# 更新数据库
GlobalStrategyConfig.set(
key,
item.value,
config_type,
item.category or "strategy",
item.description,
updated_by=user.get("username")
)
# 更新缓存 (ConfigManager)
try:
import config_manager
# 更新 GlobalStrategyConfigManager 的缓存
if hasattr(config_manager, 'GlobalStrategyConfigManager'):
mgr = config_manager.GlobalStrategyConfigManager()
# 写入Redis (会更新 redis 和 _cache)
mgr._set_to_redis(key, item.value)
# 手动更新本地缓存,确保当前进程也生效
mgr._cache[key] = item.value
logger.info(f"全局配置已更新到Redis缓存: {key} = {item.value}")
except Exception as e:
logger.warning(f"更新全局配置缓存失败: {e}")
return {
"message": "全局配置已更新",
"key": key,
"value": item.value
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/global/batch")
async def update_global_configs_batch(
configs: list[ConfigItem],
user: Dict[str, Any] = Depends(get_current_user),
):
"""批量更新全局策略配置(仅管理员)"""
if (user.get("role") or "user") != "admin":
raise HTTPException(status_code=403, detail="仅管理员可修改全局策略配置")
try:
from database.models import GlobalStrategyConfig
import config_manager
updated_count = 0
mgr = None
if hasattr(config_manager, 'GlobalStrategyConfigManager'):
mgr = config_manager.GlobalStrategyConfigManager()
for item in configs:
# 简单验证
config_type = item.type
val = item.value
if config_type == 'number':
try:
val = float(val)
except:
continue
elif config_type == 'boolean':
if not isinstance(val, bool):
val = str(val).lower() in ('true', '1', 'yes', 'on')
# 更新DB
GlobalStrategyConfig.set(
item.key,
val,
config_type,
item.category,
item.description,
updated_by=user.get("username")
)
# 更新缓存
if mgr:
mgr._set_to_redis(item.key, val)
mgr._cache[item.key] = val
updated_count += 1
return {"message": f"成功更新 {updated_count} 个全局配置项"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

View File

@ -35,7 +35,7 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
'LIMIT_ORDER_OFFSET_PCT',
'ENTRY_MAX_DRIFT_PCT_TRENDING',
'ENTRY_MAX_DRIFT_PCT_RANGING',
'FIXED_RISK_PERCENT', // 0.02 = 2%
// FIXED_RISK_PERCENT
])
const isPctLike = PCT_LIKE_KEYS.has(label)
const isNumberAsIs = NUMBER_AS_IS_KEYS.has(label)
@ -429,6 +429,24 @@ const GlobalConfig = () => {
MIN_HOLD_TIME_SEC: 1800,
USE_DYNAMIC_ATR_MULTIPLIER: false, // 使2.5
}
},
script_v1: {
name: '高收益趋势 (脚本配置)',
desc: '原 update_global_config.py 脚本中的配置。高止盈(60%) + 紧止损(10%) + 移动止损保护。适合捕捉大单边行情。',
configs: {
TAKE_PROFIT_PERCENT: 60.0,
TAKE_PROFIT_1_PERCENT: 30.0,
STOP_LOSS_PERCENT: 10.0,
TRAILING_STOP_ACTIVATION: 30.0,
TRAILING_STOP_PROTECT: 5.0,
LEVERAGE: 4,
RISK_REWARD_RATIO: 3.0,
ATR_TAKE_PROFIT_MULTIPLIER: 4.5,
ATR_STOP_LOSS_MULTIPLIER: 1.5,
USE_FIXED_RISK_SIZING: true,
FIXED_RISK_PERCENT: 1.0, // 1%
MAX_LEVERAGE_SMALL_CAP: 4,
}
}
}
@ -447,6 +465,17 @@ const GlobalConfig = () => {
BETA_FILTER_THRESHOLD: { value: -0.005, type: 'number', category: 'strategy', description: '大盘共振阈值(比例,如 -0.005 表示 -0.5%)。' },
RSI_EXTREME_REVERSE_ENABLED: { value: false, type: 'boolean', category: 'strategy', description: '开启后:原信号做多但 RSI 超买(≥做多上限)时改为做空;原信号做空但 RSI 超卖(≤做空下限)时改为做多。属均值回归思路,可填补超买超卖时不下单的空置;默认关闭。' },
RSI_EXTREME_REVERSE_ONLY_NEUTRAL_4H: { value: true, type: 'boolean', category: 'strategy', description: '建议开启:仅在 4H 趋势为中性时允许 RSI 反向单,避免在强趋势里逆势抄底/摸顶,降低风险。关闭则反向可与 4H 同向仍受“禁止逆4H趋势”约束。' },
TAKE_PROFIT_PERCENT: { value: 0.25, type: 'number', category: 'risk', description: '止盈百分比(保证金比例,如 25.0=25%)。' },
STOP_LOSS_PERCENT: { value: 0.08, type: 'number', category: 'risk', description: '止损百分比(保证金比例,如 8.0=8%)。' },
TRAILING_STOP_ACTIVATION: { value: 0.20, type: 'number', category: 'risk', description: '移动止损激活阈值(盈利达到此比例后激活,如 20.0=20%)。' },
TRAILING_STOP_PROTECT: { value: 0.10, type: 'number', category: 'risk', description: '移动止损保护阈值(回撤至此比例时触发止损,如 10.0=10%)。' },
LEVERAGE: { value: 5, type: 'number', category: 'risk', description: '基础杠杆倍数。' },
RISK_REWARD_RATIO: { value: 1.5, type: 'number', category: 'risk', description: '盈亏比目标(用于计算动态止盈止损)。' },
ATR_TAKE_PROFIT_MULTIPLIER: { value: 1.5, type: 'number', category: 'risk', description: 'ATR 止盈倍数。' },
ATR_STOP_LOSS_MULTIPLIER: { value: 2.5, type: 'number', category: 'risk', description: 'ATR 止损倍数。' },
USE_FIXED_RISK_SIZING: { value: false, type: 'boolean', category: 'risk', description: '是否使用固定风险仓位计算(基于止损距离和账户余额)。' },
FIXED_RISK_PERCENT: { value: 0.01, type: 'number', category: 'risk', description: '每笔交易固定风险百分比(如 0.01=1%)。' },
MAX_LEVERAGE_SMALL_CAP: { value: 3, type: 'number', category: 'risk', description: '小市值/山寨币最大允许杠杆。' },
}
const loadConfigs = async () => {
@ -950,6 +979,7 @@ const GlobalConfig = () => {
conservative: { group: 'legacy', tag: '传统' },
balanced: { group: 'legacy', tag: '传统' },
aggressive: { group: 'legacy', tag: '高频实验' },
script_v1: { group: 'legacy', tag: '脚本迁移' },
}
const presetGroups = [
@ -975,7 +1005,7 @@ const GlobalConfig = () => {
key: 'legacy',
title: 'C. 传统 / 实验(不建议长期)',
desc: '这组更多用于对比或临时实验(频率更高/更容易过度交易),建议在稳定盈利前谨慎使用。',
presetKeys: ['conservative', 'balanced', 'aggressive'],
presetKeys: ['conservative', 'balanced', 'aggressive', 'script_v1'],
},
]