package llmjob import ( "math" "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" ) // COG 自定义重心振荡器指标 func COG(src *ta.Series, period int) *ta.Series { res := src.To("_cog", period) if res.Cached() { return res } data := src.Range(0, period) if len(data) < period { return res.Append(math.NaN()) } var sum1, sum2 float64 center := float64(period-1) / 2.0 for i := 0; i < period; i++ { weight := float64(i) - center sum1 += data[i] * weight sum2 += weight * weight } if sum2 != 0 { cogVal := -sum1 / sum2 return res.Append(cogVal) } return res.Append(0) } func J7854(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调超参数 length := pol.DefInt("length", 9, core.PNorm(3, 50)) // COG计算周期 length5 := pol.DefInt("length5", 3, core.PNorm(2, 20)) // RMA平滑周期 windowsize := pol.DefInt("windowsize", 6, core.PNorm(2, 20)) // ALMA窗口周期 offset := pol.Def("offset", 0.88, core.PNorm(0.5, 0.99)) // ALMA偏移量 sigma := pol.Def("sigma", 7, core.PNorm(1, 10)) // ALMA高斯系数 return &strat.TradeStrat{ WarmupNum: length + 50, // 确保有足够的历史数据 HedgeOff: true, // 单向持仓 EachMaxLong: 1, // 最多1个多单 EachMaxShort: 0, // 禁止做空 TimeFrames: "8h", OnBar: func(s *strat.StratJob) { e := s.Env // 检查数据长度是否足够 if e.Close.Len() < length { return } // 计算COG指标 cog1 := COG(e.Close, length) // 使用RMA平滑COG(对应原代码中的smooth选项,这里默认使用RMA) cogSmoothed := ta.RMA(cog1, length5) cog := cogSmoothed // 计算ALMA触发线 trigger := ta.ALMA(cog, windowsize, sigma, offset) // 获取最新值 cog1Val := cog1.Get(0) triggerVal := trigger.Get(0) // 检查有效数据 if math.IsNaN(cog1Val) || math.IsNaN(triggerVal) { return } // 检测COG1与触发线的交叉状态,只计算一次 crossState := cog1.Cross(trigger) // 检测COG1上穿触发线 if crossState == 1 { // 产生买入信号 s.OpenOrder(&strat.EnterReq{ Tag: "COG_Enter", }) } // 可选:添加退出逻辑 // 这里可以根据需要添加退出条件,比如COG1下穿trigger线 if crossState == -1 && len(s.LongOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "COG_Exit", Dirt: core.OdDirtLong, }) } }, } }