diff --git a/decision/engine.go b/decision/engine.go index 1e990670..6584af89 100644 --- a/decision/engine.go +++ b/decision/engine.go @@ -279,20 +279,35 @@ func buildSystemPrompt(accountEquity float64, btcEthLeverage, altcoinLeverage in // === 开仓信号强度 === sb.WriteString("# 🎯 开仓标准(严格)\n\n") sb.WriteString("只在**强信号**时开仓,不确定就观望。\n\n") - sb.WriteString("**你拥有的完整数据**:\n") - sb.WriteString("- 📊 **原始序列**:3分钟价格序列(MidPrices数组) + 4小时K线序列\n") - sb.WriteString("- 📈 **技术序列**:EMA20序列、MACD序列、RSI7序列、RSI14序列\n") - sb.WriteString("- 💰 **资金序列**:成交量序列、持仓量(OI)序列、资金费率\n") - sb.WriteString("- 🎯 **筛选标记**:AI500评分 / OI_Top排名(如果有标注)\n\n") + sb.WriteString("**你拥有的完整数据(多时间框架分析)**:\n\n") + sb.WriteString("**📊 四个时间框架序列**(每个包含最近10个数据点):\n") + sb.WriteString("1. **3分钟序列**:用于获取实时价格(当前价格 = 最后一根K线的收盘价)\n") + sb.WriteString(" - Mid prices, EMA20, MACD, RSI7, RSI14\n") + sb.WriteString("2. **15分钟序列**:短期趋势过滤(覆盖最近2.5小时)\n") + sb.WriteString(" - Mid prices, EMA20, MACD, RSI7, RSI14\n") + sb.WriteString("3. **1小时序列**:中期趋势确认(覆盖最近10小时)\n") + sb.WriteString(" - Mid prices, EMA20, MACD, RSI7, RSI14\n") + sb.WriteString("4. **4小时序列**:长期趋势方向(覆盖最近40小时)\n") + sb.WriteString(" - EMA20 vs EMA50, ATR, Volume, MACD, RSI14\n\n") + sb.WriteString("**💰 资金数据**:\n") + sb.WriteString("- 持仓量(OI)变化、资金费率、成交量对比\n\n") + sb.WriteString("**🎯 多时间框架分析建议**:\n") + sb.WriteString("- **趋势共振**:当15m/1h/4h三个时间框架方向一致时 → 高信心度信号\n") + sb.WriteString("- **趋势过滤**:用1h和4h确认主趋势,避免在震荡中交易\n") + sb.WriteString("- **入场时机**:用15m寻找入场点,确保不在短期逆势位置开仓\n") + sb.WriteString("- **背离识别**:价格创新高但MACD未创新高(多时间框架对比)\n") + sb.WriteString("- **假突破过滤**:15m突破但1h/4h未确认 → 可能是假突破\n\n") sb.WriteString("**分析方法**(完全由你自主决定):\n") - sb.WriteString("- 自由运用序列数据,你可以做但不限于趋势分析、形态识别、支撑阻力、技术阻力位、斐波那契、波动带计算\n") - sb.WriteString("- 多维度交叉验证(价格+量+OI+指标+序列形态)\n") + sb.WriteString("- 自由运用多时间框架序列,做趋势分析、形态识别、支撑阻力、背离判断\n") + sb.WriteString("- 多维度交叉验证(多时间框架 + 量价 + OI + 资金费率)\n") sb.WriteString("- 用你认为最有效的方法发现高确定性机会\n") - sb.WriteString("- 综合信心度 ≥ 75 才开仓\n\n") + sb.WriteString("- **综合信心度 ≥ 75 才开仓**\n\n") sb.WriteString("**避免低质量信号**:\n") + sb.WriteString("- 单一时间框架分析(必须多时间框架共振)\n") + sb.WriteString("- 时间框架矛盾(15m上涨但1h/4h下跌)\n") sb.WriteString("- 单一维度(只看一个指标)\n") sb.WriteString("- 相互矛盾(涨但量萎缩)\n") - sb.WriteString("- 横盘震荡\n") + sb.WriteString("- 横盘震荡(多个时间框架都无明确趋势)\n") sb.WriteString("- 刚平仓不久(<15分钟)\n\n") // === 夏普比率自我进化 === diff --git a/market/data.go b/market/data.go index 97812e64..a26783ab 100644 --- a/market/data.go +++ b/market/data.go @@ -21,8 +21,10 @@ type Data struct { CurrentRSI7 float64 OpenInterest *OIData FundingRate float64 - IntradaySeries *IntradayData - LongerTermContext *LongerTermData + IntradaySeries *IntradayData // 3分钟数据 - 实时价格 + MidTermSeries15m *MidTermData15m // 15分钟数据 - 短期趋势 + MidTermSeries1h *MidTermData1h // 1小时数据 - 中期趋势 + LongerTermContext *LongerTermData // 4小时数据 - 长期趋势 } // OIData Open Interest数据 @@ -31,7 +33,7 @@ type OIData struct { Average float64 } -// IntradayData 日内数据(3分钟间隔) +// IntradayData 日内数据(3分钟间隔) - 主要用于获取实时价格 type IntradayData struct { MidPrices []float64 EMA20Values []float64 @@ -40,6 +42,24 @@ type IntradayData struct { RSI14Values []float64 } +// MidTermData15m 15分钟时间框架数据 - 短期趋势过滤 +type MidTermData15m struct { + MidPrices []float64 + EMA20Values []float64 + MACDValues []float64 + RSI7Values []float64 + RSI14Values []float64 +} + +// MidTermData1h 1小时时间框架数据 - 中期趋势确认 +type MidTermData1h struct { + MidPrices []float64 + EMA20Values []float64 + MACDValues []float64 + RSI7Values []float64 + RSI14Values []float64 +} + // LongerTermData 长期数据(4小时时间框架) type LongerTermData struct { EMA20 float64 @@ -68,13 +88,25 @@ func Get(symbol string) (*Data, error) { // 标准化symbol symbol = Normalize(symbol) - // 获取3分钟K线数据 (最近10个) + // 获取3分钟K线数据 (最近10个) - 用于实时价格 klines3m, err := getKlines(symbol, "3m", 40) // 多获取一些用于计算 if err != nil { return nil, fmt.Errorf("获取3分钟K线失败: %v", err) } - // 获取4小时K线数据 (最近10个) + // 获取15分钟K线数据 (最近10个) - 短期趋势 + klines15m, err := getKlines(symbol, "15m", 40) + if err != nil { + return nil, fmt.Errorf("获取15分钟K线失败: %v", err) + } + + // 获取1小时K线数据 (最近10个) - 中期趋势 + klines1h, err := getKlines(symbol, "1h", 60) + if err != nil { + return nil, fmt.Errorf("获取1小时K线失败: %v", err) + } + + // 获取4小时K线数据 (最近10个) - 长期趋势 klines4h, err := getKlines(symbol, "4h", 60) // 多获取用于计算指标 if err != nil { return nil, fmt.Errorf("获取4小时K线失败: %v", err) @@ -115,10 +147,16 @@ func Get(symbol string) (*Data, error) { // 获取Funding Rate fundingRate, _ := getFundingRate(symbol) - // 计算日内系列数据 + // 计算日内系列数据 (3分钟) intradayData := calculateIntradaySeries(klines3m) - // 计算长期数据 + // 计算15分钟系列数据 + midTermData15m := calculateMidTermSeries15m(klines15m) + + // 计算1小时系列数据 + midTermData1h := calculateMidTermSeries1h(klines1h) + + // 计算长期数据 (4小时) longerTermData := calculateLongerTermData(klines4h) return &Data{ @@ -132,6 +170,8 @@ func Get(symbol string) (*Data, error) { OpenInterest: oiData, FundingRate: fundingRate, IntradaySeries: intradayData, + MidTermSeries15m: midTermData15m, + MidTermSeries1h: midTermData1h, LongerTermContext: longerTermData, }, nil } @@ -340,6 +380,96 @@ func calculateIntradaySeries(klines []Kline) *IntradayData { return data } +// calculateMidTermSeries15m 计算15分钟系列数据 +func calculateMidTermSeries15m(klines []Kline) *MidTermData15m { + data := &MidTermData15m{ + MidPrices: make([]float64, 0, 10), + EMA20Values: make([]float64, 0, 10), + MACDValues: make([]float64, 0, 10), + RSI7Values: make([]float64, 0, 10), + RSI14Values: make([]float64, 0, 10), + } + + // 获取最近10个数据点 + start := len(klines) - 10 + if start < 0 { + start = 0 + } + + for i := start; i < len(klines); i++ { + data.MidPrices = append(data.MidPrices, klines[i].Close) + + // 计算每个点的EMA20 + if i >= 19 { + ema20 := calculateEMA(klines[:i+1], 20) + data.EMA20Values = append(data.EMA20Values, ema20) + } + + // 计算每个点的MACD + if i >= 25 { + macd := calculateMACD(klines[:i+1]) + data.MACDValues = append(data.MACDValues, macd) + } + + // 计算每个点的RSI + if i >= 7 { + rsi7 := calculateRSI(klines[:i+1], 7) + data.RSI7Values = append(data.RSI7Values, rsi7) + } + if i >= 14 { + rsi14 := calculateRSI(klines[:i+1], 14) + data.RSI14Values = append(data.RSI14Values, rsi14) + } + } + + return data +} + +// calculateMidTermSeries1h 计算1小时系列数据 +func calculateMidTermSeries1h(klines []Kline) *MidTermData1h { + data := &MidTermData1h{ + MidPrices: make([]float64, 0, 10), + EMA20Values: make([]float64, 0, 10), + MACDValues: make([]float64, 0, 10), + RSI7Values: make([]float64, 0, 10), + RSI14Values: make([]float64, 0, 10), + } + + // 获取最近10个数据点 + start := len(klines) - 10 + if start < 0 { + start = 0 + } + + for i := start; i < len(klines); i++ { + data.MidPrices = append(data.MidPrices, klines[i].Close) + + // 计算每个点的EMA20 + if i >= 19 { + ema20 := calculateEMA(klines[:i+1], 20) + data.EMA20Values = append(data.EMA20Values, ema20) + } + + // 计算每个点的MACD + if i >= 25 { + macd := calculateMACD(klines[:i+1]) + data.MACDValues = append(data.MACDValues, macd) + } + + // 计算每个点的RSI + if i >= 7 { + rsi7 := calculateRSI(klines[:i+1], 7) + data.RSI7Values = append(data.RSI7Values, rsi7) + } + if i >= 14 { + rsi14 := calculateRSI(klines[:i+1], 14) + data.RSI14Values = append(data.RSI14Values, rsi14) + } + } + + return data +} + // calculateLongerTermData 计算长期数据 func calculateLongerTermData(klines []Kline) *LongerTermData { data := &LongerTermData{ @@ -493,6 +623,54 @@ func Format(data *Data) string { } } + if data.MidTermSeries15m != nil { + sb.WriteString("Mid‑term series (15‑minute intervals, oldest → latest):\n\n") + + if len(data.MidTermSeries15m.MidPrices) > 0 { + sb.WriteString(fmt.Sprintf("Mid prices: %s\n\n", formatFloatSlice(data.MidTermSeries15m.MidPrices))) + } + + if len(data.MidTermSeries15m.EMA20Values) > 0 { + sb.WriteString(fmt.Sprintf("EMA indicators (20‑period): %s\n\n", formatFloatSlice(data.MidTermSeries15m.EMA20Values))) + } + + if len(data.MidTermSeries15m.MACDValues) > 0 { + sb.WriteString(fmt.Sprintf("MACD indicators: %s\n\n", formatFloatSlice(data.MidTermSeries15m.MACDValues))) + } + + if len(data.MidTermSeries15m.RSI7Values) > 0 { + sb.WriteString(fmt.Sprintf("RSI indicators (7‑Period): %s\n\n", formatFloatSlice(data.MidTermSeries15m.RSI7Values))) + } + + if len(data.MidTermSeries15m.RSI14Values) > 0 { + sb.WriteString(fmt.Sprintf("RSI indicators (14‑Period): %s\n\n", formatFloatSlice(data.MidTermSeries15m.RSI14Values))) + } + } + + if data.MidTermSeries1h != nil { + sb.WriteString("Mid‑term series (1‑hour intervals, oldest → latest):\n\n") + + if len(data.MidTermSeries1h.MidPrices) > 0 { + sb.WriteString(fmt.Sprintf("Mid prices: %s\n\n", formatFloatSlice(data.MidTermSeries1h.MidPrices))) + } + + if len(data.MidTermSeries1h.EMA20Values) > 0 { + sb.WriteString(fmt.Sprintf("EMA indicators (20‑period): %s\n\n", formatFloatSlice(data.MidTermSeries1h.EMA20Values))) + } + + if len(data.MidTermSeries1h.MACDValues) > 0 { + sb.WriteString(fmt.Sprintf("MACD indicators: %s\n\n", formatFloatSlice(data.MidTermSeries1h.MACDValues))) + } + + if len(data.MidTermSeries1h.RSI7Values) > 0 { + sb.WriteString(fmt.Sprintf("RSI indicators (7‑Period): %s\n\n", formatFloatSlice(data.MidTermSeries1h.RSI7Values))) + } + + if len(data.MidTermSeries1h.RSI14Values) > 0 { + sb.WriteString(fmt.Sprintf("RSI indicators (14‑Period): %s\n\n", formatFloatSlice(data.MidTermSeries1h.RSI14Values))) + } + } + if data.LongerTermContext != nil { sb.WriteString("Longer‑term context (4‑hour timeframe):\n\n")