package llmjob import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ) // ConsecutiveState 存储每个品种的连续计数状态 type ConsecutiveState struct { ups float64 // 连续上涨K线数 dns float64 // 连续下跌K线数 } func J7801(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义超参数 consecutiveBarsUp := pol.DefInt("consecutiveBarsUp", 3, core.PNorm(2, 12)) consecutiveBarsDown := pol.DefInt("consecutiveBarsDown", 4, core.PNorm(2, 12)) return &strat.TradeStrat{ Name: "Consecutive Up/Down Strategy", WarmupNum: 5, // 需要至少5根K线来确保前值有效 HedgeOff: true, // 单向持仓模式 EachMaxLong: 1, // 最大持仓1个多单 EachMaxShort: 1, // 最大持仓1个空单 TimeFrames: "8h", OnStartUp: func(s *strat.StratJob) { // 初始化每个品种的状态 s.More = &ConsecutiveState{ ups: 0, dns: 0, } }, OnBar: func(s *strat.StratJob) { e := s.Env state, _ := s.More.(*ConsecutiveState) // 获取当前和前一根K线的收盘价 currentPrice := e.Close.Get(0) prevPrice := e.Close.Get(1) // 更新连续上涨计数器 if currentPrice > prevPrice { state.ups = state.ups + 1 state.dns = 0 // 重置连续下跌计数 } else if currentPrice < prevPrice { state.dns = state.dns + 1 state.ups = 0 // 重置连续上涨计数 } else { // 价格持平,重置两个计数器 state.ups = 0 state.dns = 0 } // 检查买入条件:连续上涨达到阈值且没有多单 if state.ups >= float64(consecutiveBarsUp) && len(s.LongOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "ConsUpLE", }) } // 检查卖出条件:连续下跌达到阈值且没有空单 if state.dns >= float64(consecutiveBarsDown) && len(s.ShortOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "ConsDnSE", Short: true, }) } }, } }