修改
This commit is contained in:
parent
e6560b340d
commit
0a637053fc
@ -1679,7 +1679,7 @@ class CryptoAgent:
|
|||||||
|
|
||||||
def _validate_data(self, data: Dict[str, pd.DataFrame]) -> bool:
|
def _validate_data(self, data: Dict[str, pd.DataFrame]) -> bool:
|
||||||
"""验证数据完整性"""
|
"""验证数据完整性"""
|
||||||
required_intervals = ['5m', '15m', '1h', '4h']
|
required_intervals = ['1m', '5m', '15m', '30m', '1h']
|
||||||
for interval in required_intervals:
|
for interval in required_intervals:
|
||||||
if interval not in data or data[interval].empty:
|
if interval not in data or data[interval].empty:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@ -47,147 +47,156 @@ class MarketSignalAnalyzer:
|
|||||||
- **顺势而为**:在大趋势方向上寻找入场点
|
- **顺势而为**:在大趋势方向上寻找入场点
|
||||||
- **严控风险**:每次交易风险不超过本金的2%
|
- **严控风险**:每次交易风险不超过本金的2%
|
||||||
|
|
||||||
## 零、趋势方向判断(第一步,最重要!)
|
## 零、日内交易核心理念(必须遵守!)
|
||||||
**在分析任何信号之前,先判断当前趋势方向和强度。**
|
|
||||||
|
|
||||||
### 趋势判断标准(使用 EMA 和 均线系统)
|
### 🎯 日内交易的本质
|
||||||
**上升趋势(多头市场)**:
|
**日内交易 = 当日进出 + 快速获利 + 严控盈亏比**
|
||||||
- EMA20 > EMA50 > EMA200(短中长期均线多头排列)
|
|
||||||
- 价格站稳在 EMA20 之上
|
|
||||||
- MA5 > MA10 > MA20 > MA50
|
|
||||||
- 最近高点逐步抬高,低点也逐步抬高
|
|
||||||
|
|
||||||
**下降趋势(空头市场)**:
|
### ⚠️ 铁律(违反即失败)
|
||||||
- EMA20 < EMA50 < EMA200(短中长期均线空头排列)
|
1. **盈亏比第一**:所有交易必须满足盈亏比 ≥ 1:2,优选 1:3
|
||||||
- 价格持续在 EMA20 之下
|
- 盈亏比 = (目标盈利 - 入场价) / (入场价 - 止损价)
|
||||||
- MA5 < MA10 < MA20 < MA50
|
- 做多:目标价 > 入场价 > 止损价
|
||||||
- 最近高点逐步降低,低点也逐步降低
|
- 做空:目标价 < 入场价 < 止损价
|
||||||
|
- 如果盈亏比 < 1:2,**绝对不要开仓**
|
||||||
|
|
||||||
**震荡市(无明确趋势)**:
|
2. **快进快出**:
|
||||||
- 均线纠缠,无明显排列
|
- 单笔持仓不超过 4 小时
|
||||||
- 价格在 EMA20 上下波动
|
- 达到目标立即平仓,不贪心
|
||||||
- 高点低点无规律
|
- 未达到目标但超过 2 小时,考虑平仓观望
|
||||||
- 此时可双向交易,但降低仓位
|
|
||||||
|
|
||||||
### 趋势强度判断
|
3. **严格止损**:
|
||||||
- **强趋势**:均线完美排列 + 价格远离均线 + 成交量配合
|
- 止损幅度:1-2%(最大不超过 2%)
|
||||||
- **中等趋势**:均线有排列 + 价格偶尔回踩均线
|
- 触及止损立即离场,不要犹豫
|
||||||
- **弱趋势/震荡**:均线纠缠 + 价格在均线上下反复
|
- 不要移动止损(除非是移动止盈保护利润)
|
||||||
|
|
||||||
### 顺势交易规则(必须执行)
|
4. **日内平仓**:
|
||||||
| 当前趋势 | 允许操作 | 条件 |
|
- 不建议持仓过夜
|
||||||
|---------|---------|------|
|
- 收盘前 30 分钟逐步平仓
|
||||||
| **强上升趋势** | ✅ 只做多 | 回调到支撑位、RSI超卖区、金叉 |
|
- 避免隔夜风险
|
||||||
| **强上升趋势** | ❌ 严禁做空 | 除非出现明确的顶背离+放量反转信号 |
|
|
||||||
| **强下降趋势** | ✅ 只做空 | 反弹到阻力位、RSI超买区、死叉 |
|
|
||||||
| **强下降趋势** | ❌ 严禁做多 | 除非出现明确的底背离+放量反转信号 |
|
|
||||||
| **震荡市** | ✅ 双向交易 | 但降低仓位(轻仓),提高止损要求 |
|
|
||||||
| **趋势不明确** | ⚠️ 观望为主 | 等待趋势明确后再入场 |
|
|
||||||
|
|
||||||
### 逆势交易的条件(极其严格)
|
### 日内交易时间框架(调整后)
|
||||||
**只有在满足以下全部条件时,才允许考虑逆势交易:**
|
**主周期**:30m(日内趋势)
|
||||||
1. **多重反转信号**:
|
**入场周期**:15m(寻找入场点)
|
||||||
- 明确的背离(顶背离或底背离)
|
**精确入场**:5m(确认时机)
|
||||||
- 关键形态反转(头肩顶/底、双顶/底、吞没形态)
|
**超精确入场**:1m(最后确认,可选)
|
||||||
- 放量突破关键位
|
**趋势参考**:1h(当日大方向)
|
||||||
2. **多周期确认**:4h、1h、15m 三个周期同时出现反转信号
|
|
||||||
3. **风险收益比合理**:潜在盈利至少是风险的3倍以上
|
|
||||||
4. **降低仓位**:逆势交易必须轻仓(不超过顺势仓位的50%)
|
|
||||||
|
|
||||||
**如果不符合上述条件,即使有买入/卖出信号,也必须选择 hold(观望)。**
|
### 日内交易参数
|
||||||
|
| 参数 | 设定值 |
|
||||||
|
|------|--------|
|
||||||
|
| 止损幅度 | 1-2%(最大2%) |
|
||||||
|
| 目标盈利 | 2-3%(日内快速获利) |
|
||||||
|
| 盈亏比要求 | ≥ 1:2(优选1:3) |
|
||||||
|
| 单笔持仓时长 | 不超过4小时 |
|
||||||
|
| 仓位大小 | 轻仓为主(light/micro) |
|
||||||
|
|
||||||
## 零点五、趋势位置判断和左侧交易(短线交易核心)
|
## 零点一、趋势方向判断(简化版,适配日内)
|
||||||
|
**日内交易更关注 30m 和 15m,1h 作为大方向参考**
|
||||||
|
|
||||||
### 🚨 避免盲目追涨杀跌
|
### 快速趋势判断(30m + 15m)
|
||||||
**顺势交易不等于追涨杀跌!趋势到了晚期,要警惕反转。**
|
**看涨日内(做多为主)**:
|
||||||
|
- 30m: EMA20 > EMA50,价格在 EMA20 之上
|
||||||
|
- 15m: 短期均线向上,价格站上 EMA5
|
||||||
|
- 30m 和 15m 同向向上
|
||||||
|
|
||||||
### 趋势三阶段判断
|
**看跌日内(做空为主)**:
|
||||||
**上升趋势的三个阶段**:
|
- 30m: EMA20 < EMA50,价格在 EMA20 之下
|
||||||
1. **早期**(启动阶段):
|
- 15m: 短期均线向下,价格跌破 EMA5
|
||||||
- 均线刚开始多头排列
|
- 30m 和 15m 同向向下
|
||||||
- 价格刚刚站上所有均线
|
|
||||||
- 成交量温和放大
|
|
||||||
- ✅ 可以积极做多
|
|
||||||
|
|
||||||
2. **中期**(加速阶段):
|
**震荡日内(观望为主)**:
|
||||||
- 均线完美排列,价格远离均线
|
- 30m: 均线纠缠,价格反复穿越 EMA20
|
||||||
- 成交量持续放大
|
- 15m: 无明确方向
|
||||||
- RSI 在 50-70 之间
|
- 此时最好观望,或支撑位多、压力位空(轻仓)
|
||||||
- ✅ 可以顺势做多,但警惕超买
|
|
||||||
|
|
||||||
3. **晚期**(过度延伸):
|
### 日内顺势规则
|
||||||
- 价格严重偏离均线(> 5%)
|
| 30m 趋势 | 15m 趋势 | 允许操作 | 盈亏比要求 |
|
||||||
- RSI > 75(超买区)
|
|---------|----------|---------|-----------|
|
||||||
- 布林带开口极大,价格在上轨之外
|
| **上升** | 上升 | ✅ 做多 | ≥ 1:2 |
|
||||||
- 出现顶背离信号
|
| **上升** | 下跌 | ⚠️ 回调做多 | ≥ 1:3 |
|
||||||
- ❌ 不要追多,警惕反转
|
| **下降** | 下降 | ✅ 做空 | ≥ 1:2 |
|
||||||
|
| **下降** | 上升 | ⚠️ 反弹做空 | ≥ 1:3 |
|
||||||
|
| **震荡** | 任意 | ⚠️ 观望或轻仓 | ≥ 1:3 |
|
||||||
|
|
||||||
**下降趋势的三个阶段**:
|
## 零点五、日内交易实战策略
|
||||||
1. **早期**:均线刚开始空头排列,刚刚破位 → ✅ 可以积极做空
|
|
||||||
2. **中期**:均线完美空头排列,加速下跌 → ✅ 可以顺势做空,警惕超卖
|
|
||||||
3. **晚期**:价格严重偏离均线,RSI < 25 → ❌ 不要追空,警惕反弹
|
|
||||||
|
|
||||||
### 过度延伸的信号(必须警惕)
|
### 🎯 三种日内入场方式
|
||||||
|
|
||||||
**上涨过度延伸的信号**:
|
#### 策略1:突破追入(适合强势行情)
|
||||||
- RSI > 75 且出现顶背离
|
**什么时候追?**
|
||||||
- 价格偏离 MA5 > 5%
|
- 30m 和 15m 同向,趋势明确
|
||||||
- 布林带上轨之外,且开口极大
|
- 放量突破关键位(阻力/支撑)
|
||||||
- 连续 3 根以上大阳线
|
- 15m 或 5m 级别正在加速
|
||||||
- 极端放量后价格滞涨
|
|
||||||
- ⚠️ 这时不要追多,考虑减仓或做空
|
|
||||||
|
|
||||||
**下跌过度延伸的信号**:
|
**追入必须满足**:
|
||||||
- RSI < 25 且出现底背离
|
- ✅ 盈亏比 ≥ 1:2
|
||||||
- 价格偏离 MA5 > 5%
|
- ✅ 止损:1-2%
|
||||||
- 布林带下轨之外,且开口极大
|
- ✅ 目标:2-3%
|
||||||
- 连续 3 根以上大阴线
|
- ✅ 仓位:light 或 micro
|
||||||
- 极端放量后价格企稳
|
|
||||||
- ⚠️ 这时不要追空,考虑平仓或做多
|
|
||||||
|
|
||||||
### 左侧交易规则(特定条件下可尝试)
|
**❌ 追入的危险区**:
|
||||||
|
- 15m RSI > 70(多)或 < 30(空)
|
||||||
|
- 价格偏离均线 > 3%
|
||||||
|
- 连续 3 根以上大阳/大阴
|
||||||
|
|
||||||
**什么时候可以尝试左侧交易?**
|
#### 策略2:回调/反弹入场(稳健策略)
|
||||||
|
**回调做多**(30m 上升,15m 回调):
|
||||||
|
- 回调到 EMA20 或支撑位
|
||||||
|
- RSI 回落到 40-50
|
||||||
|
- 缩量后放量反弹
|
||||||
|
|
||||||
1. **上升趋势晚期,出现明确反转信号**:
|
**反弹做空**(30m 下降,15m 反弹):
|
||||||
- RSI 顶背离 + 价格触及布林带上轨外
|
- 反弹到 EMA20 或压力位
|
||||||
- 放量滞涨 + 出现大阴线
|
- RSI 反弹到 50-60
|
||||||
- 关键阻力位出现明显反转形态(十字星、吞没)
|
- 缩量后放量下跌
|
||||||
- ✅ 可以尝试做空,小仓位(light 或 micro)
|
|
||||||
|
|
||||||
2. **下降趋势晚期,出现明确反转信号**:
|
**回调入场要求**:
|
||||||
- RSI 底背离 + 价格触及布林带下轨外
|
- ✅ 盈亏比 ≥ 1:3(更严格要求)
|
||||||
- 地量后企稳 + 出现大阳线
|
- ✅ 止损:支撑/压力位外侧 1%
|
||||||
- 关键支撑位出现明显反转形态(锤子线、早晨之星)
|
- ✅ 目标:2-3%
|
||||||
- ✅ 可以尝试做多,小仓位(light 或 micro)
|
|
||||||
|
|
||||||
3. **小级别反转信号**:
|
#### 策略3:震荡双向交易(仅限震荡市)
|
||||||
- 5m/15m 周期出现明显的背离信号
|
- 支撑位做多,压力位做空
|
||||||
- 4h/1h 大周期仍在趋势中,但小级别开始反转
|
- 严格止损 1%
|
||||||
- ✅ 可以尝试小仓位反向,但严格止损
|
- 目标 1.5-2%
|
||||||
|
- 盈亏比 ≥ 1:2
|
||||||
|
|
||||||
**左侧交易必须满足的条件**:
|
### 🚨 盈亏比检查清单(必须执行!)
|
||||||
- 至少 2 个反转信号同时出现
|
|
||||||
- 有明确的关键点位支撑/阻力
|
|
||||||
- 严格止损(不超过保证金的 1%)
|
|
||||||
- 小仓位(light 或 micro)
|
|
||||||
|
|
||||||
### 实战示例
|
**在输出任何交易信号前,必须计算盈亏比**:
|
||||||
|
|
||||||
**❌ 错误:盲目追涨**
|
|
||||||
```
|
```
|
||||||
场景:BTC 多头排列,连续上涨 5%
|
做多盈亏比 = (目标价 - 入场价) / (入场价 - 止损价)
|
||||||
MA 完美多头排列,RSI = 68
|
做空盈亏比 = (入场价 - 目标价) / (止损价 - 入场价)
|
||||||
错误分析:趋势仍在延续,追多
|
|
||||||
正确分析:价格已偏离 MA5 > 3%,接近过度延伸,观望或小仓位做空
|
示例:
|
||||||
|
- BTC 入场 65000,止损 64300(-1%),目标 66300(+2%)
|
||||||
|
- 盈亏比 = (66300 - 65000) / (65000 - 64300) = 1300 / 700 ≈ 1.86 ✅ 可行
|
||||||
```
|
```
|
||||||
|
|
||||||
**✅ 正确:等待反转信号**
|
**如果盈亏比 < 1:2,不要输出信号!**
|
||||||
|
|
||||||
|
### 日内交易决策流程
|
||||||
|
|
||||||
```
|
```
|
||||||
场景:BTC 多头排列,但出现顶背离
|
第一步:检查盈亏比
|
||||||
4h 多头排列,但 RSI 出现顶背离
|
├── 盈亏比 < 1:2 → ❌ 不开仓
|
||||||
15m 价格创新高但 RSI 未创新高
|
└── 盈亏比 ≥ 1:2 → 继续检查
|
||||||
正确分析:趋势可能反转,小仓位尝试做空
|
|
||||||
|
第二步:判断趋势方向
|
||||||
|
├── 30m 上升 + 15m 上升 → 做多(策略1或2)
|
||||||
|
├── 30m 下降 + 15m 下降 → 做空(策略1或2)
|
||||||
|
├── 30m 震荡 → 观望或双向轻仓(策略3)
|
||||||
|
└── 趋势不明确 → 观望
|
||||||
|
|
||||||
|
第三步:选择入场方式
|
||||||
|
├── 放量突破 → market 立即入场
|
||||||
|
└── 等待回调 → limit 挂单入场
|
||||||
|
|
||||||
|
第四步:设置止损止盈
|
||||||
|
├── 止损:1-2%(最大不超过 2%)
|
||||||
|
├── 目标:2-3%(快速获利)
|
||||||
|
└── 验证盈亏比 ≥ 1:2
|
||||||
```
|
```
|
||||||
|
|
||||||
## 一、量价分析(重要)
|
## 一、量价分析(重要)
|
||||||
@ -247,19 +256,19 @@ MA 完美多头排列,RSI = 68
|
|||||||
- 布林带收口:即将变盘
|
- 布林带收口:即将变盘
|
||||||
- 布林带开口:趋势启动
|
- 布林带开口:趋势启动
|
||||||
|
|
||||||
### 均线系统(趋势判断核心)
|
### 均线系统(趋势判断核心 - 使用 EMA)
|
||||||
- **多头排列**(MA5 > MA10 > MA20 > MA50):强势上涨趋势,回调做多
|
- **多头排列**(EMA5 > EMA10 > EMA20 > EMA50):强势上涨趋势,回调做多
|
||||||
- **空头排列**(MA5 < MA10 < MA20 < MA50):强势下跌趋势,反弹做空
|
- **空头排列**(EMA5 < EMA10 < EMA20 < EMA50):强势下跌趋势,反弹做空
|
||||||
- **价格与 MA 的关系**:
|
- **价格与 EMA 的关系**:
|
||||||
- 价格站稳 MA5/MA10 上方:短线上涨
|
- 价格站稳 EMA5/EMA10 上方:短线上涨
|
||||||
- 价格突破 MA20:中线转多
|
- 价格突破 EMA20:中线转多
|
||||||
- 价格跌破 MA20:中线转空
|
- 价格跌破 EMA20:中线转空
|
||||||
- MA50 是中期趋势的分水岭
|
- EMA50 是中期趋势的分水岭
|
||||||
- **均线金叉死叉**:
|
- **均线金叉死叉**:
|
||||||
- MA5 上穿 MA10:短线买入信号
|
- EMA5 上穿 EMA10:短线买入信号
|
||||||
- MA5 下穿 MA10:短线卖出信号
|
- EMA5 下穿 EMA10:短线卖出信号
|
||||||
- MA10 上穿 MA20:中线买入信号
|
- EMA10 上穿 EMA20:中线买入信号
|
||||||
- MA10 下穿 MA20:中线卖出信号
|
- EMA10 下穿 EMA20:中线卖出信号
|
||||||
|
|
||||||
## 四、新闻舆情分析
|
## 四、新闻舆情分析
|
||||||
结合最新市场新闻判断:
|
结合最新市场新闻判断:
|
||||||
@ -272,28 +281,29 @@ MA 完美多头排列,RSI = 68
|
|||||||
**多周期共振是提高信号质量的核心方法:**
|
**多周期共振是提高信号质量的核心方法:**
|
||||||
|
|
||||||
### 周期层级关系
|
### 周期层级关系
|
||||||
- **4h(趋势层)**:决定中期大方向
|
- **1h(当日大方向)**:判断当日的主要趋势方向
|
||||||
- **1h(主周期)**:主要交易周期
|
- **30m(日内趋势层)**:决定日内主趋势
|
||||||
- **15m(入场层)**:寻找入场时机
|
- **15m(入场层)**:寻找入场时机
|
||||||
- **5m(精确入场)**:确认最佳入场点
|
- **5m(精确入场)**:确认最佳入场点
|
||||||
|
- **1m(超精确)**:最后确认(可选)
|
||||||
|
|
||||||
### 共振判断标准
|
### 共振判断标准
|
||||||
**强共振(A级信号)**:
|
**强共振(A级信号)**:
|
||||||
- 所有周期趋势同向(如 4h多 + 1h多 + 15m多)
|
- 30m + 15m + 5m 趋势同向(如 30m多 + 15m多 + 5m多)
|
||||||
- 多周期 RSI 同时超买/超卖后出现背离
|
- 多周期 RSI 同时超买/超卖后出现背离
|
||||||
- 多周期 MA 同时金叉/死叉
|
- 多周期 EMA 同时金叉/死叉
|
||||||
|
|
||||||
**中等共振(B级信号)**:
|
**中等共振(B级信号)**:
|
||||||
- 大周期(4h+1h)同向
|
- 30m + 15m 同向
|
||||||
- 主周期(1h)技术指标明确
|
- 主周期(15m)技术指标明确
|
||||||
|
|
||||||
**弱共振(C级信号)**:
|
**弱共振(C级信号)**:
|
||||||
- 只有单一周期信号
|
- 只有单一周期信号
|
||||||
- 多周期方向不一致
|
- 多周期方向不一致
|
||||||
|
|
||||||
### 实战策略
|
### 实战策略
|
||||||
- **顺势交易**:4h 和 1h 同向时,在 15m/5m 寻找入场点
|
- **顺势交易**:30m 和 15m 同向时,在 5m/1m 寻找入场点
|
||||||
- **逆势谨慎**:只有 1h 信号但 4h 反向时,降低置信度
|
- **逆势谨慎**:只有 15m 信号但 30m 反向时,降低置信度
|
||||||
- **突破交易**:多周期同时突破关键位,信号最强
|
- **突破交易**:多周期同时突破关键位,信号最强
|
||||||
|
|
||||||
## 六、入场方式
|
## 六、入场方式
|
||||||
@ -380,7 +390,7 @@ MA 完美多头排列,RSI = 68
|
|||||||
### ✅ 允许输出新信号的情况
|
### ✅ 允许输出新信号的情况
|
||||||
只有在以下情况之一时,才输出新的交易信号:
|
只有在以下情况之一时,才输出新的交易信号:
|
||||||
1. **趋势反转**:上一轮判断的趋势发生了明确反转
|
1. **趋势反转**:上一轮判断的趋势发生了明确反转
|
||||||
- 例如:上一轮看多(MA多头排列),现在转为空头排列
|
- 例如:上一轮看多(EMA多头排列),现在转为空头排列
|
||||||
2. **从观望到机会**:上一轮是观望(无信号),现在出现了明确的交易机会
|
2. **从观望到机会**:上一轮是观望(无信号),现在出现了明确的交易机会
|
||||||
3. **上一轮信号已失效**:
|
3. **上一轮信号已失效**:
|
||||||
- 价格已触及上一轮的止损或止盈价位
|
- 价格已触及上一轮的止损或止盈价位
|
||||||
@ -501,15 +511,15 @@ MA 完美多头排列,RSI = 68
|
|||||||
bb_lower = df['bb_lower'].iloc[-1]
|
bb_lower = df['bb_lower'].iloc[-1]
|
||||||
context_parts.append(f"布林带: 上轨 {bb_upper:.2f}, 下轨 {bb_lower:.2f}")
|
context_parts.append(f"布林带: 上轨 {bb_upper:.2f}, 下轨 {bb_lower:.2f}")
|
||||||
|
|
||||||
# 均线系统
|
# 均线系统(使用 30m 作为日内主周期)
|
||||||
context_parts.append(f"\n## 均线系统")
|
context_parts.append(f"\n## 均线系统 (30m 日内主趋势)")
|
||||||
df_1h = data.get('1h')
|
df_30m = data.get('30m')
|
||||||
if df_1h is not None and len(df_1h) > 0:
|
if df_30m is not None and len(df_30m) > 0:
|
||||||
latest = df_1h.iloc[-1]
|
latest = df_30m.iloc[-1]
|
||||||
context_parts.append(f"MA5: {latest.get('ma5', 'N/A')}")
|
context_parts.append(f"EMA5: {latest.get('ma5', 'N/A')}")
|
||||||
context_parts.append(f"MA10: {latest.get('ma10', 'N/A')}")
|
context_parts.append(f"EMA10: {latest.get('ma10', 'N/A')}")
|
||||||
context_parts.append(f"MA20: {latest.get('ma20', 'N/A')}")
|
context_parts.append(f"EMA20: {latest.get('ma20', 'N/A')}")
|
||||||
context_parts.append(f"MA50: {latest.get('ma50', 'N/A')}")
|
context_parts.append(f"EMA50: {latest.get('ma50', 'N/A')}")
|
||||||
|
|
||||||
# 判断均线排列
|
# 判断均线排列
|
||||||
ma5 = latest.get('ma5', 0)
|
ma5 = latest.get('ma5', 0)
|
||||||
@ -519,9 +529,9 @@ MA 完美多头排列,RSI = 68
|
|||||||
|
|
||||||
if all([ma5, ma10, ma20, ma50]):
|
if all([ma5, ma10, ma20, ma50]):
|
||||||
if ma5 > ma10 > ma20 > ma50:
|
if ma5 > ma10 > ma20 > ma50:
|
||||||
context_parts.append("均线排列: 多头排列 📈")
|
context_parts.append("均线排列: 多头排列 📈 (EMA5 > EMA10 > EMA20 > EMA50)")
|
||||||
elif ma5 < ma10 < ma20 < ma50:
|
elif ma5 < ma10 < ma20 < ma50:
|
||||||
context_parts.append("均线排列: 空头排列 📉")
|
context_parts.append("均线排列: 空头排列 📉 (EMA5 < EMA10 < EMA20 < EMA50)")
|
||||||
else:
|
else:
|
||||||
context_parts.append("均线排列: 交织,方向不明")
|
context_parts.append("均线排列: 交织,方向不明")
|
||||||
|
|
||||||
@ -583,96 +593,118 @@ MA 完美多头排列,RSI = 68
|
|||||||
return "新闻获取失败"
|
return "新闻获取失败"
|
||||||
|
|
||||||
def _analyze_trend_position(self, data: Dict[str, pd.DataFrame]) -> str:
|
def _analyze_trend_position(self, data: Dict[str, pd.DataFrame]) -> str:
|
||||||
"""分析趋势所处的位置(早期、中期、晚期)"""
|
"""分析趋势位置和日内交易机会(使用 EMA)"""
|
||||||
try:
|
try:
|
||||||
df_1h = data.get('1h')
|
df_30m = data.get('30m')
|
||||||
if df_1h is None or len(df_1h) < 50:
|
df_15m = data.get('15m')
|
||||||
|
|
||||||
|
if df_30m is None or len(df_30m) < 50:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
latest = df_1h.iloc[-1]
|
latest_30m = df_30m.iloc[-1]
|
||||||
current_price = float(latest['close'])
|
current_price = float(latest_30m['close'])
|
||||||
|
|
||||||
# 获取均线
|
# 获取日内级别 EMA(30m)
|
||||||
ma5 = latest.get('ma5')
|
ema5_30m = latest_30m.get('ma5') # 实际是 ema5
|
||||||
ma10 = latest.get('ma10')
|
ema10_30m = latest_30m.get('ma10') # 实际是 ema10
|
||||||
ma20 = latest.get('ma20')
|
ema20_30m = latest_30m.get('ma20') # 实际是 ema20
|
||||||
|
|
||||||
if not all([ma5, ma10, ma20]):
|
if not all([ema5_30m, ema10_30m, ema20_30m]):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
# 计算价格偏离度
|
# 判断日内趋势(30m EMA 为主)
|
||||||
deviation_ma5 = abs(current_price - ma5) / ma5 * 100
|
if ema5_30m > ema10_30m > ema20_30m:
|
||||||
deviation_ma20 = abs(current_price - ma20) / ma20 * 100
|
intraday_trend = "上升"
|
||||||
|
intraday_emoji = "📈"
|
||||||
# 获取 RSI
|
elif ema5_30m < ema10_30m < ema20_30m:
|
||||||
rsi = latest.get('rsi', 50)
|
intraday_trend = "下跌"
|
||||||
|
intraday_emoji = "📉"
|
||||||
# 获取布林带
|
|
||||||
bb_upper = latest.get('bb_upper')
|
|
||||||
bb_lower = latest.get('bb_lower')
|
|
||||||
|
|
||||||
analysis = []
|
|
||||||
|
|
||||||
# 判断趋势方向
|
|
||||||
if ma5 > ma10 > ma20:
|
|
||||||
trend = "上涨"
|
|
||||||
# 判断是否过度延伸
|
|
||||||
overextended_signals = []
|
|
||||||
|
|
||||||
if deviation_ma5 > 5:
|
|
||||||
overextended_signals.append(f"价格偏离 MA5 > 5% ({deviation_ma5:.1f}%)")
|
|
||||||
|
|
||||||
if rsi > 75:
|
|
||||||
overextended_signals.append(f"RSI 超买 ({rsi:.0f})")
|
|
||||||
|
|
||||||
if bb_upper and current_price > bb_upper:
|
|
||||||
overextended_signals.append("价格突破布林带上轨")
|
|
||||||
|
|
||||||
if overextended_signals:
|
|
||||||
analysis.append(f"⚠️ 警告:{trend}趋势可能过度延伸")
|
|
||||||
for signal in overextended_signals:
|
|
||||||
analysis.append(f" - {signal}")
|
|
||||||
analysis.append(f" → 不要追{trend},警惕反转")
|
|
||||||
|
|
||||||
elif deviation_ma5 > 3 or rsi > 65:
|
|
||||||
analysis.append(f"📍 位置:{trend}趋势中期")
|
|
||||||
analysis.append(f" → 价格偏离 MA5 {deviation_ma5:.1f}%,RSI {rsi:.0f}")
|
|
||||||
analysis.append(f" → 可以顺势{trend},但警惕超买")
|
|
||||||
|
|
||||||
else:
|
|
||||||
analysis.append(f"✅ 位置:{trend}趋势早期")
|
|
||||||
analysis.append(f" → 可以积极{trend}")
|
|
||||||
|
|
||||||
elif ma5 < ma10 < ma20:
|
|
||||||
trend = "下跌"
|
|
||||||
overextended_signals = []
|
|
||||||
|
|
||||||
if deviation_ma5 > 5:
|
|
||||||
overextended_signals.append(f"价格偏离 MA5 > 5% ({deviation_ma5:.1f}%)")
|
|
||||||
|
|
||||||
if rsi < 25:
|
|
||||||
overextended_signals.append(f"RSI 超卖 ({rsi:.0f})")
|
|
||||||
|
|
||||||
if bb_lower and current_price < bb_lower:
|
|
||||||
overextended_signals.append("价格跌破布林带下轨")
|
|
||||||
|
|
||||||
if overextended_signals:
|
|
||||||
analysis.append(f"⚠️ 警告:{trend}趋势可能过度延伸")
|
|
||||||
for signal in overextended_signals:
|
|
||||||
analysis.append(f" - {signal}")
|
|
||||||
analysis.append(f" → 不要追{trend},警惕反弹")
|
|
||||||
|
|
||||||
elif deviation_ma5 > 3 or rsi < 35:
|
|
||||||
analysis.append(f"📍 位置:{trend}趋势中期")
|
|
||||||
analysis.append(f" → 价格偏离 MA5 {deviation_ma5:.1f}%,RSI {rsi:.0f}")
|
|
||||||
analysis.append(f" → 可以顺势{trend},但警惕超卖")
|
|
||||||
|
|
||||||
else:
|
|
||||||
analysis.append(f"✅ 位置:{trend}趋势早期")
|
|
||||||
analysis.append(f" → 可以积极{trend}")
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
analysis.append("➖ 位置:震荡市")
|
intraday_trend = "震荡"
|
||||||
|
intraday_emoji = "➖"
|
||||||
|
|
||||||
|
analysis = [f"日内趋势(30m EMA): {intraday_emoji} {intraday_trend}"]
|
||||||
|
|
||||||
|
# 检查15分钟级别入场时机
|
||||||
|
if df_15m is not None and len(df_15m) >= 20:
|
||||||
|
latest_15m = df_15m.iloc[-1]
|
||||||
|
rsi_15m = latest_15m.get('rsi', 50)
|
||||||
|
ema5_15m = latest_15m.get('ma5') # 实际是 ema5
|
||||||
|
ema20_15m = latest_15m.get('ma20') # 实际是 ema20
|
||||||
|
|
||||||
|
# 检查短期动能
|
||||||
|
if len(df_15m) >= 5:
|
||||||
|
recent_closes = df_15m['close'].iloc[-5:].values
|
||||||
|
is_accelerating = all(recent_closes[i] > recent_closes[i-1] for i in range(1, 5))
|
||||||
|
else:
|
||||||
|
is_accelerating = False
|
||||||
|
|
||||||
|
# 计算价格偏离
|
||||||
|
if ema5_15m and ema20_15m:
|
||||||
|
deviation_ema5_15m = abs(current_price - ema5_15m) / ema5_15m * 100
|
||||||
|
distance_to_ema20 = abs(current_price - ema20_15m) / ema20_15m * 100
|
||||||
|
else:
|
||||||
|
deviation_ema5_15m = 0
|
||||||
|
distance_to_ema20 = 0
|
||||||
|
|
||||||
|
# 检查成交量
|
||||||
|
df_5m = data.get('5m')
|
||||||
|
volume_ratio = 1
|
||||||
|
if df_5m is not None and len(df_5m) >= 20:
|
||||||
|
vol_latest = df_5m['volume'].iloc[-1]
|
||||||
|
vol_ma20 = df_5m['volume'].iloc[-20:-1].mean()
|
||||||
|
volume_ratio = vol_latest / vol_ma20 if vol_ma20 > 0 else 1
|
||||||
|
|
||||||
|
# 日内过度延伸检查(EMA 反应更快,阈值更严格)
|
||||||
|
is_overextended = (
|
||||||
|
(rsi_15m > 70 and intraday_trend == "上升") or
|
||||||
|
(rsi_15m < 30 and intraday_trend == "下跌") or
|
||||||
|
deviation_ema5_15m > 3
|
||||||
|
)
|
||||||
|
|
||||||
|
if intraday_trend == "上升":
|
||||||
|
if is_accelerating and volume_ratio > 1.3 and not is_overextended:
|
||||||
|
analysis.append(f"15m: 正在加速上涨,放量突破")
|
||||||
|
analysis.append(f" → 日内追多(止损1-2%,目标2-3%)")
|
||||||
|
analysis.append(f" → 盈亏比要求 >= 1:2")
|
||||||
|
elif distance_to_ema20 < 1 and deviation_ema5_15m > 1.5:
|
||||||
|
analysis.append(f"15m: 回调到 EMA20 支撑位")
|
||||||
|
analysis.append(f" → 支撑位做多反弹(EMA20: ${ema20_15m:.0f})")
|
||||||
|
analysis.append(f" → 止损1%,目标2-3%,盈亏比 >= 1:3")
|
||||||
|
elif is_overextended:
|
||||||
|
analysis.append(f"⚠️ 15m 过度延伸: RSI {rsi_15m:.0f},偏离 EMA5 {deviation_ema5_15m:.1f}%")
|
||||||
|
analysis.append(f" → 不要追多,等待回调")
|
||||||
|
else:
|
||||||
|
analysis.append(f"15m: 上涨中,可以轻仓做多")
|
||||||
|
analysis.append(f" → RSI {rsi_15m:.0f},偏离 EMA5 {deviation_ema5_15m:.1f}%")
|
||||||
|
|
||||||
|
elif intraday_trend == "下跌":
|
||||||
|
if is_accelerating and volume_ratio > 1.3 and not is_overextended:
|
||||||
|
analysis.append(f"15m: 正在加速下跌,放量跌破")
|
||||||
|
analysis.append(f" → 日内追空(止损1-2%,目标2-3%)")
|
||||||
|
analysis.append(f" → 盈亏比要求 >= 1:2")
|
||||||
|
elif distance_to_ema20 < 1 and deviation_ema5_15m > 1.5:
|
||||||
|
analysis.append(f"15m: 反弹到 EMA20 压力位")
|
||||||
|
analysis.append(f" → 压力位做空回调(EMA20: ${ema20_15m:.0f})")
|
||||||
|
analysis.append(f" → 止损1%,目标2-3%,盈亏比 >= 1:3")
|
||||||
|
elif is_overextended:
|
||||||
|
analysis.append(f"⚠️ 15m 过度延伸: RSI {rsi_15m:.0f},偏离 EMA5 {deviation_ema5_15m:.1f}%")
|
||||||
|
analysis.append(f" → 不要追空,等待反弹")
|
||||||
|
else:
|
||||||
|
analysis.append(f"15m: 下跌中,可以轻仓做空")
|
||||||
|
analysis.append(f" → RSI {rsi_15m:.0f},偏离 EMA5 {deviation_ema5_15m:.1f}%")
|
||||||
|
|
||||||
|
else:
|
||||||
|
analysis.append(f"15m: 震荡,观望或双向轻仓")
|
||||||
|
analysis.append(f" → 支撑位多,压力位空,盈亏比 >= 1:3")
|
||||||
|
|
||||||
|
# 日内交易要点
|
||||||
|
analysis.append(f"\n💡 日内交易要点:")
|
||||||
|
analysis.append(f"- 使用 EMA(指数移动平均)反应更快")
|
||||||
|
analysis.append(f"- 盈亏比第一: 必须 >= 1:2,优选 1:3")
|
||||||
|
analysis.append(f"- 快进快出: 持仓不超过4小时")
|
||||||
|
analysis.append(f"- 严格止损: 1-2%(最大2%)")
|
||||||
|
analysis.append(f"- 目标盈利: 2-3%(快速获利)")
|
||||||
|
|
||||||
return "\n".join(analysis) if analysis else ""
|
return "\n".join(analysis) if analysis else ""
|
||||||
|
|
||||||
@ -1008,15 +1040,15 @@ MA 完美多头排列,RSI = 68
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _analyze_volatility(self, data: Dict[str, pd.DataFrame]) -> str:
|
def _analyze_volatility(self, data: Dict[str, pd.DataFrame]) -> str:
|
||||||
"""分析波动率变化"""
|
"""分析波动率变化(使用 30m 作为日内主周期)"""
|
||||||
df = data.get('1h')
|
df = data.get('30m')
|
||||||
if df is None or len(df) < 24 or 'atr' not in df.columns:
|
if df is None or len(df) < 24 or 'atr' not in df.columns:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
# ATR 变化趋势
|
# ATR 变化趋势
|
||||||
recent_atr = df['atr'].iloc[-6:].mean() # 最近 6 根
|
recent_atr = df['atr'].iloc[-6:].mean() # 最近 6 根(3小时)
|
||||||
older_atr = df['atr'].iloc[-12:-6].mean() # 之前 6 根
|
older_atr = df['atr'].iloc[-12:-6].mean() # 之前 6 根
|
||||||
|
|
||||||
if pd.isna(recent_atr) or pd.isna(older_atr) or older_atr == 0:
|
if pd.isna(recent_atr) or pd.isna(older_atr) or older_atr == 0:
|
||||||
@ -1028,12 +1060,12 @@ MA 完美多头排列,RSI = 68
|
|||||||
current_price = float(df['close'].iloc[-1])
|
current_price = float(df['close'].iloc[-1])
|
||||||
atr_percent = current_atr / current_price * 100
|
atr_percent = current_atr / current_price * 100
|
||||||
|
|
||||||
lines.append(f"当前 ATR: ${current_atr:.2f} ({atr_percent:.2f}%)")
|
lines.append(f"当前 ATR (30m): ${current_atr:.2f} ({atr_percent:.2f}%)")
|
||||||
|
|
||||||
if atr_change > 20:
|
if atr_change > 20:
|
||||||
lines.append(f"**波动率扩张**: ATR 上升 {atr_change:.0f}%,趋势可能启动")
|
lines.append(f"**波动率扩张**: ATR 上升 {atr_change:.0f}%,日内趋势可能启动")
|
||||||
elif atr_change < -20:
|
elif atr_change < -20:
|
||||||
lines.append(f"**波动率收缩**: ATR 下降 {abs(atr_change):.0f}%,可能即将突破")
|
lines.append(f"**波动率收缩**: ATR 下降 {abs(atr_change):.0f}%,可能即将变盘")
|
||||||
else:
|
else:
|
||||||
lines.append(f"波动率稳定: ATR 变化 {atr_change:+.0f}%")
|
lines.append(f"波动率稳定: ATR 变化 {atr_change:+.0f}%")
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,32 @@ class TradingDecisionMaker:
|
|||||||
TRADING_DECISION_PROMPT = """你是一位专业的加密货币交易员。你的核心职责是**仓位管理和风险控制**,而不是盲目开仓。
|
TRADING_DECISION_PROMPT = """你是一位专业的加密货币交易员。你的核心职责是**仓位管理和风险控制**,而不是盲目开仓。
|
||||||
|
|
||||||
## 🎯 核心理念
|
## 🎯 核心理念
|
||||||
**仓位管理优先于开新仓。你的首要任务是管理好现有仓位,而不是不断增加新仓位。**
|
**日内交易:快进快出 + 盈亏比第一 + 严控风险**
|
||||||
|
|
||||||
|
### 🚨 盈亏比铁律(违反即拒绝)
|
||||||
|
**所有交易必须满足盈亏比 ≥ 1:2,优选 1:3**
|
||||||
|
|
||||||
|
```
|
||||||
|
盈亏比 = (目标盈利 - 入场价) / (入场价 - 止损价)
|
||||||
|
|
||||||
|
做多:盈亏比 = (止盈价 - 入场价) / (入场价 - 止损价)
|
||||||
|
做空:盈亏比 = (入场价 - 止盈价) / (止损价 - 入场价)
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- BTC 做多:入场 65000,止损 64300(-1%),止盈 66300(+2%)
|
||||||
|
- 盈亏比 = (66300 - 65000) / (65000 - 64300) = 1300 / 700 ≈ 1.86 ✅
|
||||||
|
|
||||||
|
如果盈亏比 < 1:2,绝对不要开仓!
|
||||||
|
```
|
||||||
|
|
||||||
|
### 日内交易参数
|
||||||
|
| 参数 | 设定值 |
|
||||||
|
|------|--------|
|
||||||
|
| 止损幅度 | 1-2%(最大2%) |
|
||||||
|
| 目标盈利 | 2-3%(日内快速获利) |
|
||||||
|
| 盈亏比要求 | ≥ 1:2(优选1:3) |
|
||||||
|
| 单笔持仓时长 | 不超过4小时 |
|
||||||
|
| 仓位大小 | 轻仓为主(light/micro) |
|
||||||
|
|
||||||
## 决策流程(必须按顺序执行)
|
## 决策流程(必须按顺序执行)
|
||||||
|
|
||||||
@ -704,6 +729,57 @@ class TradingDecisionMaker:
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# 盈亏比检查规则(新增)
|
||||||
|
prompt_parts.append(f"\n## 盈亏比检查(日内交易铁律)")
|
||||||
|
prompt_parts.append(f"⚠️ 所有交易必须满足盈亏比 >= 1:2,优选 1:3")
|
||||||
|
prompt_parts.append(f"")
|
||||||
|
prompt_parts.append(f"盈亏比计算公式:")
|
||||||
|
prompt_parts.append(f" 做多盈亏比 = (止盈价 - 入场价) / (入场价 - 止损价)")
|
||||||
|
prompt_parts.append(f" 做空盈亏比 = (入场价 - 止盈价) / (止损价 - 入场价)")
|
||||||
|
prompt_parts.append(f"")
|
||||||
|
prompt_parts.append(f"⚠️ 如果盈亏比 < 1:2,**不要开仓(返回 HOLD)**")
|
||||||
|
|
||||||
|
# 计算并显示盈亏比
|
||||||
|
signals = context.get('signals', [])
|
||||||
|
if signals:
|
||||||
|
for sig in signals:
|
||||||
|
action = sig.get('action')
|
||||||
|
entry = sig.get('entry_zone')
|
||||||
|
stop_loss = sig.get('stop_loss')
|
||||||
|
take_profit = sig.get('take_profit')
|
||||||
|
|
||||||
|
if action and entry and stop_loss and take_profit:
|
||||||
|
try:
|
||||||
|
entry = float(entry)
|
||||||
|
stop_loss = float(stop_loss)
|
||||||
|
take_profit = float(take_profit)
|
||||||
|
|
||||||
|
if action == 'buy':
|
||||||
|
risk_ratio = entry - stop_loss
|
||||||
|
reward_ratio = take_profit - entry
|
||||||
|
elif action == 'sell':
|
||||||
|
risk_ratio = stop_loss - entry
|
||||||
|
reward_ratio = entry - take_profit
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if risk_ratio > 0 and reward_ratio > 0:
|
||||||
|
rr_ratio = reward_ratio / risk_ratio
|
||||||
|
rr_percent = (risk_ratio / entry) * 100
|
||||||
|
|
||||||
|
if rr_ratio >= 2.0:
|
||||||
|
status = f"✅ 通过 (1:{rr_ratio:.1f})"
|
||||||
|
else:
|
||||||
|
status = f"❌ 拒绝 (1:{rr_ratio:.1f} < 1:2)"
|
||||||
|
|
||||||
|
prompt_parts.append(f"\n信号 {action} @ ${entry:,.2f}:")
|
||||||
|
prompt_parts.append(f" - 止损: ${stop_loss:,.2f} (风险 {risk_ratio:.0f} / {rr_percent:.1f}%)")
|
||||||
|
prompt_parts.append(f" - 止盈: ${take_profit:,.2f} (盈利 {reward_ratio:.0f})")
|
||||||
|
prompt_parts.append(f" - 盈亏比: 1:{rr_ratio:.2f} {status}")
|
||||||
|
|
||||||
|
except (ValueError, TypeError, ZeroDivisionError):
|
||||||
|
pass
|
||||||
|
|
||||||
prompt_parts.append(f"\n请根据以上信息,做出交易决策。")
|
prompt_parts.append(f"\n请根据以上信息,做出交易决策。")
|
||||||
|
|
||||||
return "\n".join(prompt_parts)
|
return "\n".join(prompt_parts)
|
||||||
@ -861,6 +937,62 @@ 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})"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 盈亏比检查:所有交易必须满足盈亏比 >= 1:2
|
||||||
|
action = decision.get('action', '')
|
||||||
|
entry_price = decision.get('entry_price')
|
||||||
|
stop_loss = decision.get('stop_loss')
|
||||||
|
take_profit = decision.get('take_profit')
|
||||||
|
|
||||||
|
if action and entry_price and stop_loss and take_profit:
|
||||||
|
try:
|
||||||
|
entry_price = float(entry_price)
|
||||||
|
stop_loss = float(stop_loss)
|
||||||
|
take_profit = float(take_profit)
|
||||||
|
|
||||||
|
# 计算盈亏比
|
||||||
|
if action == 'buy':
|
||||||
|
risk = entry_price - stop_loss
|
||||||
|
reward = take_profit - entry_price
|
||||||
|
elif action == 'sell':
|
||||||
|
risk = stop_loss - entry_price
|
||||||
|
reward = entry_price - take_profit
|
||||||
|
else:
|
||||||
|
risk = 0
|
||||||
|
reward = 0
|
||||||
|
|
||||||
|
# 验证价格方向正确性
|
||||||
|
if action == 'buy':
|
||||||
|
if stop_loss >= entry_price:
|
||||||
|
logger.warning(f"⚠️ 决策被拒绝: 做多止损错误 (entry={entry_price}, stop_loss={stop_loss} 应该 < entry)")
|
||||||
|
return self._get_hold_decision(decision['symbol'], f"做多止损价格错误")
|
||||||
|
if take_profit <= entry_price:
|
||||||
|
logger.warning(f"⚠️ 决策被拒绝: 做多止盈错误 (entry={entry_price}, take_profit={take_profit} 应该 > entry)")
|
||||||
|
return self._get_hold_decision(decision['symbol'], f"做多止盈价格错误")
|
||||||
|
elif action == 'sell':
|
||||||
|
if stop_loss <= entry_price:
|
||||||
|
logger.warning(f"⚠️ 决策被拒绝: 做空止损错误 (entry={entry_price}, stop_loss={stop_loss} 应该 > entry)")
|
||||||
|
return self._get_hold_decision(decision['symbol'], f"做空止损价格错误")
|
||||||
|
if take_profit >= entry_price:
|
||||||
|
logger.warning(f"⚠️ 决策被拒绝: 做空止盈错误 (entry={entry_price}, take_profit={take_profit} 应该 < entry)")
|
||||||
|
return self._get_hold_decision(decision['symbol'], f"做空止盈价格错误")
|
||||||
|
|
||||||
|
# 检查盈亏比
|
||||||
|
if risk > 0 and reward > 0:
|
||||||
|
rr_ratio = reward / risk
|
||||||
|
min_rr_ratio = 2.0 # 最小盈亏比 1:2
|
||||||
|
|
||||||
|
if rr_ratio < min_rr_ratio:
|
||||||
|
logger.warning(f"⚠️ 决策被拒绝: 盈亏比不足 (1:{rr_ratio:.2f} < 1:{min_rr_ratio:.0f})")
|
||||||
|
logger.warning(f" entry={entry_price}, stop_loss={stop_loss}, take_profit={take_profit}")
|
||||||
|
logger.warning(f" 风险={risk:.0f}, 盈利={reward:.0f}, 盈亏比=1:{rr_ratio:.2f}")
|
||||||
|
return self._get_hold_decision(
|
||||||
|
decision['symbol'],
|
||||||
|
f"盈亏比不足 (1:{rr_ratio:.2f} < 1:{min_rr_ratio:.0f})"
|
||||||
|
)
|
||||||
|
|
||||||
|
except (ValueError, TypeError, ZeroDivisionError) as e:
|
||||||
|
logger.warning(f"盈亏比检查失败: {e}")
|
||||||
|
|
||||||
# 价格距离检查:相同方向相同标的的挂单,价格距离 < 2% 时不加仓/开仓
|
# 价格距离检查:相同方向相同标的的挂单,价格距离 < 2% 时不加仓/开仓
|
||||||
action = decision.get('action', '')
|
action = decision.get('action', '')
|
||||||
new_entry_price = decision.get('entry_price')
|
new_entry_price = decision.get('entry_price')
|
||||||
|
|||||||
@ -83,14 +83,15 @@ class BinanceService:
|
|||||||
# 1h: 300根 = 12.5天(中线分析)
|
# 1h: 300根 = 12.5天(中线分析)
|
||||||
# 4h: 200根 = 33.3天(趋势分析)
|
# 4h: 200根 = 33.3天(趋势分析)
|
||||||
limits = {
|
limits = {
|
||||||
|
'1m': 200,
|
||||||
'5m': 200,
|
'5m': 200,
|
||||||
'15m': 200,
|
'15m': 200,
|
||||||
'1h': 300,
|
'30m': 200,
|
||||||
'4h': 200
|
'1h': 300
|
||||||
}
|
}
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
for interval in ['5m', '15m', '1h', '4h']:
|
for interval in ['1m', '5m', '15m', '30m', '1h']:
|
||||||
df = self.get_klines(symbol, interval, limit=limits.get(interval, 100))
|
df = self.get_klines(symbol, interval, limit=limits.get(interval, 100))
|
||||||
if not df.empty:
|
if not df.empty:
|
||||||
df = self.calculate_indicators(df, interval) # 传递 interval 参数
|
df = self.calculate_indicators(df, interval) # 传递 interval 参数
|
||||||
@ -139,23 +140,30 @@ class BinanceService:
|
|||||||
return df
|
return df
|
||||||
|
|
||||||
# 根据周期调整 MA 参数
|
# 根据周期调整 MA 参数
|
||||||
# 短周期(5m, 15m)使用较短的 MA,长周期使用较长的 MA
|
# 短周期(1m, 5m, 15m)使用较短的 MA,长周期使用较长的 MA
|
||||||
ma_config = {
|
ma_config = {
|
||||||
|
'1m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
'5m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
'5m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
'15m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
'15m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
|
'30m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
'1h': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
'1h': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
'4h': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config = ma_config.get(interval, ma_config['1h'])
|
config = ma_config.get(interval, ma_config['1h'])
|
||||||
|
|
||||||
# 移动平均线(统一命名,便于 LLM 分析)
|
# EMA(日内交易使用 EMA 反应更快)
|
||||||
df['ma5'] = self._calculate_ma(df['close'], config['ma_short'])
|
df['ema5'] = self._calculate_ema(df['close'], config['ma_short'])
|
||||||
df['ma10'] = self._calculate_ma(df['close'], config['ma_mid'])
|
df['ema10'] = self._calculate_ema(df['close'], config['ma_mid'])
|
||||||
df['ma20'] = self._calculate_ma(df['close'], config['ma_long'])
|
df['ema20'] = self._calculate_ema(df['close'], config['ma_long'])
|
||||||
df['ma50'] = self._calculate_ma(df['close'], config['ma_extra'])
|
df['ema50'] = self._calculate_ema(df['close'], config['ma_extra'])
|
||||||
|
|
||||||
# EMA
|
# 兼容:保留 ma5/ma10/ma20/ma50 作为 EMA 的别名
|
||||||
|
df['ma5'] = df['ema5']
|
||||||
|
df['ma10'] = df['ema10']
|
||||||
|
df['ma20'] = df['ema20']
|
||||||
|
df['ma50'] = df['ema50']
|
||||||
|
|
||||||
|
# MACD EMA(保持不变)
|
||||||
df['ema12'] = self._calculate_ema(df['close'], 12)
|
df['ema12'] = self._calculate_ema(df['close'], 12)
|
||||||
df['ema26'] = self._calculate_ema(df['close'], 26)
|
df['ema26'] = self._calculate_ema(df['close'], 26)
|
||||||
|
|
||||||
|
|||||||
@ -14,10 +14,11 @@ class BitgetService:
|
|||||||
|
|
||||||
# K线周期映射 - 注意 Bitget 使用大写 H
|
# K线周期映射 - 注意 Bitget 使用大写 H
|
||||||
INTERVALS = {
|
INTERVALS = {
|
||||||
|
'1m': '1m',
|
||||||
'5m': '5m',
|
'5m': '5m',
|
||||||
'15m': '15m',
|
'15m': '15m',
|
||||||
|
'30m': '30m',
|
||||||
'1h': '1H', # Bitget 大写
|
'1h': '1H', # Bitget 大写
|
||||||
'4h': '4H' # Bitget 大写
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Bitget API 基础 URL
|
# Bitget API 基础 URL
|
||||||
@ -103,22 +104,24 @@ class BitgetService:
|
|||||||
category: 产品类型,默认 USDT-FUTURES
|
category: 产品类型,默认 USDT-FUTURES
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
包含 5m, 15m, 1h, 4h 数据的字典
|
包含 1m, 5m, 15m, 30m, 1h 数据的字典
|
||||||
"""
|
"""
|
||||||
# 不同周期使用不同的数据量,平衡分析深度和性能
|
# 不同周期使用不同的数据量,平衡分析深度和性能
|
||||||
|
# 1m: 200根 = 3.3小时(超短线精确入场)
|
||||||
# 5m: 200根 = 16.7小时(日内分析)
|
# 5m: 200根 = 16.7小时(日内分析)
|
||||||
# 15m: 200根 = 2.1天(短线分析)
|
# 15m: 200根 = 2.1天(短线分析)
|
||||||
# 1h: 300根 = 12.5天(中线分析)
|
# 30m: 200根 = 4.2天(日内趋势)
|
||||||
# 4h: 200根 = 33.3天(趋势分析)
|
# 1h: 300根 = 12.5天(日内主趋势)
|
||||||
limits = {
|
limits = {
|
||||||
|
'1m': 200,
|
||||||
'5m': 200,
|
'5m': 200,
|
||||||
'15m': 200,
|
'15m': 200,
|
||||||
'1h': 300,
|
'30m': 200,
|
||||||
'4h': 200
|
'1h': 300
|
||||||
}
|
}
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
for interval in ['5m', '15m', '1h', '4h']:
|
for interval in ['1m', '5m', '15m', '30m', '1h']:
|
||||||
df = self.get_klines(symbol, interval, limit=limits.get(interval, 100),
|
df = self.get_klines(symbol, interval, limit=limits.get(interval, 100),
|
||||||
category=category)
|
category=category)
|
||||||
if not df.empty:
|
if not df.empty:
|
||||||
@ -175,21 +178,28 @@ class BitgetService:
|
|||||||
|
|
||||||
# 根据周期调整 MA 参数
|
# 根据周期调整 MA 参数
|
||||||
ma_config = {
|
ma_config = {
|
||||||
|
'1m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
'5m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
'5m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
'15m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
'15m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
|
'30m': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
'1h': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
'1h': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
||||||
'4h': {'ma_short': 5, 'ma_mid': 10, 'ma_long': 20, 'ma_extra': 50},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config = ma_config.get(interval, ma_config['1h'])
|
config = ma_config.get(interval, ma_config['1h'])
|
||||||
|
|
||||||
# 移动平均线
|
# EMA(日内交易使用 EMA 反应更快)
|
||||||
df['ma5'] = self._calculate_ma(df['close'], config['ma_short'])
|
df['ema5'] = self._calculate_ema(df['close'], config['ma_short'])
|
||||||
df['ma10'] = self._calculate_ma(df['close'], config['ma_mid'])
|
df['ema10'] = self._calculate_ema(df['close'], config['ma_mid'])
|
||||||
df['ma20'] = self._calculate_ma(df['close'], config['ma_long'])
|
df['ema20'] = self._calculate_ema(df['close'], config['ma_long'])
|
||||||
df['ma50'] = self._calculate_ma(df['close'], config['ma_extra'])
|
df['ema50'] = self._calculate_ema(df['close'], config['ma_extra'])
|
||||||
|
|
||||||
# EMA
|
# 兼容:保留 ma5/ma10/ma20/ma50 作为 EMA 的别名
|
||||||
|
df['ma5'] = df['ema5']
|
||||||
|
df['ma10'] = df['ema10']
|
||||||
|
df['ma20'] = df['ema20']
|
||||||
|
df['ma50'] = df['ema50']
|
||||||
|
|
||||||
|
# MACD EMA(保持不变)
|
||||||
df['ema12'] = self._calculate_ema(df['close'], 12)
|
df['ema12'] = self._calculate_ema(df['close'], 12)
|
||||||
df['ema26'] = self._calculate_ema(df['close'], 26)
|
df['ema26'] = self._calculate_ema(df['close'], 26)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user