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 J3956(pol *config.RunPolicyConfig) *strat.TradeStrat { fastLength := pol.DefInt("fastLength", 9, core.PNorm(5, 20)) slowMaRate := pol.Def("slowMaRate", 2.17, core.PNorm(1.5, 4)) signalLength := pol.DefInt("signalLength", 20, core.PNorm(9, 30)) entryLevel := pol.Def("entryLevel", 0, core.PNorm(-5, 5)) longExitLevel := pol.Def("longExitLevel", 11, core.PNorm(5, 20)) shortExitLevel := pol.Def("shortExitLevel", -9, core.PNorm(-20, -5)) // 计算慢速EMA周期 slowLength := int(float64(fastLength) * slowMaRate) // 确定预热数量,取所有参数中的最大值 warmupNum := fastLength if slowLength > warmupNum { warmupNum = slowLength } if signalLength > warmupNum { warmupNum = signalLength } return &strat.TradeStrat{ WarmupNum: warmupNum, HedgeOff: true, // 单向持仓模式 RunTimeFrames: []string{"8h"}, OnBar: func(s *strat.StratJob) { e := s.Env // 计算MACD指标 fastEma := ta.EMA(e.Close, fastLength) slowEma := ta.EMA(e.Close, slowLength) macd := fastEma.Sub(slowEma) signal := ta.EMA(macd, signalLength) hist := macd.Sub(signal) // 获取当前值 histVal := hist.Get(0) if math.IsNaN(histVal) { return } // 检查交叉信号 entryCross := hist.Cross(entryLevel) longEntry := entryCross == 1 // 上穿入场水平线 shortEntry := entryCross == -1 // 下穿入场水平线 longExit := hist.Cross(longExitLevel) == 1 // 上穿多头出场水平线 shortExit := hist.Cross(shortExitLevel) == -1 // 下穿空头出场水平线 // 获取当前持仓状态 longPos := s.Position(core.OdDirtLong, "") shortPos := s.Position(core.OdDirtShort, "") // 多头入场 if longEntry && longPos == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Long", }) } // 空头入场 if shortEntry && shortPos == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Short", Short: true, }) } // 多头出场 if longPos > 0 && longExit { s.CloseOrders(&strat.ExitReq{ Tag: "Long Exit", Dirt: core.OdDirtLong, }) } // 空头出场 if shortPos < 0 && shortExit { s.CloseOrders(&strat.ExitReq{ Tag: "Short Exit", Dirt: core.OdDirtShort, }) } }, } }