Files
banstagy/trend/20250225/SuperFollow.go
2026-08-24 20:53:21 +08:00

112 lines
2.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"strconv"
)
/*
原始灵感:https://www.fmz.com/strategy/442547
已改动了大部分
测试在4h上表现最佳;210101-241101,48个品种
收益1919%,回撤23%,夏普5.5
添加adx过滤,收益增加
测试使用ATRBase显著收益下降
添加跟踪止损收益下降
2025/02/24添加大周期方向开单权重,15品种夏普从9.43增长到10.48;最大回撤14.7%变为12.4%
*/
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 = 0
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 100},
}
},
//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)
//bigDirt := s.More.(int)
openDirt := 0
overRate := 0.0
if dist < shortMult && adx < 20 {
if len(s.ShortOrders) == 0 {
openDirt = -1
}
overRate = dist / shortMult
} else if dist > mult {
if len(s.LongOrders) == 0 {
openDirt = 1
}
overRate = dist / mult
}
if openDirt != 0 {
costRate := overRate * 1.1
//if openDirt*bigDirt < 0 {
// costRate *= 0.5
//}
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})
}
}
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
maSml := ta.SMA(e.Close, 15)
maBig := ta.SMA(e.Close, 70)
s.More = maSml.Cross(maBig)
},
}
}