This commit is contained in:
薇薇安 2026-01-27 11:11:03 +08:00
parent 9fe028d704
commit 16c4cfbdd8
4 changed files with 486 additions and 6 deletions

View File

@ -0,0 +1,42 @@
-- 分步止盈状态细分添加新的exit_reason值支持
-- 执行时间2026-01-27
-- 1. 更新exit_reason字段注释说明新的状态值
ALTER TABLE `trades` MODIFY COLUMN `exit_reason` VARCHAR(50)
COMMENT '平仓原因: manual(手动), stop_loss(止损), take_profit(单次止盈), trailing_stop(移动止损), sync(同步), take_profit_partial_then_take_profit(第一目标止盈后第二目标止盈), take_profit_partial_then_stop(第一目标止盈后剩余仓位止损), take_profit_partial_then_trailing_stop(第一目标止盈后剩余仓位移动止损)';
-- 2. 验证字段长度是否足够VARCHAR(50)应该足够)
SELECT
COLUMN_NAME,
COLUMN_TYPE,
COLUMN_COMMENT
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'trades'
AND COLUMN_NAME = 'exit_reason';
-- 3. 查看当前exit_reason的分布情况用于验证
SELECT
exit_reason,
COUNT(*) as count,
ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM trades WHERE status = 'closed'), 2) as percentage
FROM
trades
WHERE
status = 'closed'
GROUP BY
exit_reason
ORDER BY
count DESC;
-- 说明:
-- 新的状态值:
-- - take_profit_partial_then_take_profit: 第一目标止盈50%仓位)后,剩余仓位第二目标止盈
-- - take_profit_partial_then_stop: 第一目标止盈50%仓位)后,剩余仓位止损(保本)
-- - take_profit_partial_then_trailing_stop: 第一目标止盈50%仓位)后,剩余仓位移动止损
--
-- 这些状态用于更准确地统计胜率和盈亏比:
-- - 第一目标止盈后剩余仓位止损,应该算作"部分成功"(第一目标已达成)
-- - 第一目标止盈后剩余仓位第二目标止盈,应该算作"完整成功"

View File

@ -0,0 +1,252 @@
# 分步止盈状态管理分析与优化方案2026-01-27
## 📊 日志分析
### 日志内容
```
2026-01-27 10:51:07 - AXLUSDT [实时监控] 触发第一目标止盈30%固定止盈,基于保证金):
当前盈亏=14.65% of margin >= 目标=12.00% of margin |
当前价=0.0890, 目标价=0.0887 |
将平掉50%仓位锁定30%盈利剩余50%追求更高收益
2026-01-27 10:51:07 - AXLUSDT [实时监控] 部分止盈成功: 平仓110.5000剩余110.7000
2026-01-27 10:51:07 - AXLUSDT [实时监控] 部分止盈后:剩余仓位止损移至成本价 0.0874(保本),
剩余50%仓位追求更高收益第二目标4.0:1盈亏比或更高
```
---
## 🔍 问题分析
### 问题1日志文案与实际配置不一致
**问题**
- 日志显示:"30%固定止盈"
- 实际目标12.00%说明配置已改为10%,但日志文案未更新)
**影响**
- 日志误导,不利于排查问题
**解决方案**
- 更新日志文案,使用实际配置值(动态读取`TAKE_PROFIT_PERCENT`
---
### 问题2状态管理不完整
**当前实现**
- 部分止盈后,设置`partialProfitTaken = True`
- 剩余仓位止损移至成本价(保本)
- 但最终平仓时,如果剩余仓位止损,会被标记为`stop_loss`
**问题**
- 无法区分"纯止损"和"第一目标止盈后剩余仓位止损"
- 影响胜率、盈亏比统计的准确性
**示例场景**
1. **场景A**第一目标止盈50%仓位)→ 剩余仓位第二目标止盈
- 当前标记:`take_profit`
- ✅ 合理
2. **场景B**第一目标止盈50%仓位)→ 剩余仓位止损(保本)
- 当前标记:`stop_loss`
- ❌ 不合理:实际上已经实现了第一目标止盈,应该算作"部分成功"
3. **场景C**第一目标止盈50%仓位)→ 剩余仓位移动止损
- 当前标记:`trailing_stop`
- ⚠️ 不完整:无法区分是"第一目标止盈后移动止损"还是"直接移动止损"
---
### 问题3统计准确性受影响
**当前统计**
- 胜率 = 盈利单数 / 总单数
- 盈亏比 = 平均盈利 / 平均亏损
**问题**
- 场景B第一目标止盈后剩余仓位止损被算作"亏损单"
- 但实际上已经实现了第一目标止盈50%仓位盈利),应该算作"部分成功"
**影响**
- 胜率被低估
- 盈亏比被低估
- 无法准确评估分步止盈策略的效果
---
## ✅ 优化方案
### 方案1细分订单状态推荐
**新增状态类型**
- `take_profit_partial`: 第一目标止盈部分平仓50%
- `take_profit_partial_then_take_profit`: 第一目标止盈后,剩余仓位第二目标止盈
- `take_profit_partial_then_stop`: 第一目标止盈后,剩余仓位止损(保本)
- `take_profit_partial_then_trailing_stop`: 第一目标止盈后,剩余仓位移动止损
**保留原有状态**
- `take_profit`: 单次止盈(未启用分步止盈)
- `stop_loss`: 止损
- `trailing_stop`: 移动止损
- `manual`: 手动平仓
- `sync`: 同步平仓
---
### 方案2添加阶段标记字段
**新增字段**
- `partial_profit_stage`: 分步止盈阶段
- `none`: 未启用分步止盈
- `partial_taken`: 第一目标已达成50%仓位已平)
- `full_taken`: 第二目标已达成(全部仓位已平)
**保留`exit_reason`字段**
- 用于标记最终平仓原因
**组合使用**
- `partial_profit_stage = 'partial_taken'` + `exit_reason = 'stop_loss'` → 第一目标止盈后剩余仓位止损
- `partial_profit_stage = 'partial_taken'` + `exit_reason = 'take_profit'` → 第一目标止盈后剩余仓位第二目标止盈
---
## 🎯 推荐方案方案1细分状态
### 理由
1. **更直观**:状态名称直接反映交易过程
2. **统计方便**:可以直接按状态统计,无需组合字段
3. **向后兼容**:保留原有状态,不影响现有统计
---
## 📊 状态映射表
| 场景 | 当前状态 | 优化后状态 | 说明 |
|------|----------|------------|------|
| 第一目标止盈50%)→ 第二目标止盈剩余50% | `take_profit` | `take_profit_partial_then_take_profit` | 完整成功 |
| 第一目标止盈50%)→ 剩余仓位止损(保本) | `stop_loss` | `take_profit_partial_then_stop` | 部分成功 |
| 第一目标止盈50%)→ 剩余仓位移动止损 | `trailing_stop` | `take_profit_partial_then_trailing_stop` | 部分成功 |
| 单次止盈(未启用分步止盈) | `take_profit` | `take_profit` | 保持 |
| 止损 | `stop_loss` | `stop_loss` | 保持 |
| 移动止损 | `trailing_stop` | `trailing_stop` | 保持 |
| 手动平仓 | `manual` | `manual` | 保持 |
| 同步平仓 | `sync` | `sync` | 保持 |
---
## 🔧 实施步骤
### 步骤1更新数据库结构
**SQL迁移脚本**
```sql
-- 更新exit_reason字段支持新的状态值
ALTER TABLE trades MODIFY COLUMN exit_reason VARCHAR(50);
-- 添加注释说明新状态
ALTER TABLE trades MODIFY COLUMN exit_reason VARCHAR(50)
COMMENT '平仓原因: manual, stop_loss, take_profit, trailing_stop, sync, take_profit_partial_then_take_profit, take_profit_partial_then_stop, take_profit_partial_then_trailing_stop';
```
---
### 步骤2更新代码逻辑
**修改位置**
- `trading_system/position_manager.py``_check_single_position`方法
- `trading_system/position_manager.py``close_position`方法
**修改内容**
1. 第一目标止盈时,记录`partial_profit_taken = True`
2. 剩余仓位平仓时,根据`partial_profit_taken`和实际平仓原因,设置正确的`exit_reason`
---
### 步骤3更新日志文案
**修改位置**
- `trading_system/position_manager.py``_check_single_position`方法
**修改内容**
- 动态读取`TAKE_PROFIT_PERCENT`配置,更新日志文案
---
### 步骤4更新统计逻辑
**修改位置**
- `backend/api/routes/stats.py`(如果存在)
- 前端统计展示逻辑
**修改内容**
- 统计时,将`take_profit_partial_then_*`状态归类为"部分成功"或"成功"
---
## 📊 统计分类建议
### 胜率统计
**成功单**
- `take_profit`
- `take_profit_partial_then_take_profit`
- `take_profit_partial_then_stop`(第一目标已达成,算作成功)
- `take_profit_partial_then_trailing_stop`(第一目标已达成,算作成功)
**失败单**
- `stop_loss`
- `trailing_stop`(如果未启用分步止盈)
**中性单**
- `manual`
- `sync`
---
### 盈亏比统计
**盈利单**
- 所有`take_profit*`状态
- 计算时,`take_profit_partial_then_stop`应该算作盈利(第一目标已达成)
**亏损单**
- `stop_loss`(纯止损)
- `trailing_stop`(如果未启用分步止盈)
---
## ⚠️ 注意事项
1. **向后兼容**
- 保留原有状态值,不影响现有数据
- 新状态仅用于新交易
2. **数据迁移**
- 如果需要,可以编写脚本将历史数据中的`take_profit`状态,根据是否有`partial_profit_taken`标记,转换为新状态
3. **日志优化**
- 更新日志文案,使用实际配置值
- 添加更详细的状态转换日志
---
## ✅ 总结
**问题**
- 日志文案与实际配置不一致
- 状态管理不完整,无法区分"纯止损"和"第一目标止盈后剩余仓位止损"
- 统计准确性受影响
**解决方案**
- 细分订单状态,新增`take_profit_partial_then_*`状态
- 更新日志文案,使用实际配置值
- 更新统计逻辑,将"第一目标止盈后剩余仓位止损"算作成功
**预期效果**
- 更准确的状态管理
- 更准确的胜率、盈亏比统计
- 更清晰的日志输出

View File

@ -0,0 +1,160 @@
# 分步止盈状态细分实施完成总结2026-01-27
## ✅ 已完成的优化
### 1. 日志文案优化
**修改位置**`trading_system/position_manager.py:2858-2865`
**优化内容**
- 动态读取`TAKE_PROFIT_PERCENT`配置值
- 更新日志文案使用实际配置值如10%)而不是硬编码的"30%"
**效果**
- 日志更准确,反映实际配置
- 配置变更后,日志自动更新
---
### 2. 订单状态细分
**新增状态类型**
- `take_profit_partial_then_take_profit`: 第一目标止盈后,剩余仓位第二目标止盈
- `take_profit_partial_then_stop`: 第一目标止盈后,剩余仓位止损(保本)
- `take_profit_partial_then_trailing_stop`: 第一目标止盈后,剩余仓位移动止损
**保留原有状态**
- `take_profit`: 单次止盈(未启用分步止盈)
- `stop_loss`: 止损
- `trailing_stop`: 移动止损
- `manual`: 手动平仓
- `sync`: 同步平仓
---
### 3. 代码修改位置
#### 修改1第二目标止盈状态
**位置**`trading_system/position_manager.py:2923`
- 从`take_profit`改为`take_profit_partial_then_take_profit`
#### 修改2剩余仓位止损状态实时监控
**位置**`trading_system/position_manager.py:2832-2835`
- 检查`partial_profit_taken`如果为True设置`take_profit_partial_then_stop`
#### 修改3剩余仓位止损状态交易所止盈单检查
**位置**`trading_system/position_manager.py:1553-1555`
- 检查`partial_profit_taken`如果为True根据是否移动止损设置相应状态
#### 修改4剩余仓位移动止损状态实时监控
**位置**`trading_system/position_manager.py:2798-2800`
- 检查`partial_profit_taken`如果为True根据是否移动止损设置相应状态
---
### 4. 数据库迁移脚本
**文件**`backend/database/add_partial_profit_exit_reasons.sql`
**内容**
- 更新`exit_reason`字段注释,说明新的状态值
- 验证字段长度
- 查看当前状态分布
---
## 📊 状态映射表
| 场景 | 原状态 | 新状态 | 说明 |
|------|--------|--------|------|
| 第一目标止盈50%)→ 第二目标止盈剩余50% | `take_profit` | `take_profit_partial_then_take_profit` | 完整成功 |
| 第一目标止盈50%)→ 剩余仓位止损(保本) | `stop_loss` | `take_profit_partial_then_stop` | 部分成功 |
| 第一目标止盈50%)→ 剩余仓位移动止损 | `trailing_stop` | `take_profit_partial_then_trailing_stop` | 部分成功 |
| 单次止盈(未启用分步止盈) | `take_profit` | `take_profit` | 保持 |
| 止损 | `stop_loss` | `stop_loss` | 保持 |
| 移动止损 | `trailing_stop` | `trailing_stop` | 保持 |
| 手动平仓 | `manual` | `manual` | 保持 |
| 同步平仓 | `sync` | `sync` | 保持 |
---
## 🎯 统计分类建议
### 胜率统计
**成功单**
- `take_profit`
- `take_profit_partial_then_take_profit`(完整成功)
- `take_profit_partial_then_stop`(部分成功:第一目标已达成)
- `take_profit_partial_then_trailing_stop`(部分成功:第一目标已达成)
**失败单**
- `stop_loss`(纯止损)
- `trailing_stop`(如果未启用分步止盈)
**中性单**
- `manual`
- `sync`
---
### 盈亏比统计
**盈利单**
- 所有`take_profit*`状态
- 计算时,`take_profit_partial_then_stop`应该算作盈利(第一目标已达成)
**亏损单**
- `stop_loss`(纯止损)
- `trailing_stop`(如果未启用分步止盈)
---
## ⚠️ 注意事项
1. **数据库迁移**
- 执行`backend/database/add_partial_profit_exit_reasons.sql`
- 更新字段注释,说明新的状态值
2. **向后兼容**
- 保留原有状态值,不影响现有数据
- 新状态仅用于新交易
3. **统计逻辑更新**
- 前端统计展示需要更新,将`take_profit_partial_then_*`状态归类为"成功"或"部分成功"
---
## 📝 下一步
1. **执行数据库迁移**
```bash
mysql -u root -p auto_trade_sys < backend/database/add_partial_profit_exit_reasons.sql
```
2. **更新前端统计逻辑**
- 修改统计展示,将`take_profit_partial_then_*`状态归类为"成功"
- 可以添加"部分成功"分类,用于更详细的分析
3. **测试验证**
- 测试分步止盈场景,验证状态设置正确
- 验证统计结果是否准确
---
## ✅ 总结
**问题**
- 日志文案与实际配置不一致
- 状态管理不完整,无法区分"纯止损"和"第一目标止盈后剩余仓位止损"
- 统计准确性受影响
**解决方案**
- ✅ 更新日志文案,使用实际配置值
- ✅ 细分订单状态,新增`take_profit_partial_then_*`状态
- ✅ 更新代码逻辑,根据`partial_profit_taken`设置正确的状态
**预期效果**
- ✅ 更准确的状态管理
- ✅ 更准确的胜率、盈亏比统计
- ✅ 更清晰的日志输出

View File

@ -678,7 +678,7 @@ class PositionManager:
Args:
symbol: 交易对
reason: 平仓原因manual, stop_loss, take_profit, trailing_stop, sync
reason: 平仓原因manual, stop_loss, take_profit, trailing_stop, sync, take_profit_partial_then_take_profit, take_profit_partial_then_stop, take_profit_partial_then_trailing_stop
Returns:
是否成功
@ -1552,6 +1552,14 @@ class PositionManager:
# 直接比较当前盈亏百分比与止损目标(基于保证金)
if pnl_percent_margin <= -stop_loss_pct_margin:
should_close_due_to_sl = True
# ⚠️ 2026-01-27优化如果已部分止盈细分状态
partial_profit_taken = position_info.get('partialProfitTaken', False)
if partial_profit_taken:
if position_info.get('trailingStopActivated'):
exit_reason_sl = 'take_profit_partial_then_trailing_stop'
else:
exit_reason_sl = 'take_profit_partial_then_stop'
else:
exit_reason_sl = 'trailing_stop' if position_info.get('trailingStopActivated') else 'stop_loss'
# 计算持仓时间
@ -2797,6 +2805,13 @@ class PositionManager:
# 直接比较当前盈亏百分比与止损目标(基于保证金)
if pnl_percent_margin <= -stop_loss_pct_margin:
should_close_due_to_sl = True
# ⚠️ 2026-01-27优化如果已部分止盈细分状态
if partial_profit_taken:
if position_info.get('trailingStopActivated'):
exit_reason_sl = 'take_profit_partial_then_trailing_stop'
else:
exit_reason_sl = 'take_profit_partial_then_stop'
else:
exit_reason_sl = 'trailing_stop' if position_info.get('trailingStopActivated') else 'stop_loss'
# 计算持仓时间
@ -2829,6 +2844,11 @@ class PositionManager:
logger.warning(f" 移动止损: 已激活(从初始止损 {position_info.get('initialStopLoss', 'N/A')} 调整)")
logger.warning("=" * 80)
# ⚠️ 2026-01-27优化如果已部分止盈细分状态为"第一目标止盈后剩余仓位止损"
if partial_profit_taken:
exit_reason_sl = 'take_profit_partial_then_stop'
logger.info(f"{symbol} [实时监控] 第一目标止盈后,剩余仓位触发止损(保本)")
# ⚠️ 关键修复:止损必须立即执行,不受时间锁限制
if await self.close_position(symbol, reason=exit_reason_sl):
logger.info(f"{symbol} [实时监控] 止损平仓成功(不受时间锁限制)")
@ -2857,11 +2877,16 @@ class PositionManager:
# 直接比较当前盈亏百分比与第一目标(基于保证金)
if pnl_percent_margin >= take_profit_1_pct_margin:
# ⚠️ 2026-01-27优化动态读取配置值更新日志文案
take_profit_pct_config = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.10)
if take_profit_pct_config > 1:
take_profit_pct_config = take_profit_pct_config / 100.0
take_profit_pct_display = take_profit_pct_config * 100
logger.info(
f"{symbol} [实时监控] 触发第一目标止盈30%固定止盈,基于保证金): "
f"{symbol} [实时监控] 触发第一目标止盈({take_profit_pct_display:.1f}%固定止盈,基于保证金): "
f"当前盈亏={pnl_percent_margin:.2f}% of margin >= 目标={take_profit_1_pct_margin:.2f}% of margin | "
f"当前价={current_price_float:.4f}, 目标价={take_profit_1:.4f} | "
f"将平掉50%仓位锁定30%盈利剩余50%追求更高收益"
f"将平掉50%仓位,锁定{take_profit_pct_display:.1f}%盈利剩余50%追求更高收益"
)
# 部分平仓50%
partial_quantity = quantity * 0.5
@ -2917,7 +2942,8 @@ class PositionManager:
# 直接比较剩余仓位盈亏百分比与第二目标(基于保证金)
if remaining_pnl_pct_margin >= take_profit_2_pct_margin:
should_close = True
exit_reason = 'take_profit'
# ⚠️ 2026-01-27优化细分状态区分"第一目标止盈后第二目标止盈"
exit_reason = 'take_profit_partial_then_take_profit'
logger.info(
f"{symbol} [实时监控] 触发第二目标止盈4.0:1山寨币策略: "
f"剩余仓位盈亏={remaining_pnl_pct_margin:.2f}% of margin >= 目标={take_profit_2_pct_margin:.2f}% of margin | "