package llmjob import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" ) // Sta2391 用于保存每个品种的策略状态 type Sta2391 struct { posReversal123 float64 // 123反转策略的信号值 posmStochCross float64 // 随机指标交叉策略的信号值 } func J2391(pol *config.RunPolicyConfig) *strat.TradeStrat { // 123反转策略参数 length := pol.DefInt("length", 40, core.PNorm(5, 30)) kSmoothing := pol.DefInt("kSmoothing", 1, core.PNorm(1, 5)) dLength := pol.DefInt("dLength", 3, core.PNorm(1, 5)) level := pol.Def("level", 30, core.PNorm(30, 70)) // 随机指标交叉策略参数 lengthSC := pol.DefInt("lengthSC", 20, core.PNorm(3, 21)) dLengthSC := pol.DefInt("dLengthSC", 3, core.PNorm(1, 5)) oversold := pol.Def("oversold", 10, core.PNorm(10, 30)) overbought := pol.Def("overbought", 90, core.PNorm(70, 90)) reverse := pol.Def("reverse", 0, core.PUniform(0, 1)) // 0表示不反转,1表示反转 // 计算预热数量,取两个策略中需要的历史数据最大值 warmupNum := length if lengthSC > warmupNum { warmupNum = lengthSC } if kSmoothing+dLength > warmupNum { warmupNum = kSmoothing + dLength } if dLengthSC > warmupNum { warmupNum = dLengthSC } // 额外需要2个历史K线判断价格反转 warmupNum += 2 return &strat.TradeStrat{ WarmupNum: warmupNum, HedgeOff: true, // 单向持仓模式 TimeFrames: "8h", OnStartUp: func(s *strat.StratJob) { // 初始化策略状态 s.More = &Sta2391{ posReversal123: 0, posmStochCross: 0, } }, OnBar: func(s *strat.StratJob) { e := s.Env state, _ := s.More.(*Sta2391) // 获取价格数据 close0 := e.Close.Get(0) // 当前收盘价 close1 := e.Close.Get(1) // 前一个收盘价 close2 := e.Close.Get(2) // 前两个收盘价 // 1. 计算123反转策略信号 // 计算随机指标 kFast := ta.Stoch(e.High, e.Low, e.Close, length) // 对K值进行平滑 vFast := ta.SMA(kFast, kSmoothing) // 计算D值 vSlow := ta.SMA(vFast, dLength) // 获取当前值 vFastVal := vFast.Get(0) vSlowVal := vSlow.Get(0) // 判断123反转策略信号 if close2 < close1 && close1 < close0 && vFastVal < vSlowVal && vFastVal > level { // 买入信号:两天内收盘价从低点转为高点,且随机指标快速线在慢速线下方但高于阈值 state.posReversal123 = 1 } else if close2 > close1 && close1 > close0 && vFastVal > vSlowVal && vFastVal < level { // 卖出信号:两天内收盘价从高点转为低点,且随机指标快速线在慢速线上方但低于阈值 state.posReversal123 = -1 } // 否则保持之前的信号(不需要else,因为不改变state.posReversal123的值) // 2. 计算随机指标交叉策略信号 // 计算随机指标 kFastSC := ta.Stoch(e.High, e.Low, e.Close, lengthSC) // 计算D值 vSlowSC := ta.SMA(kFastSC, dLengthSC) // 获取当前值 vFastSCVal := kFastSC.Get(0) vSlowSCVal := vSlowSC.Get(0) // 判断随机指标交叉策略信号 if vFastSCVal >= vSlowSCVal && vFastSCVal < oversold && vSlowSCVal < oversold { // 买入信号:快速线在慢速线上方,且两者都处于超卖区域 state.posmStochCross = 1 } else if vFastSCVal < vSlowSCVal && vFastSCVal > overbought && vSlowSCVal > overbought { // 卖出信号:快速线在慢速线下方,且两者都处于超买区域 state.posmStochCross = -1 } // 否则保持之前的信号(不需要else,因为不改变state.posmStochCross的值) // 3. 组合信号 var pos float64 if state.posReversal123 == 1 && state.posmStochCross == 1 { // 两个策略都给出买入信号 pos = 1 } else if state.posReversal123 == -1 && state.posmStochCross == -1 { // 两个策略都给出卖出信号 pos = -1 } else { // 信号不一致,无交易信号 pos = 0 } // 4. 处理信号反转 var possig float64 if reverse == 1 { // 明确检查reverse是否为1 if pos == 1 { possig = -1 // 反转买入信号为卖出信号 } else if pos == -1 { possig = 1 // 反转卖出信号为买入信号 } else { possig = 0 } } else { possig = pos // 不反转信号 } // 5. 执行交易 if possig == 1 { // 买入信号 if len(s.LongOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "long", }) } // 如果有做空持仓,平仓 if len(s.ShortOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "close_short", Dirt: core.OdDirtShort, }) } } else if possig == -1 { // 卖出信号 if len(s.ShortOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "short", Short: true, }) } // 如果有做多持仓,平仓 if len(s.LongOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "close_long", Dirt: core.OdDirtLong, }) } } else if possig == 0 { // 无信号,平仓所有持仓 if len(s.LongOrders) > 0 || len(s.ShortOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "close_all", Dirt: core.OdDirtBoth, }) } } }, } }