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" ) type KijunData struct { initialCapital float64 netProfit float64 } func J3746(pol *config.RunPolicyConfig) *strat.TradeStrat { // 定义可调超参数 ksPeriod := pol.DefInt("ksPeriod", 30, core.PNorm(9, 50)) atrPeriod := pol.DefInt("atrPeriod", 14, core.PNorm(7, 30)) atrMultiplier := pol.Def("atrMultiplier", 1.5, core.PNorm(0.8, 4)) targetPoints := pol.Def("targetPoints", 100, core.PNorm(50, 200)) riskPercent := pol.Def("riskPercent", 4, core.PNorm(1, 10)) equityProtection := pol.Def("equityProtection", 30, core.PNorm(10, 50)) return &strat.TradeStrat{ WarmupNum: ksPeriod, // 预热K线数量,确保基均线计算有足够数据 HedgeOff: true, // 单向持仓模式 RunTimeFrames: []string{"3d"}, OnStartUp: func(s *strat.StratJob) { // 初始化每个品种的特定数据 s.More = &KijunData{ initialCapital: 50000.0, // 初始资金 netProfit: 0.0, // 初始净利润 } }, OnBar: func(s *strat.StratJob) { e := s.Env m, _ := s.More.(*KijunData) // 计算技术指标 atr := ta.ATR(e.High, e.Low, e.Close, atrPeriod) atrValue := atr.Get(0) // 计算基均线 (Kijun Sen) highest := ta.Highest(e.High, ksPeriod) lowest := ta.Lowest(e.Low, ksPeriod) kijunSen := highest.Add(lowest).Div(2) kijunSenValue := kijunSen.Get(0) // 检查数据有效性 if math.IsNaN(atrValue) || math.IsNaN(kijunSenValue) { return } // 生成交易信号 openPrice := e.Open.Get(0) closePrice := e.Close.Get(0) baseLong := openPrice < kijunSenValue && closePrice > kijunSenValue baseShort := openPrice > kijunSenValue && closePrice < kijunSenValue // 计算止损距离 stopLossVal := atrValue * atrMultiplier // 更新净利润 // 计算总浮动盈亏 totalFloating := 0.0 for _, od := range s.LongOrders { totalFloating += od.Profit } for _, od := range s.ShortOrders { totalFloating += od.Profit } m.netProfit = totalFloating // 权益保护检查 equityStopout := false if s.OrderNum > 0 { // 计算当前余额(初始资金 + 净利润) totalBalance := m.initialCapital + m.netProfit // 检查是否触发权益保护 if totalFloating < 0 && math.Abs(totalFloating/totalBalance) > equityProtection/100 { equityStopout = true } } // 权益保护触发时平仓所有头寸 if equityStopout { s.CloseOrders(&strat.ExitReq{ Tag: "equity_protection", Dirt: core.OdDirtBoth, Force: true, }) return } // 检查是否有持仓 hasLongPosition := len(s.LongOrders) > 0 hasShortPosition := len(s.ShortOrders) > 0 // 计算头寸大小 balance := m.initialCapital + m.netProfit riskAmount := balance * (riskPercent / 100) // 风险金额 size := riskAmount / stopLossVal // 合约数量 if size < 0.001 { // 最小合约数量检查 size = 0.001 } // 多头交易 if baseLong && !hasLongPosition && !hasShortPosition { s.OpenOrder(&strat.EnterReq{ Tag: "l_en", Amount: size, StopLossVal: stopLossVal, TakeProfitVal: targetPoints, StopLossTag: "stop_loss", TakeProfitTag: "take_profit", }) } // 空头交易 if baseShort && !hasShortPosition && !hasLongPosition { s.OpenOrder(&strat.EnterReq{ Tag: "s_en", Short: true, Amount: size, StopLossVal: stopLossVal, TakeProfitVal: targetPoints, StopLossTag: "stop_loss", TakeProfitTag: "take_profit", }) } }, OnCheckExit: func(s *strat.StratJob, od *ormo.InOutOrder) *strat.ExitReq { // 计算基均线 highest := ta.Highest(s.Env.High, ksPeriod) lowest := ta.Lowest(s.Env.Low, ksPeriod) kijunSen := highest.Add(lowest).Div(2) kijunSenValue := kijunSen.Get(0) closePrice := s.Env.Close.Get(0) // 多头平仓条件:收盘价低于基均线 if !od.Short && closePrice < kijunSenValue { return &strat.ExitReq{ Tag: "long_exit", } } // 空头平仓条件:收盘价高于基均线 if od.Short && closePrice > kijunSenValue { return &strat.ExitReq{ Tag: "short_exit", } } return nil }, } }