package llmjob import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" "math" ) func J656(pol *config.RunPolicyConfig) *strat.TradeStrat { shortPeriod := pol.DefInt("shortPeriod", 50, core.PNorm(10, 100)) maRate := pol.Def("maRate", 2.2, core.PNorm(1.5, 4.0)) smoothMethod := pol.DefInt("smoothMethod", 1, core.PUniform(1, 4)) useCurrentRes := pol.DefInt("useCurrentRes", 1, core.PUniform(0, 1)) priceSource := pol.DefInt("priceSource", 0, core.PUniform(0, 7)) // 0=close, 1=high, 2=low, 3=open, 4=hl2, 5=hlc3, 6=hlcc4, 7=ohlc4 // 计算长期均线周期 longPeriod := int(float64(shortPeriod) * maRate) // 确定预热数量,取长期均线周期的两倍以确保足够数据 warmupNum := longPeriod * 2 return &strat.TradeStrat{ WarmupNum: warmupNum, HedgeOff: true, // 单向持仓模式 RunTimeFrames: []string{"1h"}, OnPairInfos: func(s *strat.StratJob) []*strat.PairSub { // 如果不使用当前时间框架,则需要添加额外的时间框架数据 if useCurrentRes == 0 { // 使用周线作为额外时间框架,可根据需要调整 return []*strat.PairSub{{Pair: "_cur_", TimeFrame: "W", WarmupNum: warmupNum}} } return nil }, OnBar: func(s *strat.StratJob) { e := s.Env // 获取价格数据,根据用户选择的价格源 var price *ta.Series switch priceSource { case 0: // close price = e.Close case 1: // high price = e.High case 2: // low price = e.Low case 3: // open price = e.Open case 4: // hl2 price = ta.HL2(e.High, e.Low) case 5: // hlc3 price = ta.HLC3(e.High, e.Low, e.Close) case 6: // hlcc4 // 使用基本运算实现 hlcc4 = (high + low + close + close) / 4 price = e.High.Add(e.Low).Add(e.Close).Add(e.Close).Div(4) case 7: // ohlc4 // 使用基本运算实现 ohlc4 = (open + high + low + close) / 4 price = e.Open.Add(e.High).Add(e.Low).Add(e.Close).Div(4) default: price = e.Close } // 如果不使用当前时间框架,则从More中获取其他时间框架的数据 if useCurrentRes == 0 { // 从More中获取其他时间框架的价格数据和移动平均线 if s.More == nil { return } moreData, ok := s.More.(map[string]interface{}) if !ok { return } if mtData, ok := moreData["W"]; ok { if mtPrice, ok := mtData.(*ta.Series); ok { price = mtPrice } if mtMA, ok := mtData.(map[string]interface{})["ma"]; ok { if maData, ok := mtMA.(map[string]*ta.Series); ok { if shortMA, ok := maData["short"]; ok { if longMA, ok := maData["long"]; ok { // 获取当前和前一个值 shortMA0 := shortMA.Get(0) shortMA1 := shortMA.Get(1) longMA0 := longMA.Get(0) longMA1 := longMA.Get(1) close0 := e.Close.Get(0) close1 := e.Close.Get(1) // 检查数据有效性 if math.IsNaN(shortMA0) || math.IsNaN(shortMA1) || math.IsNaN(longMA0) || math.IsNaN(longMA1) || math.IsNaN(close0) || math.IsNaN(close1) { return } // 计算均线交叉信号 crossUp := shortMA1 <= longMA1 && shortMA0 > longMA0 crossDown := shortMA1 >= longMA1 && shortMA0 < longMA0 // 计算价格趋势 priceUp := close0 > close1 priceDown := close0 < close1 // 生成交易信号 buySignal := crossUp && priceUp sellSignal := crossDown && priceDown // 执行交易 if buySignal { // 如果没有多头持仓,则开多单 if len(s.LongOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Enter Long", }) } // 如果有空头持仓,则平空单 if len(s.ShortOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "Close Short", Dirt: core.OdDirtShort, }) } } else if sellSignal { // 如果没有空头持仓,则开空单 if len(s.ShortOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Enter Short", Short: true, }) } // 如果有多头持仓,则平多单 if len(s.LongOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "Close Long", Dirt: core.OdDirtLong, }) } } return } } } } } return } // 确保有足够的数据 if price.Len() < longPeriod { return } // 根据选择的计算方法计算短期和长期移动平均线 var shortMA, longMA *ta.Series switch smoothMethod { case 1: // SMA shortMA = ta.SMA(price, shortPeriod) longMA = ta.SMA(price, longPeriod) case 2: // EMA shortMA = ta.EMA(price, shortPeriod) longMA = ta.EMA(price, longPeriod) case 3: // WMA shortMA = ta.WMA(price, shortPeriod) longMA = ta.WMA(price, longPeriod) case 4: // 线性回归 shortMA = ta.LinReg(price, shortPeriod) longMA = ta.LinReg(price, longPeriod) default: shortMA = ta.EMA(price, shortPeriod) longMA = ta.EMA(price, longPeriod) } // 获取当前和前一个值 shortMA0 := shortMA.Get(0) shortMA1 := shortMA.Get(1) longMA0 := longMA.Get(0) longMA1 := longMA.Get(1) close0 := e.Close.Get(0) close1 := e.Close.Get(1) // 检查数据有效性 if math.IsNaN(shortMA0) || math.IsNaN(shortMA1) || math.IsNaN(longMA0) || math.IsNaN(longMA1) || math.IsNaN(close0) || math.IsNaN(close1) { return } // 计算均线交叉信号 crossUp := shortMA1 <= longMA1 && shortMA0 > longMA0 crossDown := shortMA1 >= longMA1 && shortMA0 < longMA0 // 计算价格趋势 priceUp := close0 > close1 priceDown := close0 < close1 // 生成交易信号 buySignal := crossUp && priceUp sellSignal := crossDown && priceDown // 执行交易 if buySignal { // 如果没有多头持仓,则开多单 if len(s.LongOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Enter Long", }) } // 如果有空头持仓,则平空单 if len(s.ShortOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "Close Short", Dirt: core.OdDirtShort, }) } } else if sellSignal { // 如果没有空头持仓,则开空单 if len(s.ShortOrders) == 0 { s.OpenOrder(&strat.EnterReq{ Tag: "Enter Short", Short: true, }) } // 如果有多头持仓,则平多单 if len(s.LongOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "Close Long", Dirt: core.OdDirtLong, }) } } }, OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) { // 处理其他时间框架的数据 if useCurrentRes == 0 && tf == "W" { // 根据用户选择的价格源获取价格数据 var price *ta.Series switch priceSource { case 0: // close price = e.Close case 1: // high price = e.High case 2: // low price = e.Low case 3: // open price = e.Open case 4: // hl2 price = ta.HL2(e.High, e.Low) case 5: // hlc3 price = ta.HLC3(e.High, e.Low, e.Close) case 6: // hlcc4 // 使用基本运算实现 hlcc4 = (high + low + close + close) / 4 price = e.High.Add(e.Low).Add(e.Close).Add(e.Close).Div(4) case 7: // ohlc4 // 使用基本运算实现 ohlc4 = (open + high + low + close) / 4 price = e.Open.Add(e.High).Add(e.Low).Add(e.Close).Div(4) default: price = e.Close } // 计算移动平均线 var shortMA, longMA *ta.Series switch smoothMethod { case 1: // SMA shortMA = ta.SMA(price, shortPeriod) longMA = ta.SMA(price, longPeriod) case 2: // EMA shortMA = ta.EMA(price, shortPeriod) longMA = ta.EMA(price, longPeriod) case 3: // WMA shortMA = ta.WMA(price, shortPeriod) longMA = ta.WMA(price, longPeriod) case 4: // 线性回归 shortMA = ta.LinReg(price, shortPeriod) longMA = ta.LinReg(price, longPeriod) default: shortMA = ta.EMA(price, shortPeriod) longMA = ta.EMA(price, longPeriod) } // 存储计算结果到s.More中 if s.More == nil { s.More = make(map[string]interface{}) } moreData, ok := s.More.(map[string]interface{}) if !ok { s.More = make(map[string]interface{}) moreData = s.More.(map[string]interface{}) } moreData["W"] = map[string]interface{}{ "price": price, "ma": map[string]*ta.Series{ "short": shortMA, "long": longMA, }, } } }, } }