package llmjob import ( "math" "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" ) // Sta4009 存储每个品种的策略状态 type Sta4009 struct { atrTrailingStop float64 // ATR跟踪止损值 position int // 当前持仓方向(1=多头,-1=空头,0=无持仓) entryPrice float64 // 入场价格 buyTarget float64 // 多头目标价格 sellTarget float64 // 空头目标价格 } func J4009(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调参数 keyValue := pol.Def("keyValue", 1, core.PNorm(0.1, 5)) atrPeriod := pol.DefInt("atrPeriod", 14, core.PNorm(5, 30)) useHeikinAshi := pol.DefInt("useHeikinAshi", 0, core.PNorm(0, 1)) // 0=false, 1=true exitPercentage := pol.Def("exitPercentage", 0.002, core.PNorm(0.001, 0.01)) rsiPeriod := pol.DefInt("rsiPeriod", 14, core.PNorm(7, 30)) donchianLength := pol.DefInt("donchianLength", 20, core.PNorm(10, 50)) return &strat.TradeStrat{ WarmupNum: donchianLength + 20, // 确保有足够数据计算所有指标 HedgeOff: true, // 单向持仓模式 TimeFrames: "1d", OnStartUp: func(s *strat.StratJob) { // 初始化策略状态 s.More = &Sta4009{ atrTrailingStop: math.NaN(), position: 0, entryPrice: math.NaN(), buyTarget: math.NaN(), sellTarget: math.NaN(), } }, OnBar: func(s *strat.StratJob) { e := s.Env state, _ := s.More.(*Sta4009) // 计算基础指标 atr := ta.ATR(e.High, e.Low, e.Close, atrPeriod) lossDistance := keyValue * atr.Get(0) rsiValue := ta.RSI(e.Close, rsiPeriod).Get(0) // 计算价格源(普通收盘价或惠金-阿希收盘价) var priceSource *ta.Series if useHeikinAshi > 0 { haOpen, haHigh, haLow, haClose := ta.HeikinAshi(e) haCloseSeries := haOpen.Add(haHigh).Add(haLow).Add(haClose).Div(4) priceSource = haCloseSeries } else { priceSource = e.Close } currentPrice := priceSource.Get(0) prevPrice := priceSource.Get(1) // 计算ATR跟踪止损 if !math.IsNaN(lossDistance) && !math.IsNaN(currentPrice) && !math.IsNaN(prevPrice) { prevStop := state.atrTrailingStop if math.IsNaN(prevStop) { prevStop = 0 } if currentPrice > prevStop && prevPrice > prevStop { // 价格在止损线上方且前一价格也在止损线上方,止损线上移 state.atrTrailingStop = math.Max(prevStop, currentPrice-lossDistance) } else if currentPrice < prevStop && prevPrice < prevStop { // 价格在止损线下方且前一价格也在止损线下方,止损线下移 state.atrTrailingStop = math.Min(prevStop, currentPrice+lossDistance) } else if currentPrice > prevStop { // 价格上穿止损线,设置新的止损线 state.atrTrailingStop = currentPrice - lossDistance } else { // 价格下穿止损线,设置新的止损线 state.atrTrailingStop = currentPrice + lossDistance } } // 计算持仓方向 if !math.IsNaN(prevPrice) && !math.IsNaN(state.atrTrailingStop) { if prevPrice < state.atrTrailingStop && currentPrice > state.atrTrailingStop { state.position = 1 // 多头信号 } else if prevPrice > state.atrTrailingStop && currentPrice < state.atrTrailingStop { state.position = -1 // 空头信号 } // 否则保持原有方向 } // 计算唐奇安通道 donchianUpper := ta.Highest(e.High, donchianLength) donchianLower := ta.Lowest(e.Low, donchianLength) donchianBasis := donchianUpper.Add(donchianLower).Div(2).Get(0) // 计算交叉信号 above := currentPrice > state.atrTrailingStop && prevPrice <= state.atrTrailingStop below := currentPrice < state.atrTrailingStop && prevPrice >= state.atrTrailingStop // 生成交易信号 buySignal := currentPrice > state.atrTrailingStop && above && rsiValue > 50 && currentPrice > donchianBasis sellSignal := currentPrice < state.atrTrailingStop && below && rsiValue < 50 && currentPrice < donchianBasis // 执行交易 if buySignal && s.OrderNum == 0 { state.entryPrice = currentPrice state.buyTarget = state.entryPrice * (1 + exitPercentage) state.sellTarget = state.entryPrice * (1 - exitPercentage) s.OpenOrder(&strat.EnterReq{ Tag: "Buy", OrderType: core.OrderTypeMarket, }) } else if sellSignal && s.OrderNum == 0 { state.entryPrice = currentPrice state.buyTarget = state.entryPrice * (1 + exitPercentage) state.sellTarget = state.entryPrice * (1 - exitPercentage) s.OpenOrder(&strat.EnterReq{ Tag: "Sell", Short: true, OrderType: core.OrderTypeMarket, }) } // 退出条件检查 if len(s.LongOrders) > 0 { od := s.LongOrders[0] if od.Status >= ormo.InOutStatusFullEnter { if currentPrice >= state.buyTarget { // 达到止盈目标 s.CloseOrders(&strat.ExitReq{ Tag: "Take Profit", Dirt: core.OdDirtLong, Limit: state.buyTarget, }) } else if currentPrice <= state.sellTarget { // 触发止损 s.CloseOrders(&strat.ExitReq{ Tag: "Stop Loss", Dirt: core.OdDirtLong, Limit: state.sellTarget, }) } } } if len(s.ShortOrders) > 0 { od := s.ShortOrders[0] if od.Status >= ormo.InOutStatusFullEnter { if currentPrice <= state.sellTarget { // 达到止盈目标 s.CloseOrders(&strat.ExitReq{ Tag: "Take Profit", Dirt: core.OdDirtShort, Limit: state.sellTarget, }) } else if currentPrice >= state.buyTarget { // 触发止损 s.CloseOrders(&strat.ExitReq{ Tag: "Stop Loss", Dirt: core.OdDirtShort, Limit: state.buyTarget, }) } } } }, } }