// 修复后的banbot完整策略代码 package llmjob import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" ) type MacdRsiState struct { above50 bool // 标记RSI是否上穿50 below50 bool // 标记RSI是否下穿50 longEntryTime int64 // 记录多头入场时间 shortEntryTime int64 // 记录空头入场时间 } func J2775(pol *config.RunPolicyConfig) *strat.TradeStrat { fastPeriod := pol.DefInt("fastPeriod", 15, core.PNorm(5, 20)) macdRate := pol.Def("macdRate", 2.5, core.PNorm(1.5, 4)) rsiPeriod := pol.DefInt("rsiPeriod", 16, core.PNorm(7, 21)) exitBars := pol.DefInt("exitBars", 5, core.PNorm(1, 10)) signalSmoothing := pol.DefInt("signalSmoothing", 9, core.PNorm(5, 15)) // 计算MACD慢线长度 slowPeriod := int(float64(fastPeriod) * macdRate) return &strat.TradeStrat{ WarmupNum: slowPeriod + signalSmoothing + rsiPeriod, HedgeOff: true, // 单向持仓 EachMaxLong: 1, // 最多一个多头订单 EachMaxShort: 1, // 最多一个空头订单 RunTimeFrames: []string{"8h"}, OnStartUp: func(s *strat.StratJob) { s.More = &MacdRsiState{ above50: false, below50: false, longEntryTime: 0, shortEntryTime: 0, } }, OnBar: func(s *strat.StratJob) { e := s.Env state, _ := s.More.(*MacdRsiState) // 计算MACD指标 macdLine, signalLine := ta.MACD(e.Close, fastPeriod, slowPeriod, signalSmoothing) // 计算RSI指标 rsi := ta.RSI(e.Close, rsiPeriod) // 检测MACD金叉和死叉 bullishCross := macdLine.Cross(signalLine) == 1 bearishCross := macdLine.Cross(signalLine) == -1 // 更新RSI状态 if rsi.Get(0) > 50 && rsi.Get(1) <= 50 { state.above50 = true } if rsi.Get(0) < 50 && rsi.Get(1) >= 50 { state.below50 = true } // 执行交易信号 if bullishCross && state.above50 && len(s.LongOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Buy", }) state.longEntryTime = e.TimeStop } if bearishCross && state.below50 && len(s.ShortOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Sell", Short: true, }) state.shortEntryTime = e.TimeStop } // 检查退出条件 if len(s.LongOrders) > 0 && state.longEntryTime > 0 { holdBars := e.BarCount(state.longEntryTime) if holdBars >= float64(exitBars) { s.CloseOrders(&strat.ExitReq{ Tag: "Exit Long", Dirt: core.OdDirtLong, }) state.longEntryTime = 0 } } if len(s.ShortOrders) > 0 && state.shortEntryTime > 0 { holdBars := e.BarCount(state.shortEntryTime) if holdBars >= float64(exitBars) { s.CloseOrders(&strat.ExitReq{ Tag: "Exit Short", Dirt: core.OdDirtShort, }) state.shortEntryTime = 0 } } }, } }