package llmjob import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ) type NinjaState struct { longEntryBar int64 shortEntryBar int64 } func J7050(pol *config.RunPolicyConfig) *strat.TradeStrat { lookbackPeriods := pol.DefInt("lookbackPeriods", 4, core.PUniform(2, 8)) entryOffsetRatio := pol.Def("entryOffsetRatio", 0.85, core.PUniform(0.2, 0.9)) barsToHold := pol.DefInt("barsToHold", 0, core.PUniform(0, 5)) return &strat.TradeStrat{ WarmupNum: lookbackPeriods + 1, HedgeOff: true, TimeFrames: "4h", OnStartUp: func(s *strat.StratJob) { s.More = &NinjaState{ longEntryBar: -1, shortEntryBar: -1, } }, OnBar: func(s *strat.StratJob) { e := s.Env state := s.More.(*NinjaState) currentBar := e.TimeStop / e.TFMSecs // 修复:在K线开始时,首先检查是否需要平掉上一根K线建的仓位(对应原始策略中的 K 线收盘平仓) if barsToHold == 0 && s.OrderNum > 0 { s.CloseOrders(&strat.ExitReq{Tag: "close_at_bar_close"}) } // 获取历史K线数据 low1 := e.Low.Get(1) low2 := e.Low.Get(2) low3 := e.Low.Get(3) high1 := e.High.Get(1) high2 := e.High.Get(2) high3 := e.High.Get(3) c := e.Close.Get(0) // 优化:缓存重复计算 range1 := high1 - low1 // 计算做多条件:连续3根K线最低价递减且当前收盘价 <= low[1] longCondition := low1 > low2 && low2 > low3 && c <= low1 if longCondition && len(s.LongOrders) == 0 { // 计算止损触发价:low[1] + (high[1]-low[1]) * entryOffsetRatio stopPrice := low1 + range1*entryOffsetRatio s.OpenOrder(&strat.EnterReq{ Tag: "BarUp", Stop: stopPrice, }) state.longEntryBar = currentBar } // 计算做空条件:连续3根K线最高价递增且当前收盘价 >= high[1] shortCondition := high1 < high2 && high2 < high3 && c >= high1 if shortCondition && len(s.ShortOrders) == 0 { // 计算止损触发价:high[1] - (high[1]-low[1]) * entryOffsetRatio stopPrice := high1 - range1*entryOffsetRatio s.OpenOrder(&strat.EnterReq{ Tag: "BarDown", Short: true, Stop: stopPrice, }) state.shortEntryBar = currentBar } // 平仓逻辑:达到持仓K线数限制 (当 barsToHold > 0 时的增强逻辑) if barsToHold > 0 { if len(s.LongOrders) > 0 && state.longEntryBar >= 0 && currentBar-state.longEntryBar >= int64(barsToHold) { s.CloseOrders(&strat.ExitReq{Tag: "close_long", Dirt: core.OdDirtLong}) } if len(s.ShortOrders) > 0 && state.shortEntryBar >= 0 && currentBar-state.shortEntryBar >= int64(barsToHold) { s.CloseOrders(&strat.ExitReq{Tag: "close_short", Dirt: core.OdDirtShort}) } } // 清理已平仓的记录 if len(s.LongOrders) == 0 { state.longEntryBar = -1 } if len(s.ShortOrders) == 0 { state.shortEntryBar = -1 } }, } }