418 lines
11 KiB
Markdown
418 lines
11 KiB
Markdown
# 配置值格式统一方案
|
||
|
||
## 🎯 问题分析
|
||
|
||
### 当前问题
|
||
|
||
**数据库中的配置值**(百分比形式):
|
||
- `TRAILING_STOP_ACTIVATION` = 30(表示30%)
|
||
- `TRAILING_STOP_PROTECT` = 15(表示15%)
|
||
- `MIN_VOLATILITY` = 3(表示3%)
|
||
|
||
**代码期望的格式**(比例形式):
|
||
- `TRAILING_STOP_ACTIVATION` = 0.30(表示30%)
|
||
- `TRAILING_STOP_PROTECT` = 0.15(表示15%)
|
||
- `MIN_VOLATILITY` = 0.03(表示3%)
|
||
|
||
**临时修复**:
|
||
- 在代码中添加格式转换逻辑(如果值>1,除以100)
|
||
- 问题:代码逻辑复杂,容易出错,维护困难
|
||
|
||
---
|
||
|
||
## ✅ 更好的解决方案
|
||
|
||
### 方案:统一数据格式(推荐)
|
||
|
||
**原则**:
|
||
- **数据库存储**:统一使用比例形式(0.30表示30%)
|
||
- **前端输入**:用户输入30,前端转换为0.30存储
|
||
- **前端显示**:从数据库读取0.30,显示为30
|
||
- **代码逻辑**:直接使用比例形式,不需要格式转换
|
||
|
||
**优势**:
|
||
1. ✅ **数据格式统一**:避免混乱
|
||
2. ✅ **代码逻辑清晰**:不需要到处做格式转换
|
||
3. ✅ **减少出错**:避免格式不一致导致的bug
|
||
4. ✅ **易于维护**:统一的格式,更容易理解和维护
|
||
|
||
---
|
||
|
||
## 🔧 实施步骤
|
||
|
||
### 步骤1:检查前端格式转换逻辑
|
||
|
||
**当前前端逻辑**(`frontend/src/components/ConfigPanel.jsx:1588-1594`):
|
||
```javascript
|
||
// 常规比例型:前端按"百分比"输入(0~100),存储为 0~1
|
||
if (processedValue < 0 || processedValue > 100) {
|
||
setLocalValue(getInitialDisplayValue(value))
|
||
return
|
||
}
|
||
processedValue = processedValue / 100 // ✅ 前端已经转换为比例形式
|
||
```
|
||
|
||
**结论**:✅ **前端已经正确转换**,用户输入30,会转换为0.30存储
|
||
|
||
---
|
||
|
||
### 步骤2:检查后端验证逻辑
|
||
|
||
**当前后端验证**(`backend/api/routes/config.py:843-848`):
|
||
```python
|
||
# 特殊验证:百分比配置应该在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%)"
|
||
)
|
||
```
|
||
|
||
**结论**:✅ **后端已经正确验证**,只接受0-1之间的值
|
||
|
||
---
|
||
|
||
### 步骤3:数据迁移(修复现有数据)
|
||
|
||
**问题**:数据库中可能已经有旧数据是百分比形式(30而不是0.30)
|
||
|
||
**解决方案**:创建数据迁移脚本,将百分比形式转换为比例形式
|
||
|
||
**需要迁移的配置项**:
|
||
- `TRAILING_STOP_ACTIVATION`(如果>1,除以100)
|
||
- `TRAILING_STOP_PROTECT`(如果>1,除以100)
|
||
- `MIN_VOLATILITY`(如果>1,除以100)
|
||
- `TAKE_PROFIT_PERCENT`(如果>1,除以100)
|
||
- `STOP_LOSS_PERCENT`(如果>1,除以100)
|
||
- 其他百分比配置项
|
||
|
||
---
|
||
|
||
### 步骤4:移除代码中的格式转换(可选)
|
||
|
||
**当前代码**(`backend/config_manager.py:735-758`):
|
||
```python
|
||
# ⚠️ 关键修复:百分比配置值格式转换
|
||
if isinstance(value, (int, float)) and value is not None:
|
||
percent_keys = [...]
|
||
if key in percent_keys:
|
||
if value > 1:
|
||
value = value / 100.0 # 格式转换
|
||
```
|
||
|
||
**建议**:
|
||
- 数据迁移完成后,可以移除格式转换逻辑
|
||
- 或者保留作为兼容性处理(标记为临时方案)
|
||
|
||
---
|
||
|
||
## 📝 数据迁移脚本
|
||
|
||
### SQL迁移脚本
|
||
|
||
```sql
|
||
-- 迁移百分比配置项:将百分比形式(>1)转换为比例形式(除以100)
|
||
|
||
-- 1. 迁移 trading_config 表
|
||
UPDATE trading_config
|
||
SET config_value = CAST(config_value AS DECIMAL(10, 4)) / 100.0
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT',
|
||
'MIN_STOP_LOSS_PRICE_PCT',
|
||
'MIN_TAKE_PROFIT_PRICE_PCT',
|
||
'FIXED_RISK_PERCENT',
|
||
'MAX_POSITION_PERCENT',
|
||
'MAX_TOTAL_POSITION_PERCENT',
|
||
'MIN_POSITION_PERCENT'
|
||
)
|
||
AND config_type = 'number'
|
||
AND CAST(config_value AS DECIMAL(10, 4)) > 1;
|
||
|
||
-- 2. 迁移 global_strategy_config 表
|
||
UPDATE global_strategy_config
|
||
SET config_value = CAST(config_value AS DECIMAL(10, 4)) / 100.0
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT',
|
||
'MIN_STOP_LOSS_PRICE_PCT',
|
||
'MIN_TAKE_PROFIT_PRICE_PCT',
|
||
'FIXED_RISK_PERCENT',
|
||
'MAX_POSITION_PERCENT',
|
||
'MAX_TOTAL_POSITION_PERCENT',
|
||
'MIN_POSITION_PERCENT'
|
||
)
|
||
AND config_type = 'number'
|
||
AND CAST(config_value AS DECIMAL(10, 4)) > 1;
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 验证步骤
|
||
|
||
### 1. 检查数据库中的配置值
|
||
|
||
```sql
|
||
-- 检查 trading_config 表中的百分比配置项
|
||
SELECT config_key, config_value, config_type
|
||
FROM trading_config
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT'
|
||
)
|
||
AND config_type = 'number';
|
||
|
||
-- 检查 global_strategy_config 表中的百分比配置项
|
||
SELECT config_key, config_value, config_type
|
||
FROM global_strategy_config
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT'
|
||
)
|
||
AND config_type = 'number';
|
||
```
|
||
|
||
### 2. 执行数据迁移
|
||
|
||
```bash
|
||
# 执行SQL迁移脚本
|
||
mysql -u username -p database_name < migrate_percent_configs.sql
|
||
```
|
||
|
||
### 3. 验证迁移结果
|
||
|
||
```sql
|
||
-- 验证:所有百分比配置项应该在0-1之间
|
||
SELECT config_key, config_value
|
||
FROM trading_config
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT'
|
||
)
|
||
AND config_type = 'number'
|
||
AND (CAST(config_value AS DECIMAL(10, 4)) < 0 OR CAST(config_value AS DECIMAL(10, 4)) > 1);
|
||
-- 应该返回0行
|
||
```
|
||
|
||
### 4. 清除Redis缓存
|
||
|
||
```bash
|
||
# 清除Redis缓存,让系统重新加载配置
|
||
redis-cli FLUSHDB
|
||
# 或者只清除配置相关的key
|
||
redis-cli DEL "config:trading_config:*"
|
||
redis-cli DEL "config:global_strategy_config:*"
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 实施建议
|
||
|
||
### 方案A:立即迁移数据(推荐)
|
||
|
||
**步骤**:
|
||
1. ✅ 创建数据迁移脚本
|
||
2. ✅ 执行数据迁移
|
||
3. ✅ 验证迁移结果
|
||
4. ✅ 清除Redis缓存
|
||
5. ⚠️ 保留代码中的格式转换作为兼容性处理(标记为临时方案)
|
||
|
||
**优势**:
|
||
- 数据格式统一,避免混乱
|
||
- 代码逻辑清晰
|
||
- 减少出错
|
||
|
||
**风险**:
|
||
- 需要确保迁移脚本正确
|
||
- 需要备份数据库
|
||
|
||
---
|
||
|
||
### 方案B:保留格式转换(临时方案)
|
||
|
||
**步骤**:
|
||
1. ✅ 保留代码中的格式转换逻辑
|
||
2. ✅ 标记为临时兼容性处理
|
||
3. ⚠️ 后续逐步迁移数据
|
||
|
||
**优势**:
|
||
- 不需要立即迁移数据
|
||
- 系统可以继续运行
|
||
|
||
**劣势**:
|
||
- 代码逻辑复杂
|
||
- 容易出错
|
||
- 维护困难
|
||
|
||
---
|
||
|
||
## 📊 对比分析
|
||
|
||
### 当前方案(代码中格式转换)
|
||
|
||
**优点**:
|
||
- ✅ 不需要立即迁移数据
|
||
- ✅ 系统可以继续运行
|
||
|
||
**缺点**:
|
||
- ❌ 代码逻辑复杂,需要到处做格式转换
|
||
- ❌ 容易出错(忘记转换)
|
||
- ❌ 维护困难
|
||
- ❌ 数据格式不统一
|
||
|
||
---
|
||
|
||
### 统一数据格式方案
|
||
|
||
**优点**:
|
||
- ✅ 数据格式统一,避免混乱
|
||
- ✅ 代码逻辑清晰,不需要格式转换
|
||
- ✅ 减少出错,易于维护
|
||
- ✅ 前端和后端验证逻辑一致
|
||
|
||
**缺点**:
|
||
- ⚠️ 需要数据迁移
|
||
- ⚠️ 需要备份数据库
|
||
|
||
---
|
||
|
||
## ✅ 最终建议
|
||
|
||
### 推荐方案:统一数据格式
|
||
|
||
**理由**:
|
||
1. **架构更清晰**:数据格式统一,代码逻辑简单
|
||
2. **易于维护**:不需要到处做格式转换
|
||
3. **减少出错**:避免格式不一致导致的bug
|
||
4. **长期收益**:虽然需要一次性迁移,但长期收益更大
|
||
|
||
**实施步骤**:
|
||
1. 创建数据迁移脚本
|
||
2. 备份数据库
|
||
3. 执行数据迁移
|
||
4. 验证迁移结果
|
||
5. 清除Redis缓存
|
||
6. 保留代码中的格式转换作为兼容性处理(标记为临时方案,后续可以移除)
|
||
|
||
---
|
||
|
||
## 📝 数据迁移脚本(完整版)
|
||
|
||
```sql
|
||
-- ============================================================
|
||
-- 配置值格式统一迁移脚本
|
||
-- 将百分比形式(>1)转换为比例形式(除以100)
|
||
-- ============================================================
|
||
|
||
-- 1. 备份表(可选,但强烈推荐)
|
||
CREATE TABLE trading_config_backup AS SELECT * FROM trading_config;
|
||
CREATE TABLE global_strategy_config_backup AS SELECT * FROM global_strategy_config;
|
||
|
||
-- 2. 迁移 trading_config 表
|
||
UPDATE trading_config
|
||
SET config_value = CAST(config_value AS DECIMAL(10, 4)) / 100.0
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT',
|
||
'MIN_STOP_LOSS_PRICE_PCT',
|
||
'MIN_TAKE_PROFIT_PRICE_PCT',
|
||
'FIXED_RISK_PERCENT',
|
||
'MAX_POSITION_PERCENT',
|
||
'MAX_TOTAL_POSITION_PERCENT',
|
||
'MIN_POSITION_PERCENT'
|
||
)
|
||
AND config_type = 'number'
|
||
AND CAST(config_value AS DECIMAL(10, 4)) > 1;
|
||
|
||
-- 3. 迁移 global_strategy_config 表
|
||
UPDATE global_strategy_config
|
||
SET config_value = CAST(config_value AS DECIMAL(10, 4)) / 100.0
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT',
|
||
'MIN_STOP_LOSS_PRICE_PCT',
|
||
'MIN_TAKE_PROFIT_PRICE_PCT',
|
||
'FIXED_RISK_PERCENT',
|
||
'MAX_POSITION_PERCENT',
|
||
'MAX_TOTAL_POSITION_PERCENT',
|
||
'MIN_POSITION_PERCENT'
|
||
)
|
||
AND config_type = 'number'
|
||
AND CAST(config_value AS DECIMAL(10, 4)) > 1;
|
||
|
||
-- 4. 验证迁移结果
|
||
-- 检查是否还有>1的百分比配置项
|
||
SELECT 'trading_config' as table_name, config_key, config_value
|
||
FROM trading_config
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT'
|
||
)
|
||
AND config_type = 'number'
|
||
AND CAST(config_value AS DECIMAL(10, 4)) > 1
|
||
UNION ALL
|
||
SELECT 'global_strategy_config' as table_name, config_key, config_value
|
||
FROM global_strategy_config
|
||
WHERE config_key IN (
|
||
'TRAILING_STOP_ACTIVATION',
|
||
'TRAILING_STOP_PROTECT',
|
||
'MIN_VOLATILITY',
|
||
'TAKE_PROFIT_PERCENT',
|
||
'STOP_LOSS_PERCENT'
|
||
)
|
||
AND config_type = 'number'
|
||
AND CAST(config_value AS DECIMAL(10, 4)) > 1;
|
||
-- 应该返回0行
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 总结
|
||
|
||
### 当前方案的问题
|
||
|
||
**代码中格式转换**:
|
||
- ❌ 代码逻辑复杂
|
||
- ❌ 需要到处做格式转换
|
||
- ❌ 容易出错
|
||
- ❌ 维护困难
|
||
|
||
### 更好的方案
|
||
|
||
**统一数据格式**:
|
||
- ✅ 数据库存储比例形式(0.30表示30%)
|
||
- ✅ 前端输入时转换为比例形式
|
||
- ✅ 前端显示时转换为百分比形式
|
||
- ✅ 代码逻辑直接使用比例形式
|
||
|
||
### 实施建议
|
||
|
||
1. **立即执行数据迁移**:统一数据格式
|
||
2. **保留格式转换作为兼容性处理**:标记为临时方案
|
||
3. **后续可以移除格式转换**:数据格式统一后,可以移除
|