package llmjob import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" ) // StrategyMore 存储每个品种的策略状态 type StrategyMore struct { LastBarNum float64 // 上次交易的K线编号 } // MultiEMACross 多重均线交叉与时间间隔整合策略 func J4225(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调参数 emaBasePeriod := pol.DefInt("emaBasePeriod", 4, core.PNorm(3, 15)) emaMidRatio := pol.Def("emaMidRatio", 2.1, core.PNorm(1.5, 4)) emaSlowRatio := pol.Def("emaSlowRatio", 10, core.PNorm(5, 20)) timeInterval := pol.DefInt("timeInterval", 35, core.PNorm(10, 100)) atrMultiplier := pol.Def("atrMultiplier", 1.9, core.PNorm(0.5, 5)) // 计算EMA周期 emaMidPeriod := int(float64(emaBasePeriod) * emaMidRatio) emaSlowPeriod := int(float64(emaBasePeriod) * emaSlowRatio) // 确定预热K线数量,取最慢EMA周期的2倍 warmupNum := emaSlowPeriod * 2 return &strat.TradeStrat{ WarmupNum: warmupNum, HedgeOff: true, // 单向持仓模式 RunTimeFrames: []string{"8h"}, OnStartUp: func(s *strat.StratJob) { // 初始化每个品种的策略状态 s.More = &StrategyMore{ LastBarNum: -1, // 初始化为-1,表示尚未交易 } }, OnBar: func(s *strat.StratJob) { e := s.Env m, _ := s.More.(*StrategyMore) // 计算EMA指标 emaFast := ta.EMA(e.Close, emaBasePeriod) emaMid := ta.EMA(e.Close, emaMidPeriod) emaSlow := ta.EMA(e.Close, emaSlowPeriod) // 计算ATR用于动态止盈止损 atr := ta.ATR(e.High, e.Low, e.Close, 14) atrVal := atr.Get(0) // 检查EMA交叉条件 - 修复重复计算问题 fastCrossSlow := emaFast.Cross(emaSlow) midCrossSlow := emaMid.Cross(emaSlow) fastCrossSlowUp := fastCrossSlow == 1 // 快线上穿慢线 midCrossSlowUp := midCrossSlow == 1 // 中线上穿慢线 fastCrossSlowDown := fastCrossSlow == -1 // 快线下穿慢线 midCrossSlowDown := midCrossSlow == -1 // 中线下穿慢线 // 生成交易信号 buyCondition := fastCrossSlowUp && midCrossSlowUp sellCondition := fastCrossSlowDown && midCrossSlowDown // 检查时间间隔是否满足要求 currentBarNum := e.BarCount(0) barsSinceLastTrade := currentBarNum - m.LastBarNum timeElapsedOk := m.LastBarNum == -1 || barsSinceLastTrade >= float64(timeInterval) // 如果有交易信号且时间间隔满足要求 if (buyCondition || sellCondition) && timeElapsedOk { // 先平掉所有现有仓位 if len(s.LongOrders) > 0 || len(s.ShortOrders) > 0 { s.CloseOrders(&strat.ExitReq{ Tag: "close_all", Dirt: core.OdDirtBoth, Force: true, }) } // 计算止盈止损价格 stopLossDist := atrVal * atrMultiplier takeProfitDist := stopLossDist * 1.67 // 保持5:3的盈亏比 // 根据信号方向开仓 if buyCondition { s.OpenOrder(&strat.EnterReq{ Tag: "Buy", Short: false, OrderType: core.OrderTypeMarket, StopLossVal: stopLossDist, TakeProfitVal: takeProfitDist, StopLossTag: "stop_loss", TakeProfitTag: "take_profit", }) m.LastBarNum = currentBarNum } else if sellCondition { s.OpenOrder(&strat.EnterReq{ Tag: "Sell", Short: true, OrderType: core.OrderTypeMarket, StopLossVal: stopLossDist, TakeProfitVal: takeProfitDist, StopLossTag: "stop_loss", TakeProfitTag: "take_profit", }) m.LastBarNum = currentBarNum } } }, } }