# 配置架构验证文档

## 📋 验证目标

确认：
1. ✅ **所有用户下的账户都使用全局策略配置**
2. ✅ **普通用户无法通过自己的配置直接影响核心策略参数**

---

## 🏗️ 配置架构设计

### 1. 配置层级

```
┌─────────────────────────────────────────────────────────┐
│  全局策略账号 (account_id=1, 默认)                      │
│  - 存储所有核心策略参数                                  │
│  - 例如：ATR_STOP_LOSS_MULTIPLIER, ATR_TAKE_PROFIT_... │
└─────────────────────────────────────────────────────────┘
                    ↓ 读取
┌─────────────────────────────────────────────────────────┐
│  用户账户 (account_id=2, 3, 4...)                        │
│  - 存储风险旋钮（每个账户独立）                           │
│  - 例如：MAX_POSITION_PERCENT, AUTO_TRADE_ENABLED...    │
└─────────────────────────────────────────────────────────┘
```

### 2. 配置读取逻辑

**位置**：`backend/config_manager.py` 的 `get_trading_config()` 方法

```python
def eff_get(key: str, default: Any):
    """
    策略核心：默认从全局账号读取（GLOBAL_STRATEGY_ACCOUNT_ID）。
    风险旋钮：从当前账号读取。
    """
    # API key/secret/testnet 永远按账号读取
    if key in RISK_KNOBS_KEYS or global_mgr is None:
        return self.get(key, default)  # 从当前账号读取
    try:
        # 从全局账号读取
        return global_mgr.get(key, default)
    except Exception:
        return self.get(key, default)
```

**风险旋钮列表**（`RISK_KNOBS_KEYS`）：
- `MIN_MARGIN_USDT`
- `MIN_POSITION_PERCENT`
- `MAX_POSITION_PERCENT`
- `MAX_TOTAL_POSITION_PERCENT`
- `AUTO_TRADE_ENABLED`
- `MAX_OPEN_POSITIONS`
- `MAX_DAILY_ENTRIES`

**核心策略参数**（从全局账号读取）：
- `ATR_STOP_LOSS_MULTIPLIER`
- `ATR_TAKE_PROFIT_MULTIPLIER`
- `RISK_REWARD_RATIO`
- `USE_FIXED_RISK_SIZING`
- `FIXED_RISK_PERCENT`
- `USE_DYNAMIC_ATR_MULTIPLIER`
- `MIN_SIGNAL_STRENGTH`
- `SCAN_INTERVAL`
- `TOP_N_SYMBOLS`
- ... 等等所有非风险旋钮的配置

---

## 🔒 权限控制

### 1. 后端API权限控制

**位置**：`backend/api/routes/config.py`

#### GET `/api/config` - 获取配置列表

```python
# 普通用户：只展示风险旋钮 + 账号密钥
# 管理员：若当前不是"全局策略账号"，同样只展示风险旋钮
is_admin = (user.get("role") or "user") == "admin"
gid = _global_strategy_account_id()
if (not is_admin) or (is_admin and int(account_id) != int(gid)):
    allowed = set(USER_RISK_KNOBS) | {"BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET"}
    result = {k: v for k, v in result.items() if k in allowed}
```

**验证**：
- ✅ 普通用户只能看到 `USER_RISK_KNOBS` + API密钥
- ✅ 管理员在非全局策略账号时，也只能看到风险旋钮
- ✅ 只有管理员在全局策略账号时，才能看到所有配置

#### PUT `/api/config/{key}` - 更新单个配置

```python
# 管理员：若不是全局策略账号，则禁止修改策略核心
if (user.get("role") or "user") == "admin":
    gid = _global_strategy_account_id()
    if int(account_id) != int(gid):
        if key not in (USER_RISK_KNOBS | {"BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET"}):
            raise HTTPException(status_code=403, detail=f"该配置由全局策略账号 #{gid} 统一管理")

# 产品模式：普通用户只能改"风险旋钮"与账号私有密钥/测试网
if (user.get("role") or "user") != "admin":
    if key not in (USER_RISK_KNOBS | {"BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET"}):
        raise HTTPException(status_code=403, detail="该配置由平台统一管理（仅管理员可修改）")
```

**验证**：
- ✅ 普通用户尝试修改核心策略参数会返回 403 错误
- ✅ 管理员在非全局策略账号时，也无法修改核心策略参数
- ✅ 只有管理员在全局策略账号时，才能修改核心策略参数

#### POST `/api/config/batch` - 批量更新配置

```python
for item in configs:
    # 管理员：若不是全局策略账号，则批量只允许风险旋钮/密钥
    if (user.get("role") or "user") == "admin":
        gid = _global_strategy_account_id()
        if int(account_id) != int(gid):
            if item.key not in (USER_RISK_KNOBS | {"BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET"}):
                errors.append(f"{item.key}: 该配置由全局策略账号 #{gid} 统一管理，请切换账号修改")
                continue
    
    # 产品模式：普通用户只能改"风险旋钮"与账号私有密钥/测试网
    if (user.get("role") or "user") != "admin":
        if item.key not in (USER_RISK_KNOBS | {"BINANCE_API_KEY", "BINANCE_API_SECRET", "USE_TESTNET"}):
            errors.append(f"{item.key}: 该配置由平台统一管理（仅管理员可修改）")
            continue
```

**验证**：
- ✅ 普通用户批量更新时，核心策略参数会被过滤并返回错误
- ✅ 管理员在非全局策略账号时，核心策略参数也会被过滤

---

## ✅ 验证结果

### 1. 所有账户使用全局策略配置 ✅

**验证点**：
- `config_manager.py` 的 `get_trading_config()` 方法中，所有非风险旋钮的配置都通过 `eff_get()` 从全局账号读取
- 即使普通用户在自己的账户中设置了核心策略参数，也不会生效（因为读取时从全局账号读取）

**代码位置**：
- `backend/config_manager.py:509-522`

**结论**：✅ **所有账户都使用全局策略配置**

---

### 2. 普通用户无法修改核心策略参数 ✅

**验证点**：
- **前端限制**：普通用户在配置页面只能看到风险旋钮（通过API过滤）
- **后端限制**：
  - GET `/api/config`：只返回风险旋钮
  - PUT `/api/config/{key}`：尝试修改核心参数返回 403
  - POST `/api/config/batch`：核心参数被过滤并返回错误

**代码位置**：
- `backend/api/routes/config.py:273-280` (GET)
- `backend/api/routes/config.py:645-655` (PUT)
- `backend/api/routes/config.py:765-776` (POST)

**结论**：✅ **普通用户无法通过自己的配置直接影响核心策略参数**

---

## 📊 配置分类总结

### 风险旋钮（每个账户独立）
- `MIN_MARGIN_USDT` - 最小保证金（USDT）
- `MIN_POSITION_PERCENT` - 最小仓位占比
- `MAX_POSITION_PERCENT` - 最大仓位占比
- `MAX_TOTAL_POSITION_PERCENT` - 总仓位占比上限
- `AUTO_TRADE_ENABLED` - 自动交易开关
- `MAX_OPEN_POSITIONS` - 同时持仓数量上限
- `MAX_DAILY_ENTRIES` - 每日最多开仓次数

### 核心策略参数（全局统一）
- `ATR_STOP_LOSS_MULTIPLIER` - ATR止损倍数
- `ATR_TAKE_PROFIT_MULTIPLIER` - ATR止盈倍数
- `RISK_REWARD_RATIO` - 盈亏比
- `USE_FIXED_RISK_SIZING` - 使用固定风险百分比
- `FIXED_RISK_PERCENT` - 固定风险百分比
- `USE_DYNAMIC_ATR_MULTIPLIER` - 动态ATR倍数
- `MIN_SIGNAL_STRENGTH` - 最小信号强度
- `SCAN_INTERVAL` - 扫描间隔
- `TOP_N_SYMBOLS` - 每次扫描处理的交易对数量
- ... 等等所有非风险旋钮的配置

### 账号私有配置（每个账户独立）
- `BINANCE_API_KEY` - 币安API密钥
- `BINANCE_API_SECRET` - 币安API密钥
- `USE_TESTNET` - 是否使用测试网

---

## 🎯 实际运行验证

### 测试场景1：普通用户查看配置
1. 普通用户登录
2. 进入配置页面
3. **预期**：只能看到风险旋钮 + API密钥配置
4. **验证**：前端只显示允许的配置项

### 测试场景2：普通用户尝试修改核心策略参数
1. 普通用户登录
2. 尝试通过API修改 `ATR_STOP_LOSS_MULTIPLIER`
3. **预期**：返回 403 错误："该配置由平台统一管理（仅管理员可修改）"
4. **验证**：后端拒绝修改请求

### 测试场景3：管理员在非全局策略账号修改核心策略参数
1. 管理员登录
2. 切换到非全局策略账号（如 account_id=2）
3. 尝试修改 `ATR_STOP_LOSS_MULTIPLIER`
4. **预期**：返回 403 错误："该配置由全局策略账号 #1 统一管理，请切换到该账号修改"
5. **验证**：后端拒绝修改请求

### 测试场景4：管理员在全局策略账号修改核心策略参数
1. 管理员登录
2. 切换到全局策略账号（account_id=1）
3. 修改 `ATR_STOP_LOSS_MULTIPLIER = 2.5`
4. **预期**：修改成功
5. **验证**：所有账户的交易系统都会使用新的值（通过 `config_manager.get_trading_config()` 读取）

---

## 🔍 代码检查清单

- [x] `backend/config_manager.py` - 配置读取逻辑使用全局账号
- [x] `backend/api/routes/config.py` - API权限控制
- [x] `frontend/src/components/ConfigPanel.jsx` - 前端配置页面（依赖后端过滤）
- [x] `frontend/src/components/GlobalConfig.jsx` - 管理员全局配置页面

---

## ✅ 最终结论

1. ✅ **所有用户下的账户都使用全局策略配置**
   - 通过 `config_manager.get_trading_config()` 的 `eff_get()` 函数实现
   - 核心策略参数从全局账号（account_id=1）读取
   - 风险旋钮从当前账号读取

2. ✅ **普通用户无法通过自己的配置直接影响核心策略参数**
   - 前端：只能看到风险旋钮
   - 后端：尝试修改核心参数会返回 403 错误
   - 即使数据库中有值，读取时也会从全局账号读取

3. ✅ **管理员权限控制**
   - 管理员在非全局策略账号时，也只能修改风险旋钮
   - 只有管理员在全局策略账号时，才能修改核心策略参数

---

## 📝 注意事项

1. **全局策略账号ID**：默认是 `account_id=1`，可通过环境变量 `ATS_GLOBAL_STRATEGY_ACCOUNT_ID` 修改

2. **配置缓存**：配置存储在 Redis 中，修改后需要确保 Redis 缓存已更新

3. **配置生效**：修改全局策略配置后，所有账户的交易系统会在下次 `reload_from_redis()` 时读取新值

4. **风险旋钮的作用**：虽然核心策略参数是全局的，但每个账户可以通过风险旋钮控制：
   - 仓位大小（MAX_POSITION_PERCENT）
   - 交易频率（MAX_DAILY_ENTRIES）
   - 同时持仓数量（MAX_OPEN_POSITIONS）
   - 是否启用自动交易（AUTO_TRADE_ENABLED）

---

## 🎯 建议

1. **定期检查**：定期验证全局策略账号的配置是否正确
2. **配置快照**：在修改全局策略配置前，先导出配置快照作为备份
3. **测试环境**：在测试环境验证配置修改的效果，再应用到生产环境
4. **文档更新**：修改配置后，及时更新相关文档
