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" ) // ZeroLagEMA 计算零滞后指数移动平均线 func ZeroLagEMA(source *ta.Series, length int) *ta.Series { res := source.To("_zlema", length) if res.Cached() { return res } if source.Len() < length { return res.Append(math.NaN()) } ema1 := ta.EMA(source, length) ema2 := ta.EMA(ema1, length) c1 := ema1.Get(0) - ema2.Get(0) zlema := ema1.Get(0) + c1 return res.Append(zlema) } // ZlemaState 存储每个品种的策略状态 type ZlemaState struct { goLong bool sectionLongs int sectionShorts int sectionLongConditions int sectionShortConditions int totalLongs float64 totalShorts float64 averageLongs float64 averageShorts float64 lastHigh float64 lastLow float64 inLong bool inShort bool } func J2984(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调超参数 fastPeriod := pol.DefInt("fastPeriod", 10, core.PNorm(3, 20)) maRate := pol.Def("maRate", 2.4, core.PNorm(1.5, 5)) takeProfitRate := pol.Def("takeProfitRate", 3.5, core.PNorm(1, 10)) trailingStopRate := pol.Def("trailingStopRate", 3.5, core.PNorm(1, 8)) trailingActivationRate := pol.Def("trailingActivationRate", 16, core.PNorm(5, 25)) stopLossPercent := pol.Def("stopLossPercent", 7.5, core.PNorm(1, 15)) // 金字塔加仓参数 pyramidingLess := pol.DefInt("pyramidingLess", 1, core.PNorm(0, 5)) pyramidingEqual := pol.DefInt("pyramidingEqual", 0, core.PNorm(0, 5)) pyramidingGreater := pol.DefInt("pyramidingGreater", 1000000, core.PNorm(100, 1000000)) // 交易方向控制参数 longsOnly := pol.Def("longsOnly", 0, core.PUniform(0, 1)) > 0.5 shortsOnly := pol.Def("shortsOnly", 0, core.PUniform(0, 1)) > 0.5 flipOpens := pol.Def("flipOpens", 0, core.PUniform(0, 1)) > 0.5 // 计算慢线周期 slowPeriod := int(float64(fastPeriod) * maRate) return &strat.TradeStrat{ WarmupNum: slowPeriod * 2, // 确保有足够的数据计算指标 HedgeOff: true, // 单向持仓模式 EachMaxLong: 1, // 最多开1单多仓 EachMaxShort: 1, // 最多开1单空仓 DrawDownExit: false, // 不使用回撤止盈 RunTimeFrames: []string{"8h"}, StopLoss: 0.075, OnStartUp: func(s *strat.StratJob) { // 初始化策略状态 s.More = &ZlemaState{ goLong: true, sectionLongs: 0, sectionShorts: 0, sectionLongConditions: 0, sectionShortConditions: 0, totalLongs: 0, totalShorts: 0, averageLongs: 0, averageShorts: 0, lastHigh: 0, lastLow: 0, inLong: false, inShort: false, } }, OnBar: func(s *strat.StratJob) { e := s.Env state, _ := s.More.(*ZlemaState) // 计算Zero-Lag EMA zlemaFast := ZeroLagEMA(e.Close, fastPeriod) zlemaSlow := ZeroLagEMA(e.Close, slowPeriod) // 获取当前值 fastVal := zlemaFast.Get(0) slowVal := zlemaSlow.Get(0) fastVal1 := zlemaFast.Get(1) slowVal1 := zlemaSlow.Get(1) closePrice := e.Close.Get(0) highPrice := e.High.Get(0) lowPrice := e.Low.Get(0) // 检查数据有效性 if math.IsNaN(fastVal) || math.IsNaN(slowVal) || math.IsNaN(closePrice) { return } // 生成基础交易信号 longSignal := fastVal > slowVal && fastVal1 <= slowVal1 // 快线上穿慢线 shortSignal := fastVal < slowVal && fastVal1 >= slowVal1 // 快线下穿慢线 // 应用交易方向翻转功能 if flipOpens { longSignal, shortSignal = shortSignal, longSignal } // 应用仅做多/仅做空选项 if longsOnly { shortSignal = false } if shortsOnly { longSignal = false } // 更新连续信号计数 if longSignal { state.sectionLongs++ state.sectionShorts = 0 } else if shortSignal { state.sectionShorts++ state.sectionLongs = 0 } // 应用金字塔式加仓条件 longCondition := longSignal && (state.sectionLongs <= pyramidingLess || state.sectionLongs >= pyramidingGreater || state.sectionLongs == pyramidingEqual) shortCondition := shortSignal && (state.sectionShorts <= pyramidingLess || state.sectionShorts >= pyramidingGreater || state.sectionShorts == pyramidingEqual) // 更新开仓价格和数量 if longCondition { state.totalLongs += closePrice state.sectionLongConditions++ state.averageLongs = state.totalLongs / float64(state.sectionLongConditions) state.inLong = true state.inShort = false } else if shortCondition { state.totalShorts += closePrice state.sectionShortConditions++ state.averageShorts = state.totalShorts / float64(state.sectionShortConditions) state.inShort = true state.inLong = false } // 更新最高价/最低价追踪 if state.inLong { if state.lastHigh == 0 || highPrice > state.lastHigh { state.lastHigh = highPrice } } else if state.inShort { if state.lastLow == 0 || lowPrice < state.lastLow { state.lastLow = lowPrice } } // 执行交易 if longCondition && len(s.LongOrders) == 0 { // 设置止损止盈 - 基于平均开仓价计算 stopLossVal := state.averageLongs * (1 - stopLossPercent/100) takeProfitVal := state.averageLongs * (1 + takeProfitRate/100) s.OpenOrder(&strat.EnterReq{ Tag: "long", Short: false, OrderType: core.OrderTypeMarket, StopLossVal: stopLossVal, TakeProfitVal: takeProfitVal, StopLossTag: "stop_loss", TakeProfitTag: "take_profit", }) } else if shortCondition && len(s.ShortOrders) == 0 { // 设置止损止盈 - 基于平均开仓价计算 stopLossVal := state.averageShorts * (1 + stopLossPercent/100) takeProfitVal := state.averageShorts * (1 - takeProfitRate/100) s.OpenOrder(&strat.EnterReq{ Tag: "short", Short: true, OrderType: core.OrderTypeMarket, StopLossVal: stopLossVal, TakeProfitVal: takeProfitVal, StopLossTag: "stop_loss", TakeProfitTag: "take_profit", }) } // 检查平仓条件 if state.inLong && shortSignal { s.CloseOrders(&strat.ExitReq{ Tag: "trend_reverse", Dirt: core.OdDirtLong, }) } else if state.inShort && longSignal { s.CloseOrders(&strat.ExitReq{ Tag: "trend_reverse", Dirt: core.OdDirtShort, }) } }, OnCheckExit: func(s *strat.StratJob, od *ormo.InOutOrder) *strat.ExitReq { e := s.Env state, _ := s.More.(*ZlemaState) closePrice := e.Close.Get(0) if od.Short { // 做空订单检查 if state.inShort { // 检查追踪止损条件 - 包含激活条件判断 if state.lastLow > 0 && state.lastLow <= state.averageShorts*(1-trailingActivationRate/100) && // 激活条件 closePrice >= state.lastLow*(1+trailingStopRate/100) { // 追踪止损条件 return &strat.ExitReq{Tag: "trailing_stop"} } } } else { // 做多订单检查 if state.inLong { // 检查追踪止损条件 - 包含激活条件判断 if state.lastHigh > 0 && state.lastHigh >= state.averageLongs*(1+trailingActivationRate/100) && // 激活条件 closePrice <= state.lastHigh*(1-trailingStopRate/100) { // 追踪止损条件 return &strat.ExitReq{Tag: "trailing_stop"} } } } return nil }, OnOrderChange: func(s *strat.StratJob, od *ormo.InOutOrder, chgType int) { state, _ := s.More.(*ZlemaState) // 订单状态变化时更新状态 if chgType == strat.OdChgExitFill { if od.Short { // 做空订单已平仓 state.inShort = false state.averageShorts = 0 state.totalShorts = 0 state.sectionShorts = 0 state.sectionShortConditions = 0 state.lastLow = 0 } else { // 做多订单已平仓 state.inLong = false state.averageLongs = 0 state.totalLongs = 0 state.sectionLongs = 0 state.sectionLongConditions = 0 state.lastHigh = 0 } } }, } }