package trend import ( "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/strat" ta "github.com/banbox/banta" "strconv" ) /* 版本1:备份:2025/02/23 原始灵感:https://www.fmz.com/strategy/442547 已改动了大部分 测试在4h上表现最佳;210101-241101,48个品种 收益1919%,回撤23%,夏普5.5 添加adx过滤,收益增加 测试使用ATRBase显著收益下降 */ type supFlwMore struct { enter *strat.EnterReq exitIds []int64 } func SuperFollow(p *config.RunPolicyConfig) *strat.TradeStrat { atrLen := 14 // 默认12 mult := p.Def("mult", 1.4, core.PNorm(0.7, 2.5)) sRate := p.Def("sRate", 1.1, core.PNorm(0.7, 1.8)) slAtr := p.Def("slAtr", 1.6, core.PNorm(1, 2.5)) tpRate := p.Def("tpRate", 3, core.PNorm(1.7, 5.5)) shortMult := -mult * sRate return &strat.TradeStrat{ WarmupNum: 200, EachMaxShort: 1, EachMaxLong: 1, //OnStartUp: func(s *strat.StratJob) { // s.More = &supFlwMore{} //}, //OnPairInfos: func(s *strat.StratJob) []*strat.PairSub { // return []*strat.PairSub{ // {"_cur_", "4h", 200}, // } //}, //OnBar: func(s *strat.StratJob) { // m, _ := s.More.(*supFlwMore) // if m.enter != nil { // s.OpenOrder(m.enter) // m.enter = nil // } else if len(m.exitIds) > 0 { // for _, id := range m.exitIds { // s.CloseOrders(&strat.ExitReq{Tag: "tooLong", OrderID: id}) // } // m.exitIds = nil // } //}, //OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) { // m, _ := s.More.(*supFlwMore) OnBar: func(s *strat.StratJob) { e := s.Env o, c := e.Open.Get(0), e.Close.Get(0) atr := ta.ATR(e.High, e.Low, e.Close, atrLen).Get(0) dist := (c - o) / atr adx := ta.ADX(e.High, e.Low, e.Close, 30).Get(0) openDirt := 0 overRate := 0.0 if len(s.ShortOrders) == 0 && dist < shortMult && adx < 20 { openDirt = -1 overRate = dist / shortMult } else if len(s.LongOrders) == 0 && dist > mult { openDirt = 1 overRate = dist / mult } if openDirt != 0 { costRate := overRate * 1.1 s.OpenOrder(&strat.EnterReq{ Tag: strconv.Itoa(openDirt), Short: openDirt < 0, TakeProfitVal: atr * slAtr * tpRate * overRate, StopLossVal: atr * slAtr * overRate, CostRate: costRate, }) } else { // 长期未关闭的,超过200个平仓 odList := s.GetOrders(core.OdDirtBoth) for _, od := range odList { holdNum := e.BarCount(od.EnterAt) if holdNum > 200 { s.CloseOrders(&strat.ExitReq{Tag: "tooLong", OrderID: od.ID}) } } } }, } }