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" ) // AtrRsiStrategy 存储每个品种的持仓期间最高价和最低价 type AtrRsiStrategy struct { IntraTradeHigh float64 IntraTradeLow float64 } func J2625(pol *config.RunPolicyConfig) *strat.TradeStrat { atrLength := pol.DefInt("atr_length", 18, core.PNorm(10, 50)) atrMaRate := pol.Def("atr_ma_rate", 1.8, core.PNorm(1.2, 3.0)) rsiLength := pol.DefInt("rsi_length", 9, core.PNorm(7, 30)) rsiEntry := pol.DefInt("rsi_entry", 7, core.PNorm(5, 20)) atrMaNormMin := pol.Def("atr_ma_norm_min", 0.3, core.PNorm(0.1, 0.5)) atrMaNormMax := pol.Def("atr_ma_norm_max", 0.7, core.PNorm(0.5, 1.0)) trailingPercent := pol.Def("trailing_percent", 1.3, core.PNorm(0.5, 3.0)) // 计算ATR移动平均线周期 atrMaLength := int(float64(atrLength) * atrMaRate) // 计算RSI买入和卖出阈值 rsiBuy := 50 + float64(rsiEntry) rsiSell := 50 - float64(rsiEntry) // 确定预热数量,取最大参数值 warmupNum := atrMaLength if rsiLength > warmupNum { warmupNum = rsiLength } return &strat.TradeStrat{ WarmupNum: warmupNum, HedgeOff: true, // 单向持仓模式 RunTimeFrames: []string{"1h"}, OnStartUp: func(s *strat.StratJob) { // 初始化每个品种的持仓期间最高价和最低价 s.More = &AtrRsiStrategy{ IntraTradeHigh: 0, IntraTradeLow: 0, } }, OnBar: func(s *strat.StratJob) { e := s.Env m, _ := s.More.(*AtrRsiStrategy) // 计算技术指标 atrValue := ta.ATR(e.High, e.Low, e.Close, atrLength) atrMa := ta.SMA(atrValue, atrMaLength) rsiValue := ta.RSI(e.Close, rsiLength) // 获取当前价格 closePrice := e.Close.Get(0) highPrice := e.High.Get(0) lowPrice := e.Low.Get(0) // 检查数据有效性 if math.IsNaN(closePrice) || math.IsNaN(highPrice) || math.IsNaN(lowPrice) || math.IsNaN(atrValue.Get(0)) || math.IsNaN(atrMa.Get(0)) || math.IsNaN(rsiValue.Get(0)) { return } // 计算ATR移动平均线的标准化值 atrMaNorm := atrMa.Get(0) / closePrice * 100 // 获取当前持仓状态 longOrders := s.LongOrders shortOrders := s.ShortOrders hasLongPosition := len(longOrders) > 0 hasShortPosition := len(shortOrders) > 0 // 无持仓状态 if !hasLongPosition && !hasShortPosition { // 重置持仓期间最高价和最低价 m.IntraTradeHigh = highPrice m.IntraTradeLow = lowPrice // 检查波动率是否在适合交易范围内 if atrMaNorm >= atrMaNormMin && atrMaNorm <= atrMaNormMax { // 检查当前波动率是否高于平均波动率 if atrValue.Get(0) > atrMa.Get(0) { // 检查RSI信号 if rsiValue.Get(0) > rsiBuy { // RSI超买,做多 s.OpenOrder(&strat.EnterReq{ Tag: "B1", OrderType: core.OrderTypeLimit, Limit: closePrice + 5, }) } else if rsiValue.Get(0) < rsiSell { // RSI超卖,做空 s.OpenOrder(&strat.EnterReq{ Tag: "S1", Short: true, OrderType: core.OrderTypeLimit, Limit: closePrice - 5, }) } } } } else if hasLongPosition { // 多头持仓状态 // 更新持仓期间最高价 if highPrice > m.IntraTradeHigh { m.IntraTradeHigh = highPrice } m.IntraTradeLow = lowPrice // 计算多头追踪止损价格 longTp := m.IntraTradeHigh * (1 - trailingPercent/100) // 获取入场价格 enterPrice := longOrders[0].InitPrice // 设置止损和止盈 for _, od := range longOrders { od.SetStopLoss(&ormo.ExitTrigger{ Price: longTp, Rate: 1.0, // 全部退出 Tag: "trailing_stop", }) od.SetTakeProfit(&ormo.ExitTrigger{ Price: enterPrice * 1.03, Rate: 1.0, // 全部退出 Tag: "take_profit", }) } } else if hasShortPosition { // 空头持仓状态 m.IntraTradeHigh = highPrice // 更新持仓期间最低价 if lowPrice < m.IntraTradeLow { m.IntraTradeLow = lowPrice } // 计算空头追踪止损价格 shortTp := m.IntraTradeLow * (1 + trailingPercent/100) // 获取入场价格 enterPrice := shortOrders[0].InitPrice // 设置止损和止盈 for _, od := range shortOrders { od.SetStopLoss(&ormo.ExitTrigger{ Price: shortTp, Rate: 1.0, // 全部退出 Tag: "trailing_stop", }) od.SetTakeProfit(&ormo.ExitTrigger{ Price: enterPrice * 0.94, Rate: 1.0, // 全部退出 Tag: "take_profit", }) } } }, } }