package llmjob import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" "math" ) func J3992(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调超参数 fastLength := pol.DefInt("fastLength", 10, core.PUniform(5, 20)) macdSlowRate := pol.Def("macdSlowRate", 2.17, core.PNorm(1.5, 4)) rsiThreshold := pol.DefInt("rsiThreshold", 65, core.PUniform(60, 80)) bbMult := pol.Def("bbMult", 2.0, core.PNorm(1.5, 3.0)) rsiLength := pol.DefInt("rsiLength", 14, core.PUniform(7, 21)) // 计算其他参数 MACDLength := 9 // 固定值 slowLength := int(float64(fastLength) * macdSlowRate) rsiOverbought := float64(rsiThreshold) rsiOversold := 100 - rsiOverbought stopLossPercent := 0.02 // 2% stop loss takeProfitPercent := 0.05 // 5% take profit // 计算预热数量,取最大值 warmupNum := slowLength if MACDLength > warmupNum { warmupNum = MACDLength } if rsiLength > warmupNum { warmupNum = rsiLength } if bbLength := 20; bbLength > warmupNum { warmupNum = bbLength } return &strat.TradeStrat{ WarmupNum: warmupNum, HedgeOff: true, // 单向持仓模式 RunTimeFrames: []string{"8h"}, OnBar: func(s *strat.StratJob) { e := s.Env // 检查数据长度是否足够 if e.Close.Len() < warmupNum { return } // MACD calculations fastMA := ta.EMA(e.Close, fastLength) slowMA := ta.EMA(e.Close, slowLength) macdLine := fastMA.Sub(slowMA) signalLine := ta.EMA(macdLine, MACDLength) // RSI calculation rsi := ta.RSI(e.Close, rsiLength) // Bollinger Bands calculation bbLength := 20 basis := ta.SMA(e.Close, bbLength) stdDev := ta.StdDev(e.Close, bbLength) dev := stdDev.Mul(bbMult) upper := basis.Add(dev) lower := basis.Sub(dev) // 获取当前值 closePrice := e.Close.Get(0) macdVal := macdLine.Get(0) signalVal := signalLine.Get(0) rsiVal := rsi.Get(0) upperVal := upper.Get(0) lowerVal := lower.Get(0) // 检查NaN值 if math.IsNaN(closePrice) || math.IsNaN(macdVal) || math.IsNaN(signalVal) || math.IsNaN(rsiVal) || math.IsNaN(upperVal) || math.IsNaN(lowerVal) { return } // Entry conditions macdCrossOver := macdLine.Cross(signalLine) == 1 rsiCrossUnder := rsi.Cross(rsiOversold) == -1 longCondition := (macdCrossOver || rsiCrossUnder) && closePrice > lowerVal macdCrossUnder := macdLine.Cross(signalLine) == -1 rsiCrossOver := rsi.Cross(rsiOverbought) == 1 shortCondition := (macdCrossUnder || rsiCrossOver) && closePrice < upperVal // Long position logic if longCondition && len(s.LongOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Long", OrderType: core.OrderTypeMarket, StopLossVal: closePrice * (1 - stopLossPercent), TakeProfitVal: closePrice * (1 + takeProfitPercent), }) } // Short position logic if shortCondition && len(s.ShortOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Short", Short: true, OrderType: core.OrderTypeMarket, StopLossVal: closePrice * (1 + stopLossPercent), TakeProfitVal: closePrice * (1 - takeProfitPercent), }) } }, } }