package llmjob import ( "math" "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/orm/ormo" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" ) func J7046(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调超参数 smaPeriod := pol.DefInt("smaPeriod", 22, core.PNorm(10, 50)) mult := pol.Def("mult", 1.0, core.PNorm(0.8, 3.0)) trailingLossPct := pol.Def("trailingLossPct", 0.075, core.PNorm(0.03, 0.15)) trailingPointsPct := pol.Def("trailingPointsPct", 0.05, core.PNorm(0.01, 0.10)) trailingOffsetPct := pol.Def("trailingOffsetPct", 0.005, core.PNorm(0.001, 0.02)) return &strat.TradeStrat{ Name: "Bollinger Band Breakout", WarmupNum: smaPeriod + 10, // 预热K线数量 HedgeOff: true, // 单向持仓模式 EachMaxLong: 1, // 最多1个多单 EachMaxShort: 1, // 最多1个空单 TimeFrames: "8h", OnBar: func(s *strat.StratJob) { e := s.Env closePrice := e.Close.Get(0) // 检查数据有效性 if math.IsNaN(closePrice) { return } // 计算布林带指标 upper, _, lower := ta.BBANDS(e.Close, smaPeriod, mult, mult) // 检测突破信号 longSignal := e.Close.Cross(upper) // 上穿上轨,返回1表示上穿 shortSignal := e.Close.Cross(lower) // 下穿下轨,返回-1表示下穿 // 多头入场逻辑 if longSignal == 1 && len(s.LongOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "long", Short: false, OrderType: core.OrderTypeMarket, }) } // 空头入场逻辑 if shortSignal == -1 && len(s.ShortOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "short", Short: true, OrderType: core.OrderTypeMarket, }) } // 更新追踪止损 updateTrailingStop(s, closePrice, trailingLossPct, trailingPointsPct, trailingOffsetPct) }, } } // 更新追踪止损的辅助函数 func updateTrailingStop(s *strat.StratJob, closePrice, lossPct, pointsPct, offsetPct float64) { // 处理多头仓位的追踪止损 for _, order := range s.LongOrders { if order.Status >= 2 { // 已入场 entryPrice := order.Enter.Average maxLossPrice := entryPrice * (1 - lossPct) // 最大损失价格 activationPrice := entryPrice * (1 + pointsPct) // 激活追踪的价格 // 获取当前止损信息 currentStop := order.GetStopLoss() var newStopPrice float64 // 判断是否已激活追踪止损 if closePrice >= activationPrice { // 已激活,使用偏移量计算止损 newStopPrice = closePrice * (1 - offsetPct) } else { // 未激活,使用最大损失作为止损 newStopPrice = maxLossPrice } // 只有当新止损价格更优(更高)时才更新 if currentStop == nil || newStopPrice > currentStop.Price { order.SetStopLoss(&ormo.ExitTrigger{ Price: newStopPrice, Tag: "trailing_stop", }) } } } // 处理空头仓位的追踪止损 for _, order := range s.ShortOrders { if order.Status >= 2 { // 已入场 entryPrice := order.Enter.Average maxLossPrice := entryPrice * (1 + lossPct) // 最大损失价格 activationPrice := entryPrice * (1 - pointsPct) // 激活追踪的价格 // 获取当前止损信息 currentStop := order.GetStopLoss() var newStopPrice float64 // 判断是否已激活追踪止损 if closePrice <= activationPrice { // 已激活,使用偏移量计算止损 newStopPrice = closePrice * (1 + offsetPct) } else { // 未激活,使用最大损失作为止损 newStopPrice = maxLossPrice } // 只有当新止损价格更优(更低)时才更新 if currentStop == nil || newStopPrice < currentStop.Price { order.SetStopLoss(&ormo.ExitTrigger{ Price: newStopPrice, Tag: "trailing_stop", }) } } } }