// 修复后的完整策略代码 // 请勿修改package包名和任意函数名 package llmjob import ( "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" "math" ) /* 因止盈止损触发价未检查是否合理的bug导致虚假净值曲线 */ // SuperTrendData 存储每个品种的Supertrend相关数据 type SuperTrendData struct { trend int // 当前趋势方向,1表示上升趋势,-1表示下降趋势 longTrailStop float64 // 多头仓位的移动止损价格 shortTrailStop float64 // 空头仓位的移动止损价格 up float64 // 上轨值 dn float64 // 下轨值 } func J1662(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调参数 atrPeriod := pol.DefInt("atrPeriod", 8, core.PNorm(5, 30)) atrMultiplier := pol.Def("atrMultiplier", 2.5, core.PNorm(1.5, 5.0)) lenAtr := 20 baseAtrLen := int(math.Round(float64(lenAtr) * 4.3)) return &strat.TradeStrat{ WarmupNum: baseAtrLen, // 预热K线数量,确保有足够数据计算指标 RunTimeFrames: []string{"8h"}, OnStartUp: func(s *strat.StratJob) { // 初始化每个品种的Supertrend数据 s.More = &SuperTrendData{ trend: 1, // 初始趋势设为上升 longTrailStop: math.NaN(), shortTrailStop: math.NaN(), up: math.NaN(), dn: math.NaN(), } }, OnBar: func(s *strat.StratJob) { e := s.Env data, _ := s.More.(*SuperTrendData) // 计算数据源 (hl2 = (high + low) / 2) src := ta.HL2(e.High, e.Low) // 计算ATR值 atr := ta.ATR(e.High, e.Low, e.Close, atrPeriod) // 计算Supertrend指标 upVal := src.Get(0) - atr.Get(0)*atrMultiplier dnVal := src.Get(0) + atr.Get(0)*atrMultiplier atr2 := ta.ATR(e.High, e.Low, e.Close, lenAtr) atrBase := ta.Lowest(ta.Highest(atr2, lenAtr), baseAtrLen).Get(0) // 获取历史值 up1 := data.up if math.IsNaN(up1) { up1 = upVal } dn1 := data.dn if math.IsNaN(dn1) { dn1 = dnVal } // 更新上轨和下轨 close1 := e.Close.Get(1) if !math.IsNaN(close1) { if close1 > up1 { upVal = math.Max(upVal, up1) } if close1 < dn1 { dnVal = math.Min(dnVal, dn1) } } // 保存当前上下轨值 data.up = upVal data.dn = dnVal // 判断趋势方向 prevTrend := data.trend closePrice := e.Close.Get(0) if !math.IsNaN(closePrice) && !math.IsNaN(dn1) && !math.IsNaN(up1) && !math.IsNaN(atrBase) { if data.trend == -1 && closePrice > dn1 { data.trend = 1 // 趋势由下降转为上升 } else if data.trend == 1 && closePrice < up1 { data.trend = -1 // 趋势由上升转为下降 } } // 生成交易信号 buySignal := data.trend == 1 && prevTrend == -1 sellSignal := data.trend == -1 && prevTrend == 1 // 执行交易策略 if buySignal { // 开仓多头,使用下轨作为触发价格 s.OpenOrder(&strat.EnterReq{ Tag: "Long", Stop: dnVal, Log: true, }) s.CloseOrders(&strat.ExitReq{ Tag: "XShort", Dirt: core.OdDirtShort, Log: true, }) } if sellSignal { // 开仓空头,使用上轨作为触发价格 s.OpenOrder(&strat.EnterReq{ Tag: "Short", Short: true, Stop: upVal, Log: true, }) s.CloseOrders(&strat.ExitReq{ Tag: "XLong", Dirt: core.OdDirtLong, Log: true, }) } pipValue := atrBase * 0 trailingValue := atrBase * 0 // 移动止损逻辑 if s.OrderNum > 0 { // 多头移动止损 if len(s.LongOrders) > 0 { // 获取持仓均价 avgPrice := s.PositionAvgPrice(core.OdDirtLong, "") if avgPrice > 0 { if math.IsNaN(data.longTrailStop) || closePrice > avgPrice+trailingValue { data.longTrailStop = e.High.Get(0) - trailingValue } // 计算初始止损 longStopLevel := upVal - pipValue // 使用更严格的止损(更接近当前价格的止损) finalStop := math.Max(data.longTrailStop, longStopLevel) if finalStop >= closePrice { s.CloseOrders(&strat.ExitReq{ Tag: "SLLong", Dirt: core.OdDirtLong, }) } else { s.SetAllStopLoss(core.OdDirtLong, &ormo.ExitTrigger{ Price: finalStop, Tag: "sl", }) } } } // 空头移动止损 if len(s.ShortOrders) > 0 { // 获取持仓均价 avgPrice := s.PositionAvgPrice(core.OdDirtShort, "") if avgPrice > 0 { if math.IsNaN(data.shortTrailStop) || closePrice < avgPrice-trailingValue { data.shortTrailStop = e.Low.Get(0) + trailingValue } // 计算初始止损 shortStopLevel := dnVal + pipValue // 使用更严格的止损(更接近当前价格的止损) finalStop := math.Min(data.shortTrailStop, shortStopLevel) if finalStop < closePrice { s.CloseOrders(&strat.ExitReq{ Tag: "SLShort", Dirt: core.OdDirtShort, }) } else { s.SetAllStopLoss(core.OdDirtShort, &ormo.ExitTrigger{ Price: finalStop, Tag: "sl", }) } } } } }, } }