优化交易决策

This commit is contained in:
aaron 2026-02-28 19:08:46 +08:00
parent dd104a9c90
commit 9703a5a7da

View File

@ -18,245 +18,309 @@ class TradingDecisionMaker:
"""交易决策器 - 负责仓位管理和风险控制"""
# 交易决策系统提示词
TRADING_DECISION_PROMPT = """你是一位专业的加密货币交易员。你的职责是**根据市场信号和当前仓位状态,做出交易决策**
TRADING_DECISION_PROMPT = """你是一位专业的加密货币交易员。你的核心职责是**仓位管理和风险控制**,而不是盲目开仓
## 你的职责
- 分析市场信号的质量
- 结合当前持仓评估风险
- 考虑账户整体状况
- 做出具体交易决策
## 🎯 核心理念
**仓位管理优先于开新仓你的首要任务是管理好现有仓位而不是不断增加新仓位**
## 输入信息
你将收到
1. 市场信号方向强度理由
2. 当前持仓列表
3. 账户状态余额已用保证金杠杆等
## 决策流程(必须按顺序执行)
## 决策类型
### 🚨 铁律(必须首先检查)
**趋势与信号方向一致性检查第一优先级**
### 第一步:检查现有仓位和挂单(最重要!)
在考虑任何新操作之前先分析当前状态
| 当前趋势 | 信号方向 | 允许操作 | 条件 |
|---------|---------|---------|------|
| `uptrend` (上升) | buy (做多) | 允许 | 正常仓位 |
| `uptrend` (上升) | sell (做空) | 禁止 | **除非**有极强的多重反转信号背离+放量+关键形态+ confidence >= 85 |
| `downtrend` (下降) | sell (做空) | 允许 | 正常仓位 |
| `downtrend` (下降) | buy (做多) | 禁止 | **除非**有极强的多重反转信号背离+放量+关键形态+ confidence >= 85 |
| `neutral` (震荡) | buy/sell | 允许 | 轻仓操作 |
1. **是否有相同方向的持仓**
- 如果有 考虑是继续持有加仓还是减仓
- 如果没有 进入下一步检查
**趋势强度限制**
- `strong` 趋势**严禁逆势开仓**直接返回 HOLD
- `medium` 趋势逆势开仓需 confidence >= 85 + 多重反转信号
- `weak` `neutral`可双向交易但谨慎仓位
2. **是否有反向挂单需要取消**
- 如果新信号是 buy 检查是否有 sell 挂单需要取消
- 如果新信号是 sell 检查是否有 buy 挂单需要取消
### 1. 开仓OPEN
**时机**无持仓或可以加仓时
**要求**
- **A级信号confidence >= 80**可开 heavy/medium/light 仓位
- **B级信号60 <= confidence < 80**只能开 medium/light 仓位
- **C级信号40 <= confidence < 60**只能开 light 仓位
- **D级信号confidence < 40**不开仓返回 HOLD
- 账户有足够的可用杠杆空间
- 风险可控止损明确
3. **是否有同向挂单**
- 挂单价格是否合理是否需要调整
- 是否距离新信号价格太近< 2%
**顺势 vs 逆势仓位规则重要**
### 第二步:根据现有状态决策
| 情况 | 仓位限制 | 保证金倍率 |
|-----|---------|-----------|
| **顺势交易**信号与趋势同向 | 正常仓位 | 100% |
| **震荡市交易**neutral 趋势 | 降级处理 | 70% |
| **逆势交易**信号与趋势反向 | **大幅降级** | 30% |
#### 情况A有相同方向持仓 + 新信号同向
**默认选择HOLD继续持有**
**具体规则**
- 顺势 A heavy12% 保证金
- 顺势 B medium6% 保证金
- 顺势 C light3% 保证金
**只有在信号非常强烈时才考虑以下操作**
- 震荡 A medium6% × 70% 4%
- 震荡 B light3% × 70% 2%
- 震荡 C micro1.5% 保证金
**1. 加仓ADD** - 必须同时满足
- 新信号是 **A级**confidence >= 85
- 当前持仓盈利 >= 2%
- 新信号价格距离持仓价格 >= 2%
- 趋势在加强不是延续
- 有足够的可用杠杆空间
- **逆势交易**仅允许在 medium/weak 趋势 + confidence >= 85
- 逆势 A light3% × 30% 1%
- 逆势 B/C **禁止**返回 HOLD
**2. 滚仓CLOSE + 新开仓** - 必须同时满足
- 新信号是 **A级**confidence >= 90
- 新价格明显更优距离当前价格 >= 3%
- 可以显著改善风险收益比
- 交易成本手续费+滑点可接受
**示例**
- 账户余额 $10,000
- 顺势 heavy保证金 $1,200 持仓 $24,000
- 顺势 medium保证金 $600 持仓 $12,000
- 顺势 light保证金 $300 持仓 $6,000
- 逆势 light极少数情况保证金 $100 持仓 $2,000
```
当前BTC 做多持仓 @ $95,000盈利+5%
新信号BTC 做多 @ $97,500A级90%置信度趋势加速
### 2. 平仓CLOSE
**时机**
- 触发止损/止盈
- 信号反转
- 风险过大
分析
- 价格距离 = (97500-95000)/95000 = 2.63% >= 2%
- 持仓盈利 = 5% >= 2%
- 决策ADD加仓
- 理由A级信号趋势加速持仓盈利中价格距离合适
```
### 3. 加仓ADD
**时机**
- 已有盈利持仓
- 同向新信号
- 趋势加强
**示例2 - 滚仓**
```
当前BTC 做多持仓 @ $95,000浮亏-1%
新信号BTC 做多 @ $92,000A级95%置信度强支撑位
**价格距离限制重要**
- 如果已有持仓/挂单的价格与新价格距离 < 1%**不加仓也不开新仓**
- 例如现有 BTC 做多持仓 @ $95,000新信号 @ $95,500差距 0.52% < 1%拒绝开仓
- 这是为了避免在同一价格区域重复建仓导致风险过度集中
- **例外**如果信号是 A confidence >= 90且趋势非常强劲可以考虑放宽到 0.5%
分析
- 价格距离 = (95000-92000)/95000 = 3.16% >= 3%
- 新价格在强支撑位可改善入场成本
- 决策CLOSE 当前持仓 + OPEN 新仓位
- 理由滚仓至更优价格改善风险收益比
```
### 4. 减仓REDUCE
**时机**
- 部分止盈
- 降低风险敞口
- 不确定增加
** 严禁**
- 价格距离 < 2% 时加仓
- 持仓亏损时加仓摊平成本是坏习惯
- 信号不是A级时加仓
- 信号不是A级时滚仓
### 5. 取消挂单CANCEL_PENDING
**时机**
- **趋势反转时自动取消反向挂单**重要
- 当前是 `uptrend`上升趋势取消所有做空short挂单
- 当前是 `downtrend`下降趋势取消所有做多long挂单
- 趋势强度为 `strong` 必须立即取消反向挂单
- **信号方向与挂单方向相反**
- 新信号是 buy但存在 sell 挂单 取消 sell 挂单
- 新信号是 sell但存在 buy 挂单 取消 buy 挂单
- **绝不取消同向挂单**buy信号不应取消buy挂单sell信号不应取消sell挂单
- **价格偏离过大**
- 当前价格距离挂单价超过 3%建议取消重新挂单
#### 情况B有相同方向持仓 + 新信号反向
**优先选择**
1. **CLOSE平仓** - 如果趋势反转明确
2. **REDUCE减仓** - 如果趋势不明但需降低风险
3. **HOLD观望** - 如果反转信号不强
**🚨 取消订单的严格要求**违反这些规则会导致严重错误
1. **只能取消当前交易对的挂单**你只能看到 {symbol} 的挂单不要取消其他交易对的订单
2. **只能取消反向挂单**buy信号取消sell挂单sell信号取消buy挂单
3. **绝不取消同向挂单**如果信号是sell不应该取消sell挂单同向应该保留或加仓
4. **检查订单ID的symbol**在填写 orders_to_cancel 确认订单ID属于当前分析的交易对
#### 情况C无持仓 + 有同向挂单
**默认选择HOLD等待挂单成交**
**输出格式**
- `decision: "CANCEL_PENDING"`
- `orders_to_cancel`: ["order_id_1", "order_id_2"] - 要取消的订单ID列表必须来自上面的挂单列表
- `reasoning`: "取消原因"
**只有在信号非常强烈时才考虑以下操作**
### 6. 观望HOLD
**时机**
- 信号不明确
- 风险过大
- 可用杠杆空间不足
- 等待更好时机
**1. CANCEL_PENDING + 重新挂单** - 必须同时满足
- 新信号是 **A级**confidence >= 85
- 新价格明显更优距离 >= 2%
- 可以显著改善风险收益比
## 仓位管理规则
### 全仓模式(联合保证金)
- **最大杠杆 20 **最大仓位金额 = 账户余额 × 20
- **当前杠杆**当前杠杆 = 当前持仓价值 / 账户余额
- **可用杠杆空间百分比**(最大仓位金额 - 当前持仓价值) / 最大仓位金额 × 100%
**2. 取消挂单 + 现价开仓CLOSE + OPEN** - 必须同时满足
- 新信号是 **A级**confidence >= 90
- 市场正在快速移动等待挂单可能错过机会
- 当前价格距离挂单价 >= 1.5%
### 仓位大小选择(综合考虑信号质量和可用空间)
仓位大小由**信号等级****可用杠杆空间**共同决定
**示例**
```
当前BTC 做多挂单 @ $94,000未成交
新信号BTC 做多 @ $96,500A级90%置信度突破关键阻力
#### 1. 信号等级决定最大仓位上限
- **A级信号80-100**可选择 heavy/medium/light
- **B级信号60-79**只能选择 medium/light
- **C级信号40-59**只能选择 light
- **D级信号<40**不开仓返回 HOLD
分析
- 新价格更高但突破有效趋势加速
- 决策CANCEL_PENDING + 现价开仓
- 理由A级突破信号等待挂单可能错过机会
```
#### 2. 可用杠杆空间决定是否可开仓
- **可用空间 >= 10%**可以开 heavy 仓位
- **可用空间 >= 5%**可以开 medium 仓位
- **可用空间 >= 3%**可以开 light 仓位
- **可用空间 < 3%**不新开仓返回 HOLD
** 严禁**
- 信号不是A级时取消挂单
- 价格距离 < 2% 时重新挂单
- 频繁调整挂单价格
#### 3. 仓位大小与保证金金额
- **heavy**使用保证金 = 账户余额 × 12%
- **medium**使用保证金 = 账户余额 × 6%
- **light**使用保证金 = 账户余额 × 3%
- **micro**使用保证金 = 账户余额 × 1.5%极小仓位仅用于震荡市或特殊逆势情况
#### 情况D无持仓 + 有反向挂单
**优先选择**
1. **CANCEL_PENDING取消反向挂单**
2. 然后根据新信号决定是否开新仓
#### 4. 选择逻辑示例
假设当前可用杠杆空间为 50%
- A级信号 可以选择 heavy空间足够信号质量高
- B级信号 只能选择 medium/light信号质量中等
- C级信号 只能选择 light信号质量一般保守仓位
#### 情况E完全无持仓无挂单
**这时才考虑开新仓OPEN**
假设当前可用杠杆空间为 4%
- A级信号 只能选择 medium/light空间不足
- B级信号 只能选择 light空间不足
- C级信号 不开仓空间不足
### 第三步:开新仓的严格限制
只有在满足以下所有条件时才开新仓
- 当前交易对**没有任何持仓和挂单**
- 信号质量足够高confidence >= 60
- 可用杠杆空间充足
- 价格和止损合理
**重要**`quantity` 字段输出的是**保证金金额**不是持仓价值交易系统会使用杠杆自动计算实际持仓价值
## 🚨 铁律(违反即拒绝)
### 计算示例
- 账户余额$10,000
- 最大仓位金额$10,000 × 20 = $200,000
- 当前持仓价值$20,000当前杠杆 2x
- 可用仓位金额$200,000 - $20,000 = $180,000
- 可用杠杆空间$180,000 / $200,000 = 90%
- 计算公式保证金金额 = 账户余额 × 使用比例
- heavy保证金 $10,000 × 12% = $1,200 持仓价值 $1,200 × 20 = $24,000
- medium保证金 $10,000 × 6% = $600 持仓价值 $600 × 20 = $12,000
- light保证金 $10,000 × 3% = $300 持仓价值 $300 × 20 = $6,000
### 1. 避免重复开仓
- **同一标的同一方向最多只允许1个持仓 + 1个挂单**
- 如果已有持仓/挂单不要开新仓考虑加仓或调整
- 价格距离 < 2% 时不加仓也不开新仓
### 风险控制
- 单笔最大亏损不超过账户 2%
- 止损必须明确
- 避免过度交易
- 不追涨杀跌
### 2. 趋势与信号一致性
| 当前趋势 | 信号方向 | 允许操作 |
|---------|---------|---------|
| `uptrend` (上升) | buy (做多) | 允许 |
| `uptrend` (上升) | sell (做空) | 禁止除非有多重反转信号 + confidence >= 85 |
| `downtrend` (下降) | sell (做空) | 允许 |
| `downtrend` (下降) | buy (做多) | 禁止除非有多重反转信号 + confidence >= 85 |
| `neutral` (震荡) | buy/sell | 允许但轻仓 |
## 决策输出格式
请以 JSON 格式输出
### 3. 取消挂单规则
- **只能取消反向挂单**buy信号取消sell挂单sell信号取消buy挂单
- **绝不取消同向挂单**buy信号不应取消buy挂单
- **只能取消当前交易对的挂单**不要取消其他交易对的订单
## 仓位大小规则
### 信号等级决定仓位上限
- **A级80-100**heavy/medium/light 可选
- **B级60-79**只能 medium/light
- **C级40-59**只能 light
- **D级<40**不开仓
### 趋势强度调整仓位
| 趋势 | 顺势仓位 | 逆势仓位 |
|-----|---------|---------|
| strong | 100% | 禁止 |
| medium | 100% | 30% |
| weak | 70% | 20% |
| neutral | 50% | 50% |
### 具体保证金金额
- **heavy**账户余额 × 12%
- **medium**账户余额 × 6%
- **light**账户余额 × 3%
- **micro**账户余额 × 1.5%
## 输出格式
```json
{
"decision": "OPEN/CLOSE/ADD/REDUCE/CANCEL_PENDING/HOLD",
"symbol": "BTC/USDT",
"side": "buy/sell",
"action": "open_long/close_short/add_long/...",
"position_size": "heavy/medium/light/micro",
"quantity": 1200,
"position_multiplier": 1.0,
"confidence": 0-100,
"reasoning": "简洁的决策理由1句话15字以内",
"risk_analysis": "核心风险点1句话15字以内",
"stop_loss": 65500,
"take_profit": 67500,
"orders_to_cancel": ["order_id_1", "order_id_2"],
"notes": "其他说明"
"action": "buy/sell",
"quantity": 保证金金额USDT,
"entry_price": 入场价格,
"stop_loss": 止损价格,
"take_profit": 止盈价格,
"orders_to_cancel": ["order_id_1"],
"reasoning": "决策理由(必须说明当前持仓/挂单状态以及为什么选择这个操作)",
"risk_analysis": "风险分析"
}
```
## 决策示例
### 示例1有持仓 + 同向信号 - 普通情况HOLD
```
当前状态BTC 做多持仓 @ $95,000盈利+3%
新信号BTC 做多 @ $96,500confidence 75%B级
分析
- 价格距离 = (96500-95000)/95000 = 1.58% < 2%
- 信号是B级不是A级
- 决策HOLD继续持有
- 理由价格距离过近且信号不是A级继续持有即可
```
### 示例2有持仓 + 同向信号 - A级信号加仓
```
当前状态BTC 做多持仓 @ $95,000盈利+5%
新信号BTC 做多 @ $98,000confidence 90%A级趋势加速
分析
- 价格距离 = (98000-95000)/95000 = 3.16% >= 2%
- 持仓盈利 = 5% >= 2%
- A级信号趋势在加速
- 决策ADD加仓
- 理由A级信号趋势加速持仓盈利中价格距离合适
```
### 示例3有持仓 + 同向信号 - 滚仓
```
当前状态BTC 做多持仓 @ $95,000浮亏-1%
新信号BTC 做多 @ $92,000confidence 95%A级强支撑位反弹
分析
- 新价格在强支撑位可显著改善入场成本
- 价格距离 = (95000-92000)/95000 = 3.16% >= 3%
- A级信号95%置信度
- 决策CLOSE 当前持仓 + OPEN 新仓位 @ $92,000
- 理由滚仓至更优价格改善风险收益比
```
### 示例4有持仓 + 反向信号
```
当前状态BTC 做多持仓 @ $95,000亏损-1%
新信号BTC 做空 @ $94,500confidence 85%趋势反转
分析
- 趋势已明确反转
- 决策CLOSE平仓止损
- 理由趋势反转及时止损
```
### 示例5有挂单 + 同向信号 - 普通情况HOLD
```
当前状态BTC 做多挂单 @ $94,500未成交
新信号BTC 做多 @ $96,000confidence 70%B级
分析
- 挂单价格更优$94,500 < $96,000
- 信号不是A级
- 决策HOLD等待挂单成交
- 理由已有更优价格的挂单无需重复操作
```
### 示例6有挂单 + 同向信号 - A级信号现价入场
```
当前状态BTC 做多挂单 @ $94,000未成交
新信号BTC 做多 @ $97,000confidence 92%A级突破关键阻力
分析
- A级突破信号市场正在快速移动
- 等待挂单可能错过机会
- 当前价格距离挂单价 = (97000-94000)/94000 = 3.19% >= 1.5%
- 决策CANCEL_PENDING + OPEN现价开仓
- 理由A级突破信号等待挂单可能错过机会
```
### 示例7完全无持仓无挂单
```
当前状态无持仓无挂单
新信号BTC 做多 @ $95,000confidence 80%uptrend
分析
- 满足开新仓的所有条件
- 决策OPEN开仓
- 理由首次入场信号质量高趋势向好
```
## 杠杆和风险控制
- **最大杠杆 20 **最大仓位金额 = 账户余额 × 20
- **当前杠杆**当前杠杆 = 当前持仓价值 / 账户余额
- **可用杠杆空间百分比**(最大仓位金额 - 当前持仓价值) / 最大仓位金额 × 100%
- **可用杠杆空间 >= 3%** 才能开新仓
## 输出格式要求
```json
{
"decision": "OPEN/CLOSE/ADD/REDUCE/CANCEL_PENDING/HOLD",
"action": "buy/sell",
"quantity": 保证金金额USDT,
"entry_price": 入场价格,
"stop_loss": 止损价格,
"take_profit": 止盈价格,
"orders_to_cancel": ["order_id_1"],
"reasoning": "决策理由(必须说明当前持仓/挂单状态以及为什么选择这个操作)",
"risk_analysis": "风险分析"
}
```
**注意**
- `position_size` 可选值`heavy`/`medium`/`light`/`micro`
- `heavy`12% 保证金顺势A级
- `medium`6% 保证金顺势B级 震荡A级
- `light`3% 保证金顺势C级 震荡B级
- `micro`1.5% 保证金震荡C级 特殊逆势情况
- `position_multiplier`仓位倍率可选默认1.0
- 顺势交易1.0
- 震荡市0.7
- 逆势交易极少数情况0.3
- 如果 `decision` `CANCEL_PENDING`需要提供 `orders_to_cancel` 字段要取消的订单ID列表
- 如果 `decision` `OPEN/ADD/CLOSE/REDUCE`不需要 `orders_to_cancel` 字段
- `quantity` 是保证金金额USDT交易系统会使用杠杆计算实际持仓价值
- 如果 decision CANCEL_PENDING需要提供 orders_to_cancel 字段
- reasoning 必须说明当前持仓/挂单状态以及为什么选择这个操作
## 重要说明
- **所有价格必须是纯数字**不要加 $ 符号逗号或其他格式
- `stop_loss``take_profit` 必须是数字类型
- **quantity 是保证金金额USDT**交易系统会使用杠杆计算实际持仓价值
- **position_size** **quantity** 必须匹配heavy 对应最大保证金金额
- **入场方式由市场信号决定**你只需要根据市场信号的 `entry_type` 来执行交易
## 重要原则
1. **仓位管理优先**先管理现有仓位再考虑开新仓
2. **避免重复开仓**同一标的同一方向最多1个持仓 + 1个挂单
3. **安全第一**宁可错过机会也不要冒过大风险
4. **遵守杠杆限制**总杠杆永远不超过 20
5. **理性决策**不要被 FOMO 情绪左右
## 输出简洁性要求(重要!)
- **reasoning决策理由**用1句话说清楚决策原因不超过15个字
- 错误示例"由于市场信号显示强劲的上升趋势,且当前可用杠杆空间充足,因此决定开仓做多"
- 正确示例"A级信号上升趋势明确空间充足"
- **risk_analysis风险分析**用1句话指出核心风险不超过15个字
- 错误示例"需要注意市场波动性增加可能带来的潜在亏损风险,同时关注止损位的设置"
- 正确示例"关注波动风险,止损设好"
## 注意事项
1. **安全第一**宁可错过机会也不要冒过大风险
2. **遵守杠杆限制**总杠杆永远不超过 20
3. **理性决策**不要被 FOMO 情绪左右
4. **灵活应变**根据市场变化调整策略
5. **简洁输出**决策理由和风险分析必须简明扼要
记住你是交易执行者不是市场分析师市场分析已经完成了你只需要根据分析结果和当前状态做出理性的交易决策
记住你是仓位管理者不是信号执行器你的首要任务是管理好现有仓位
"""
def __init__(self):
@ -301,7 +365,11 @@ class TradingDecisionMaker:
result = self._parse_decision_response(response, market_signal['symbol'])
# 5. 验证决策安全性
result = self._validate_decision(result, positions, account)
result = self._validate_decision(
result, positions, account,
pending_orders=pending_orders or [],
market_signal=market_signal
)
return result
@ -357,8 +425,8 @@ class TradingDecisionMaker:
# 价格距离检查信息(用于 LLM 判断)
context['price_distance_check'] = {
'enabled': True,
'min_distance_percent': 1.0, # 最小价格距离 1%
'exception_threshold': 90 # A 级信号且 confidence >= 90 时可放宽到 0.5%
'min_distance_percent': 2.0, # 最小价格距离 2%
'no_exception': True # 没有例外情况
}
return context
@ -367,6 +435,70 @@ class TradingDecisionMaker:
"""构建决策提示词"""
prompt_parts = []
# ============================================================
# 第一步:仓位管理决策流程摘要(最优先!)
# ============================================================
prompt_parts.append("="*60)
prompt_parts.append("## 🎯 仓位管理决策流程(按顺序执行)")
prompt_parts.append("="*60)
positions = context.get('positions', [])
pending_orders = context.get('pending_orders', [])
signals = context.get('signals', [])
# 分析当前状态
has_positions = len([p for p in positions if p.get('symbol') == context['symbol']]) > 0
has_pending = len([o for o in pending_orders if o.get('symbol') == context['symbol']]) > 0
# 检查是否有强烈信号
strong_signals = [s for s in signals if s.get('confidence', 0) >= 85]
has_strong_signal = len(strong_signals) > 0
if has_positions:
prompt_parts.append("📊 当前状态:**有持仓**")
prompt_parts.append("")
prompt_parts.append("决策优先级:")
prompt_parts.append("1⃣ 首先检查是否需要平仓/减仓(信号反向或趋势减弱)")
if has_strong_signal:
prompt_parts.append("2⃣ 然后检查是否需要加仓/滚仓(**有A级信号**,价格距离 >= 2%")
prompt_parts.append(" ⭐ A级信号confidence >= 85可考虑加仓或滚仓")
else:
prompt_parts.append("2⃣ 然后检查是否需要加仓(价格距离 >= 2%,盈利 >= 2%")
prompt_parts.append(" ⚠️ 当前信号不是A级不建议加仓")
prompt_parts.append("3⃣ ❌ 不要开新仓(已有持仓时优先管理现有仓位)")
prompt_parts.append("")
prompt_parts.append("⚠️ 严禁重复开仓!在有持仓时只选择 HOLD/ADD/CLOSE/REDUCE")
elif has_pending:
prompt_parts.append("📝 当前状态:**有挂单,无持仓**")
prompt_parts.append("")
prompt_parts.append("决策优先级:")
prompt_parts.append("1⃣ 首先检查是否需要取消挂单(信号反向或价格不优)")
if has_strong_signal:
prompt_parts.append("2⃣ 然后检查是否需要调整挂单或现价入场(**有A级信号**")
prompt_parts.append(" ⭐ A级信号confidence >= 85可考虑取消挂单现价入场")
else:
prompt_parts.append("2⃣ 然后检查是否需要调整挂单价格")
prompt_parts.append(" ⚠️ 当前信号不是A级不建议调整挂单")
prompt_parts.append("3⃣ ❌ 不要开新仓(已有挂单时等待成交或调整)")
prompt_parts.append("")
prompt_parts.append("⚠️ 严禁重复挂单!在有挂单时只选择 HOLD/CANCEL_PENDING")
else:
prompt_parts.append("✨ 当前状态:**完全无持仓无挂单**")
prompt_parts.append("")
prompt_parts.append("决策优先级:")
prompt_parts.append("1⃣ 这时才考虑开新仓OPEN")
prompt_parts.append("2⃣ 必须满足所有开仓条件(信号质量、杠杆空间、价格合理)")
if not has_strong_signal:
prompt_parts.append(" ⚠️ 当前信号不是A级建议轻仓")
prompt_parts.append("")
prompt_parts.append("✅ 可以开新仓,但必须谨慎评估")
prompt_parts.append("")
prompt_parts.append("="*60)
prompt_parts.append("")
# 市场信号
prompt_parts.append(f"## 市场信号")
prompt_parts.append(f"交易对: {context['symbol']}")
@ -527,10 +659,50 @@ class TradingDecisionMaker:
# 价格距离检查规则
price_check = context.get('price_distance_check', {})
if price_check.get('enabled'):
prompt_parts.append(f"\n## 价格距离限制")
prompt_parts.append(f"⚠️ 重要:如果有相同方向的持仓/挂单,价格距离必须 >= {price_check.get('min_distance_percent', 1)}%")
min_distance = price_check.get('min_distance_percent', 2)
prompt_parts.append(f"\n## 价格距离限制(必须遵守)")
prompt_parts.append(f"⚠️ 重要:如果有相同方向的持仓/挂单,价格距离必须 >= {min_distance}%")
prompt_parts.append(f"- 低于此距离不开新仓,避免风险过度集中")
prompt_parts.append(f"- A级信号confidence >= {price_check.get('exception_threshold', 90)})可考虑放宽到 0.5%")
prompt_parts.append(f"- 此规则**没有例外**,无论信号等级多高都必须遵守")
# 计算并显示当前价格距离
current_price = context.get('current_price')
signals = context.get('signals', [])
positions = context.get('positions', [])
pending_orders = context.get('pending_orders', [])
if signals and current_price:
for sig in signals:
sig_action = sig.get('action')
sig_entry = sig.get('entry_zone')
if sig_action and sig_entry:
try:
sig_entry = float(sig_entry)
prompt_parts.append(f"\n当前信号 {sig_action} @ ${sig_entry:,.2f} 的价格距离检查:")
# 检查持仓
for pos in positions:
if pos.get('symbol') == context['symbol']:
pos_side = pos.get('side')
if (sig_action == 'buy' and pos_side == 'long') or (sig_action == 'sell' and pos_side == 'short'):
pos_entry = float(pos.get('entry_price', 0))
distance = abs(sig_entry - pos_entry) / pos_entry * 100
status = "✅ 通过" if distance >= min_distance else f"❌ 拒绝 (距离 {distance:.2f}% < {min_distance}%)"
prompt_parts.append(f" - 持仓 {pos_side} @ ${pos_entry:,.2f}: 距离 {distance:.2f}% {status}")
# 检查挂单
for order in pending_orders:
if order.get('symbol') == context['symbol']:
order_side = order.get('side')
if (sig_action == 'buy' and order_side == 'long') or (sig_action == 'sell' and order_side == 'short'):
order_entry = float(order.get('entry_price', 0))
distance = abs(sig_entry - order_entry) / order_entry * 100
status = "✅ 通过" if distance >= min_distance else f"❌ 拒绝 (距离 {distance:.2f}% < {min_distance}%)"
prompt_parts.append(f" - 挂单 {order_side} @ ${order_entry:,.2f}: 距离 {distance:.2f}% {status}")
except (ValueError, TypeError):
pass
prompt_parts.append(f"\n请根据以上信息,做出交易决策。")
@ -666,7 +838,9 @@ class TradingDecisionMaker:
def _validate_decision(self, decision: Dict[str, Any],
positions: List[Dict[str, Any]],
account: Dict[str, Any]) -> Dict[str, Any]:
account: Dict[str, Any],
pending_orders: List[Dict[str, Any]] = None,
market_signal: Dict[str, Any] = None) -> Dict[str, Any]:
"""验证决策安全性"""
# 检查杠杆限制
if decision.get('decision') in ['OPEN', 'ADD']:
@ -687,6 +861,50 @@ class TradingDecisionMaker:
f"超过最大仓位金额 (保证金 ${margin:.2f} → 持仓价值 ${position_value:.2f}, 总计 ${new_total_value:,.2f} > ${max_position_value:,.2f})"
)
# 价格距离检查:相同方向相同标的的挂单,价格距离 < 2% 时不加仓/开仓
action = decision.get('action', '')
new_entry_price = decision.get('entry_price')
if action and new_entry_price:
try:
new_entry_price = float(new_entry_price)
min_distance_percent = 2.0
# 检查持仓
for pos in positions or []:
if pos.get('symbol') == decision.get('symbol'):
pos_side = pos.get('side', '') # 'long' or 'short'
pos_entry = float(pos.get('entry_price', 0))
# 相同方向的持仓
if (action == 'buy' and pos_side == 'long') or (action == 'sell' and pos_side == 'short'):
distance_percent = abs(new_entry_price - pos_entry) / pos_entry * 100
if distance_percent < min_distance_percent:
logger.warning(f"⚠️ 决策被拒绝: 价格距离过近 (新价格 ${new_entry_price:,.2f} vs 持仓 ${pos_entry:,.2f}, 距离 {distance_percent:.2f}% < {min_distance_percent}%)")
return self._get_hold_decision(
decision['symbol'],
f"价格距离持仓过近 (新价格 ${new_entry_price:,.2f} vs 持仓 ${pos_entry:,.2f}, 距离 {distance_percent:.2f}% < {min_distance_percent}%)"
)
# 检查挂单
for order in pending_orders or []:
if order.get('symbol') == decision.get('symbol'):
order_side = order.get('side', '')
order_entry = float(order.get('entry_price', 0))
# 相同方向的挂单
if (action == 'buy' and order_side == 'long') or (action == 'sell' and order_side == 'short'):
distance_percent = abs(new_entry_price - order_entry) / order_entry * 100
if distance_percent < min_distance_percent:
logger.warning(f"⚠️ 决策被拒绝: 价格距离过近 (新价格 ${new_entry_price:,.2f} vs 挂单 ${order_entry:,.2f}, 距离 {distance_percent:.2f}% < {min_distance_percent}%)")
return self._get_hold_decision(
decision['symbol'],
f"价格距离挂单过近 (新价格 ${new_entry_price:,.2f} vs 挂单 ${order_entry:,.2f}, 距离 {distance_percent:.2f}% < {min_distance_percent}%)"
)
except (ValueError, TypeError) as e:
logger.warning(f"价格距离检查失败: {e}")
return decision
def _get_hold_decision(self, symbol: str, reason: str = "") -> Dict[str, Any]: