// 修复后的banbot完整策略代码 package llmjob import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" "math" ) // 定义一个结构体来存储策略需要的变量 type StrategyData struct { atrValue float64 } func J4034(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调参数 fastLength := pol.DefInt("fastLength", 12, core.PNorm(5, 20)) emaRate := pol.Def("emaRate", 2.33, core.PNorm(1.5, 5.0)) rsiLength := pol.DefInt("rsiLength", 14, core.PNorm(7, 30)) rsiOverbought := pol.DefInt("rsiOverbought", 70, core.PNorm(60, 85)) rsiOversold := pol.DefInt("rsiOversold", 30, core.PNorm(15, 40)) volLength := pol.DefInt("volLength", 20, core.PNorm(10, 40)) atrLength := pol.DefInt("atrLength", 14, core.PNorm(7, 30)) atrMultiplierSL := pol.Def("atrMultiplierSL", 1.8, core.PNorm(1.0, 3.0)) atrMultiplierTP := pol.Def("atrMultiplierTP", 2.5, core.PNorm(1.5, 5.0)) // 计算慢速EMA周期 slowLength := int(float64(fastLength) * emaRate) // 确定预热数量,取所有指标中最大的周期 warmupNum := fastLength if slowLength > warmupNum { warmupNum = slowLength } if rsiLength > warmupNum { warmupNum = rsiLength } if volLength > warmupNum { warmupNum = volLength } if atrLength > warmupNum { warmupNum = atrLength } // 额外增加1个K线用于突破确认 warmupNum += 1 return &strat.TradeStrat{ WarmupNum: warmupNum, EachMaxLong: 1, // 最多同时持有一个多头订单 EachMaxShort: 1, // 最多同时持有一个空头订单 HedgeOff: true, // 单向持仓模式 RunTimeFrames: []string{"8h"}, OnStartUp: func(s *strat.StratJob) { // 初始化策略数据 s.More = &StrategyData{atrValue: 0} }, OnBar: func(s *strat.StratJob) { e := s.Env // 计算技术指标 fastEMA := ta.EMA(e.Close, fastLength) slowEMA := ta.EMA(e.Close, slowLength) rsiValue := ta.RSI(e.Close, rsiLength) volMA := ta.SMA(e.Volume, volLength) atr := ta.ATR(e.High, e.Low, e.Close, atrLength) // 获取当前值 closePrice := e.Close.Get(0) highPrev := e.High.Get(1) lowPrev := e.Low.Get(1) volume := e.Volume.Get(0) volMAValue := volMA.Get(0) rsi := rsiValue.Get(0) atrValue := atr.Get(0) maCross := fastEMA.Cross(slowEMA) // 检查数据有效性 if math.IsNaN(closePrice) || math.IsNaN(highPrev) || math.IsNaN(lowPrev) || math.IsNaN(volume) || math.IsNaN(volMAValue) || math.IsNaN(rsi) || math.IsNaN(atrValue) { return } // 存储ATR值以便在跟踪止损中使用 data, _ := s.More.(*StrategyData) data.atrValue = atrValue // K线突破条件 longCandleBreak := closePrice > highPrev shortCandleBreak := closePrice < lowPrev // 入场条件 longCondition := maCross == 1 && rsi < float64(rsiOverbought) && volume > volMAValue && longCandleBreak shortCondition := maCross == -1 && rsi > float64(rsiOversold) && volume > volMAValue && shortCandleBreak // 执行交易 if longCondition && len(s.LongOrders) == 0 { // 计算具体止损止盈价格 longStop := closePrice - atrMultiplierSL*atrValue longTP := closePrice + atrMultiplierTP*atrValue s.OpenOrder(&strat.EnterReq{ Tag: "Long", Short: false, OrderType: core.OrderTypeMarket, StopLoss: longStop, TakeProfit: longTP, }) } if shortCondition && len(s.ShortOrders) == 0 { // 计算具体止损止盈价格 shortStop := closePrice + atrMultiplierSL*atrValue shortTP := closePrice - atrMultiplierTP*atrValue s.OpenOrder(&strat.EnterReq{ Tag: "Short", Short: true, OrderType: core.OrderTypeMarket, StopLoss: shortStop, TakeProfit: shortTP, }) } }, } }