117 lines
3.8 KiB
Go
117 lines
3.8 KiB
Go
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)
|
||
}
|
||
},
|
||
}
|
||
}
|