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

145 lines
4.5 KiB
Go
Raw 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"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
/*
自研均线趋势策略,多空都开。适合1h
尝试加止损、止盈、限价入场,都会导致整体收益减少
48个品种,21年到24年11月1日,累计收益1291%,最大回撤66%,夏普9.2
总收益90%来自多头
但加入空投可使夏普从5.64提高到9.2
TODO 添加相似矩阵过滤,趋同的品种不开单
结合MACDEMA,优化做多逻辑
相比SMACrossV1,略微不平滑;且收益降低;优先使用SMACrossV1
*/
type maSta struct {
openPrice float64
bigRsi float64
bigLong bool
}
func SMACrossV2(p *config.RunPolicyConfig) *strat.TradeStrat {
// 初始:两个SMA 做空:SMA 15 8
maLType := com.DefMaType(p, "maL", com.MaSMA)
maSType := com.DefMaType(p, "maS", com.MaSMA)
maLLen := p.DefInt("maLLen", 20, core.PNormF(7, 70, 20, 0))
maSLen := p.DefInt("maSLen", 15, core.PNormF(5, 50, 15, 0))
maLRate := p.Def("maLRate", 9, core.PNorm(2, 15))
maSRate := p.Def("maSRate", 8, core.PNorm(2, 14))
maLBig := int(math.Round(float64(maLLen) * maLRate))
maSBig := int(math.Round(float64(maSLen) * maSRate))
p.KeepHyperOnly("maSLen", "maSRate")
return &strat.TradeStrat{
WarmupNum: 200,
EachMaxShort: 1,
EachMaxLong: 1,
BatchInOut: true,
OnStartUp: func(s *strat.StratJob) {
s.More = &maSta{}
},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "4h", 30},
}
},
OnBar: func(s *strat.StratJob) {
e := s.Env
m, _ := s.More.(*maSta)
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 30)
openRate := 0.015 * c / atr.Get(0)
if openRate < 1 {
openRate = math.Sqrt(openRate)
}
er := ta.ER(e.Close, 50)
erDelta := min(1.3, er.Get(0)/er.Get(12))
if erDelta > 1 {
openRate *= erDelta
} else {
// 过滤掉ER下降的
openRate = 0
}
// 方案一:多空SMA:略微平滑,收益略小一点
// 方案二:多空VWMA:略微波动大点,收益略好一点
price := ta.AvgPrice(e)
ma1 := com.GetMA(price, e.Volume, maLType, maLLen)
ma2 := com.GetMA(price, e.Volume, maLType, maLBig)
x1 := ma1.Cross(ma2)
if x1 == 1 && openRate > 0 {
s.OpenOrder(&strat.EnterReq{Tag: "long", CostRate: openRate, Log: true})
} else if x1 == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "xlong", Dirt: core.OdDirtLong, Log: true})
}
if len(s.LongOrders) > 0 && m.openPrice < c && m.bigRsi > 80 && ma1.Get(0)-ma1.Get(2) > atr.Get(0)*0.5 {
// 多仓,盈利,小均线变向平仓
m.bigLong = true
}
//if m.bigLong && m.bigRsi > 70 {
// m.bigLong = false
// s.OpenOrder(&strat.EnterReq{Tag: "short2", Short: true, CostRate: openRate, Log: true})
//}
ma3 := com.GetMA(price, e.Volume, maSType, maSLen)
ma4 := com.GetMA(price, e.Volume, maSType, maSBig)
x2 := ma3.Cross(ma4)
if len(s.ShortOrders) == 0 && x2 == -1 && openRate > 0 {
m.bigLong = false
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, CostRate: openRate, Log: true})
} else if x2 == 1 {
s.CloseOrders(&strat.ExitReq{Tag: "xshort", Dirt: core.OdDirtShort, Log: true})
}
if len(s.ShortOrders) > 0 && m.bigRsi < 30 && s.ShortOrders[0].ProfitRate > 0 {
s.CloseOrders(&strat.ExitReq{Tag: "xshort2", Dirt: core.OdDirtShort, Log: true})
}
//if !s.IsWarmUp {
// line := fmt.Sprintf("%s %s %d %d %f %f %f %f %f atr:%f er:%f m1:%f m2:%f m3:%f m4:%f x1:%v x2:%v rate:%f",
// s.Account, s.Symbol.Symbol, len(s.LongOrders), len(s.ShortOrders),
// e.Open.Get(0), e.High.Get(0), e.Low.Get(0), e.Close.Get(0), e.Volume.Get(0),
// atr.Get(0), er.Get(0), ma1.Get(0), ma2.Get(0), ma3.Get(0), ma4.Get(0),
// x1, x2, openRate)
// s.Strat.WriteOutput(line, true)
//}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
m, _ := s.More.(*maSta)
m.bigRsi = ta.RSI(e.Close, 9).Get(0)
},
OnBatchJobs: func(jobs []*strat.StratJob) {
longNum := float64(0)
bigDown := float64(0)
for _, s := range jobs {
if len(s.LongOrders) == 0 {
continue
}
longNum += 1
m, _ := s.More.(*maSta)
if m.bigLong {
bigDown += 1
}
}
if bigDown*1.5 > longNum && longNum*2 > float64(len(jobs)) {
for _, s := range jobs {
if len(s.LongOrders) == 0 {
continue
}
s.CloseOrders(&strat.ExitReq{Tag: "xlong2", Dirt: core.OdDirtLong, Log: true})
}
}
},
}
}