优化交易决策

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