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

117 lines
3.8 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 (
"fmt"
"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
在15m上,需把均线周期乘以4
尝试加止损、止盈、限价入场,都会导致整体收益减少
48个品种,21年到24年11月1日,累计收益1560%,最大回撤25%,夏普5.8
总收益93%来自多头
但加入空头可使夏普从4.8提高到5.8
多空的参数独立,比同一套参数,收益更稳定些
基于连续信号的商品期货交易策略
https://mp.weixin.qq.com/s/6MS94OhGYhtjBQ1Ufa5Rag
下面基于170固定品种:
使用1.5%*Close/atr作为开仓倍数,夏普从8.12提升到9.63
增加ErDelta过滤,夏普从9.63提升到11.03;最大回撤从21.8%降低到20.8%
有效信号权重测试没有明显改善:
OnStartUp: func(s *strat.StratJob) {
s.More = []float64{0.5, 0.5} // long, short
},
probs := s.More.([]float64)
if x1 == 1{
newShort := probs[1] * 0.5
s.More = []float64{1 - newShort, newShort}
sigDelta := math.Abs(1 - newShort*2)
if sigDelta > 0.2 {
openRate *= (1 - newShort) * 1.7
s.OpenOrder(&strat.EnterReq{Tag: "long", CostRate: openRate})
}
}
if x2 == -1{
newLong := probs[0] * 0.5
s.More = []float64{newLong, 1 - newLong}
sigDelta := math.Abs(1 - newLong*2)
if sigDelta > 0.2 {
openRate *= (1 - newLong) * 1.7
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, CostRate: openRate})
}
}
*/
func SMACrossV1(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,
OnBar: func(s *strat.StratJob) {
e := s.Env
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})
}
ma3 := com.GetMA(price, e.Volume, maSType, maSLen)
ma4 := com.GetMA(price, e.Volume, maSType, maSBig)
x2 := ma3.Cross(ma4)
if x2 == -1 && openRate > 0 {
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 !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)
}
},
}
}