This commit is contained in:
2026-08-24 20:53:21 +08:00
commit 6e78bba16a
287 changed files with 32443 additions and 0 deletions

113
trend/20250208/MACDEMAV2.go Normal file
View File

@@ -0,0 +1,113 @@
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"
)
/*
备份于2025/02/25
测试加入1d的大周期过滤,对做多或做空都未获得更好效果,反而略差
20210101-20250101
只做多:1776%,回撤28.8%,夏普3.93
多空双开:1913%,回撤22%,夏普4.53
做空部分单独运行波动很大,但和做多一起运行可减少做多的回撤
参考SMACross1加入海龟资金和ErDelta过滤后:
170品种下:夏普从7.97提升到8.91,显示最大回撤从18.71%下降到17.65%;收益从718%变为707%
*/
type entExitMore struct {
enter *strat.EnterReq
exit *strat.ExitReq
}
func MACDEMAV2(p *config.RunPolicyConfig) *strat.TradeStrat {
// 初始HMA 25 4
maType := com.DefMaType(p, "ma", com.MaHMA) // hma 包揽优化列表头部
maLen := p.DefInt("maLen", 25, core.PNormF(7, 100, 25, 0)) // 超过40表现不佳,20多表现最好
maRate := p.Def("maRate", 4.1, core.PNorm(1.5, 7))
emaLen := p.DefInt("emaLen", 100, core.PNormF(30, 240, 100, 0))
macdRt := p.Def("macdRt", 1, core.PNormF(0.7, 3, 1.2, 0))
maBigLen := int(math.Round(float64(maLen) * maRate))
mc1, mc2, mc3 := int(math.Round(12*macdRt)), int(math.Round(26*macdRt)), int(math.Round(9*macdRt))
p.KeepHyperOnly("ma", "maLen", "maRate")
return &strat.TradeStrat{
WarmupNum: 500,
EachMaxLong: 1,
EachMaxShort: 1,
//OnStartUp: func(s *strat.StratJob) {
// s.More = &entExitMore{}
//},
//OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
// return []*strat.PairSub{
// {"_cur_", "4h", 500},
// }
//},
//OnBar: func(s *strat.StratJob) {
// m, _ := s.More.(*entExitMore)
// if m.enter != nil {
// s.OpenOrder(m.enter)
// m.enter = nil
// }
// if m.exit != nil {
// s.CloseOrders(m.exit)
// m.exit = nil
// }
//},
//OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
// m, _ := s.More.(*entExitMore)
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 {
openRate = 0
}
ema := ta.EMA(e.Close, emaLen).Get(0)
macd, signal := ta.MACD(e.Close, mc1, mc2, mc3)
macdSub := macd.Get(0) - signal.Get(0)
if c > ema && macdSub > 0 && len(s.LongOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
CostRate: openRate,
})
} else if len(s.LongOrders) > 0 && (macdSub < 0 && c < ema) {
s.CloseOrders(&strat.ExitReq{
Tag: "closeL",
Dirt: core.OdDirtLong,
})
}
ma1 := com.GetMA(e.Close, e.Volume, maType, maLen)
ma2 := com.GetMA(e.Close, e.Volume, maType, maBigLen)
cross := ma1.Cross(ma2)
if cross == 1 && len(s.ShortOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "closeS",
Dirt: core.OdDirtShort,
})
} else if cross == -1 && len(s.ShortOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
CostRate: openRate,
})
}
},
}
}

View File

@@ -0,0 +1,107 @@
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
在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})
} else if x1 == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "xlong", Dirt: core.OdDirtLong})
}
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})
} else if x2 == 1 {
s.CloseOrders(&strat.ExitReq{Tag: "xshort", Dirt: core.OdDirtShort})
}
},
}
}

View File

@@ -0,0 +1,98 @@
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})
}
}
}
},
}
}

11
trend/20250208/main.go Normal file
View File

@@ -0,0 +1,11 @@
package trend
import "github.com/banbox/banbot/strat"
func init() {
strat.AddStratGroup("20250208", map[string]strat.FuncMakeStrat{
"m01": SuperFollow,
"m02": MACDEMAV2,
"m03": SMACrossV1,
})
}

113
trend/20250225/MACDEMAV2.go Normal file
View File

@@ -0,0 +1,113 @@
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"
)
/*
测试加入1d的大周期过滤,对做多或做空都未获得更好效果,反而略差
20210101-20250101
只做多:1776%,回撤28.8%,夏普3.93
多空双开:1913%,回撤22%,夏普4.53
做空部分单独运行波动很大,但和做多一起运行可减少做多的回撤
参考SMACross1加入海龟资金和ErDelta过滤后:
170品种下:夏普从7.97提升到8.91,显示最大回撤从18.71%下降到17.65%;收益从718%变为707%
2025/02/25 ERChg<1时保留ATR比率开单,整体*1.15
*/
type entExitMore struct {
enter *strat.EnterReq
exit *strat.ExitReq
}
func MACDEMAV2(p *config.RunPolicyConfig) *strat.TradeStrat {
// 初始HMA 25 4
maType := com.DefMaType(p, "ma", com.MaHMA) // hma 包揽优化列表头部
maLen := p.DefInt("maLen", 25, core.PNormF(7, 100, 25, 0)) // 超过40表现不佳,20多表现最好
maRate := p.Def("maRate", 4.1, core.PNorm(1.5, 7))
emaLen := p.DefInt("emaLen", 100, core.PNormF(30, 240, 100, 0))
macdRt := p.Def("macdRt", 1, core.PNormF(0.7, 3, 1.2, 0))
maBigLen := int(math.Round(float64(maLen) * maRate))
mc1, mc2, mc3 := int(math.Round(12*macdRt)), int(math.Round(26*macdRt)), int(math.Round(9*macdRt))
p.KeepHyperOnly("ma", "maLen", "maRate")
return &strat.TradeStrat{
WarmupNum: 500,
EachMaxLong: 1,
EachMaxShort: 1,
//OnStartUp: func(s *strat.StratJob) {
// s.More = &entExitMore{}
//},
//OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
// return []*strat.PairSub{
// {"_cur_", "4h", 500},
// }
//},
//OnBar: func(s *strat.StratJob) {
// m, _ := s.More.(*entExitMore)
// if m.enter != nil {
// s.OpenOrder(m.enter)
// m.enter = nil
// }
// if m.exit != nil {
// s.CloseOrders(m.exit)
// m.exit = nil
// }
//},
//OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
// m, _ := s.More.(*entExitMore)
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)
}
openRate *= 1.15
er := ta.ER(e.Close, 50)
erDelta := min(1.3, er.Get(0)/er.Get(12))
if erDelta > 1 {
openRate *= erDelta
}
ema := ta.EMA(e.Close, emaLen).Get(0)
macdCols := ta.MACD(e.Close, mc1, mc2, mc3).Cols
macdSub := macdCols[0].Get(0) - macdCols[1].Get(0)
if c > ema && macdSub > 0 && len(s.LongOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
CostRate: openRate,
})
} else if len(s.LongOrders) > 0 && (macdSub < 0 && c < ema) {
s.CloseOrders(&strat.ExitReq{
Tag: "closeL",
Dirt: core.OdDirtLong,
})
}
ma1 := com.GetMA(e.Close, e.Volume, maType, maLen)
ma2 := com.GetMA(e.Close, e.Volume, maType, maBigLen)
cross := ma1.Cross(ma2)
if cross == 1 && len(s.ShortOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "closeS",
Dirt: core.OdDirtShort,
})
} else if cross == -1 && len(s.ShortOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
CostRate: openRate,
})
}
},
}
}

91
trend/20250225/MACDX.go Normal file
View File

@@ -0,0 +1,91 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
视频号:山居听雨楼 2025/02/19
“有没有一眼就能看清楚,而且很好用的交易方法。。。。。这里分享一个只用macd的交易方法。”
【主要思想】
大周期(1d)MACD快线和慢线都处于0轴上方看多,都处于0轴下方看空;
小周期(8h)MACD:
看多时:快线上穿0轴或金叉,做多;死叉平仓。
看空时:快线下穿0轴或死叉,做空,死叉平仓。
测试小周期金叉死叉无需要求0轴上下,略好一点。
测试小周期当前参数4h盈利最佳。大周期1d最佳。
*/
func MACDX2(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 200,
RunTimeFrames: []string{"4h"},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 100},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = 0
},
OnBar: func(s *strat.StratJob) {
e := s.Env
dirt := s.More.(int)
macdCols := ta.MACD(e.Close, 26, 56, 20).Cols
macdX := macdCols[0].Cross(macdCols[1])
macdX2 := macdCols[0].Cross(0)
atr := ta.ATR(e.High, e.Low, e.Close, 30)
openRate := 0.015 * e.Close.Get(0) / atr.Get(0)
if openRate < 1 {
openRate = math.Sqrt(openRate)
}
openRate *= 1.3
er := ta.ER(e.Close, 50)
erDelta := min(1.3, er.Get(0)/er.Get(12))
if erDelta > 1 {
openRate *= erDelta
}
if len(s.LongOrders) > 0 {
if macdX == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "closeL", Dirt: core.OdDirtLong})
}
} else if dirt > 0 && openRate > 0 {
if macdX == 1 {
s.OpenOrder(&strat.EnterReq{Tag: "long", CostRate: openRate})
} else if macdX2 == 1 {
s.OpenOrder(&strat.EnterReq{Tag: "long2", CostRate: openRate})
}
}
if len(s.ShortOrders) > 0 {
if macdX == 1 {
s.CloseOrders(&strat.ExitReq{Tag: "closeS", Dirt: core.OdDirtShort})
}
} else if dirt < 0 && openRate > 0 {
if macdX == -1 {
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, CostRate: openRate})
} else if macdX2 == -1 {
s.OpenOrder(&strat.EnterReq{Tag: "short2", Short: true, CostRate: openRate})
}
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
macdCols := ta.MACD(e.Close, 12, 26, 9).Cols
macd := macdCols[0].Get(0)
signal := macdCols[1].Get(0)
if macd > 0 && signal > 0 {
s.More = 1
} else if macd < 0 && signal < 0 {
s.More = -1
} else {
s.More = 0
}
},
}
}

View File

@@ -0,0 +1,107 @@
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
在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})
} else if x1 == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "xlong", Dirt: core.OdDirtLong})
}
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})
} else if x2 == 1 {
s.CloseOrders(&strat.ExitReq{Tag: "xshort", Dirt: core.OdDirtShort})
}
},
}
}

View File

@@ -0,0 +1,111 @@
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)
},
}
}

113
trend/MACDEMAV2.go Normal file
View File

@@ -0,0 +1,113 @@
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"
)
/*
测试加入1d的大周期过滤,对做多或做空都未获得更好效果,反而略差
20210101-20250101
只做多:1776%,回撤28.8%,夏普3.93
多空双开:1913%,回撤22%,夏普4.53
做空部分单独运行波动很大,但和做多一起运行可减少做多的回撤
参考SMACross1加入海龟资金和ErDelta过滤后:
170品种下:夏普从7.97提升到8.91,显示最大回撤从18.71%下降到17.65%;收益从718%变为707%
2025/02/25 ERChg<1时保留ATR比率开单,整体*1.15
*/
type entExitMore struct {
enter *strat.EnterReq
exit *strat.ExitReq
}
func MACDEMAV2(p *config.RunPolicyConfig) *strat.TradeStrat {
// 初始HMA 25 4
maType := com.DefMaType(p, "ma", com.MaHMA) // hma 包揽优化列表头部
maLen := p.DefInt("maLen", 15, core.PNormF(7, 100, 25, 0)) // 超过40表现不佳,20多表现最好
maRate := p.Def("maRate", 4.1, core.PNorm(1.5, 7))
emaLen := p.DefInt("emaLen", 100, core.PNormF(30, 240, 100, 0))
macdRt := p.Def("macdRt", 1, core.PNormF(0.7, 3, 1.2, 0))
maBigLen := int(math.Round(float64(maLen) * maRate))
mc1, mc2, mc3 := int(math.Round(12*macdRt)), int(math.Round(26*macdRt)), int(math.Round(9*macdRt))
p.KeepHyperOnly("ma", "maLen", "maRate")
return &strat.TradeStrat{
WarmupNum: 500,
EachMaxLong: 1,
EachMaxShort: 1,
//OnStartUp: func(s *strat.StratJob) {
// s.More = &entExitMore{}
//},
//OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
// return []*strat.PairSub{
// {"_cur_", "4h", 500},
// }
//},
//OnBar: func(s *strat.StratJob) {
// m, _ := s.More.(*entExitMore)
// if m.enter != nil {
// s.OpenOrder(m.enter)
// m.enter = nil
// }
// if m.exit != nil {
// s.CloseOrders(m.exit)
// m.exit = nil
// }
//},
//OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
// m, _ := s.More.(*entExitMore)
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)
}
openRate *= 1.15
er := ta.ER(e.Close, 50)
erDelta := min(1.3, er.Get(0)/er.Get(12))
if erDelta > 1 {
openRate *= erDelta
}
ema := ta.EMA(e.Close, emaLen).Get(0)
macd, signal := ta.MACD(e.Close, mc1, mc2, mc3)
macdSub := macd.Get(0) - signal.Get(0)
if c > ema && macdSub > 0 && len(s.LongOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
CostRate: openRate,
})
} else if len(s.LongOrders) > 0 && (macdSub < 0 && c < ema) {
s.CloseOrders(&strat.ExitReq{
Tag: "closeL",
Dirt: core.OdDirtLong,
})
}
ma1 := com.GetMA(e.Close, e.Volume, maType, maLen)
ma2 := com.GetMA(e.Close, e.Volume, maType, maBigLen)
cross := ma1.Cross(ma2)
if cross == 1 && len(s.ShortOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "closeS",
Dirt: core.OdDirtShort,
})
} else if cross == -1 && len(s.ShortOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
CostRate: openRate,
})
}
},
}
}

114
trend/MACDEMAV3.go Normal file
View File

@@ -0,0 +1,114 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
基于MACDEMAV2,修改做空部分。做空的表现和SMACrossV1很相似,导致趋同性回撤
压力位开空,止损为atr
盈利空间超过atr,设置止损为c+atr
盈利超过3倍atr,设置止损0.6
10个bar时,小亏,直接平仓
*/
func MACDEMAV3(p *config.RunPolicyConfig) *strat.TradeStrat {
emaLen := p.DefInt("emaLen", 100, core.PNormF(30, 240, 100, 0))
macdRt := p.Def("macdRt", 1, core.PNormF(0.7, 3, 1.2, 0))
lenAtr := int(p.Def("atr", 29, core.PNorm(7, 40)))
baseAtrLen := int(float64(lenAtr) * 4.3)
mc1, mc2, mc3 := int(math.Round(12*macdRt)), int(math.Round(26*macdRt)), int(math.Round(9*macdRt))
p.KeepHyperOnly("emaLen", "macdRt")
stateKey := "state"
return &strat.TradeStrat{
WarmupNum: 500,
EachMaxLong: 1,
EachMaxShort: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
atrVal := atr.Get(0)
atrMa := (atrBase + atrVal) / 2
ema := ta.EMA(e.Close, emaLen).Get(0)
macd, signal := ta.MACD(e.Close, mc1, mc2, mc3)
macdSub := macd.Get(0) - signal.Get(0)
hh3 := ta.Highest(e.High, 3).Get(0)
_, kdjD, _ := ta.KDJBy(e.High, e.Low, e.Close, 13, 3, 3, "sma")
dSMA := ta.SMA(kdjD, 3)
isYaLi := dSMA.Cross(80.5) == 1 // crossover
if (c-ema)*macdSub > 0 {
if macdSub < 0 {
if len(s.LongOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "closeL",
Dirt: core.OdDirtLong,
})
}
} else {
//s.OpenOrder(&strat.EnterReq{
// Tag: "long",
//})
}
}
if len(s.ShortOrders) > 0 {
low := e.Low.Get(0)
for _, od := range s.ShortOrders {
if od.Status < ormo.InOutStatusFullEnter {
continue
}
// state: 0初始止损 1平衡止损c+atr 2盈利宽止损
state := od.GetInfoFloat64(stateKey)
bestRange := od.InitPrice - low
sl := od.GetStopLoss()
if bestRange > atrMa*2 || state == 2 {
// 处于较好盈利
newSl := c + bestRange*0.35
if newSl < sl.Price {
od.SetStopLoss(&ormo.ExitTrigger{Price: newSl, Tag: "good"})
od.SetInfo(stateKey, 2)
}
continue
}
holdNum := e.BarCount(od.EnterAt)
if holdNum > 9.5 && od.Profit < 0 {
// 超过10个bar,依然亏,直接平
s.CloseOrders(&strat.ExitReq{Tag: "exit10", OrderID: od.ID})
continue
}
if bestRange > atrMa*0.6 || state == 1 {
// 处于平衡状态
newSL := c + atrMa*0.3
if newSL < sl.Price {
od.SetStopLoss(&ormo.ExitTrigger{Price: newSL, Tag: "zero"})
od.SetInfo(stateKey, 1)
}
}
}
}
if isYaLi && len(s.ShortOrders) == 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
Limit: hh3 - atrMa*0.5,
StopLoss: hh3 + atrMa,
StopBars: 7,
})
}
},
}
}

105
trend/MACDX.go Normal file
View File

@@ -0,0 +1,105 @@
package trend
import (
"fmt"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
视频号:山居听雨楼 2025/02/19
“有没有一眼就能看清楚,而且很好用的交易方法。。。。。这里分享一个只用macd的交易方法。”
【主要思想】
大周期(1d)MACD快线和慢线都处于0轴上方看多,都处于0轴下方看空;
小周期(8h)MACD:
看多时:快线上穿0轴或金叉,做多;死叉平仓。
看空时:快线下穿0轴或死叉,做空,死叉平仓。
测试小周期金叉死叉无需要求0轴上下,略好一点。
测试小周期当前参数4h盈利最佳。大周期1d最佳。
*/
func MACDX2(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 300,
RunTimeFrames: []string{"4h"},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 150},
}
},
OnStartUp: func(s *strat.StratJob) {
s.More = 0
},
OnBar: func(s *strat.StratJob) {
e := s.Env
dirt := s.More.(int)
macd, signal := ta.MACD(e.Close, 26, 56, 20)
macdX := macd.Cross(signal)
macdX2 := macd.Cross(0)
atr := ta.ATR(e.High, e.Low, e.Close, 30)
openRate := 0.015 * e.Close.Get(0) / atr.Get(0)
if openRate < 1 {
openRate = math.Sqrt(openRate)
}
openRate *= 1.3
er := ta.ER(e.Close, 50)
erDelta := min(1.3, er.Get(0)/er.Get(12))
if erDelta > 1 {
openRate *= erDelta
}
if len(s.LongOrders) > 0 {
if macdX == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "closeL", Dirt: core.OdDirtLong, Log: true})
}
} else if dirt > 0 && openRate > 0 {
if macdX == 1 {
s.OpenOrder(&strat.EnterReq{Tag: "long", CostRate: openRate, Log: true})
} else if macdX2 == 1 {
s.OpenOrder(&strat.EnterReq{Tag: "long2", CostRate: openRate, Log: true})
}
}
if len(s.ShortOrders) > 0 {
if macdX == 1 {
s.CloseOrders(&strat.ExitReq{Tag: "closeS", Dirt: core.OdDirtShort, Log: true})
}
} else if dirt < 0 && openRate > 0 {
if macdX == -1 {
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, CostRate: openRate, Log: true})
} else if macdX2 == -1 {
s.OpenOrder(&strat.EnterReq{Tag: "short2", Short: true, CostRate: openRate, Log: true})
}
}
if !s.IsWarmUp {
line := fmt.Sprintf("%s %s %s %d %d %f %f %f %f %f macd:%f signal:%f atr:%f er:%f x1:%v x2:%v dirt:%v rate:%f",
s.Account, s.Symbol.Symbol, s.TimeFrame, 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),
macd.Get(0), signal.Get(0), atr.Get(0), er.Get(0), macdX, macdX2, dirt, openRate)
s.Strat.WriteOutput(line, true)
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
macdS, signalS := ta.MACD(e.Close, 12, 26, 9)
macd := macdS.Get(0)
signal := signalS.Get(0)
if macd > 0 && signal > 0 {
s.More = 1
} else if macd < 0 && signal < 0 {
s.More = -1
} else {
s.More = 0
}
if !s.IsWarmUp {
line := fmt.Sprintf("%s %s %f %f %f %f %f macd:%f signal:%f",
pair, tf, e.Open.Get(0), e.High.Get(0), e.Low.Get(0), e.Close.Get(0), e.Volume.Get(0),
macd, signal)
s.Strat.WriteOutput(line, true)
}
},
}
}

116
trend/SMACrossV1.go Normal file
View File

@@ -0,0 +1,116 @@
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)
}
},
}
}

144
trend/SMACrossV2.go Normal file
View File

@@ -0,0 +1,144 @@
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})
}
}
},
}
}

111
trend/SuperFollow.go Normal file
View File

@@ -0,0 +1,111 @@
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)
},
}
}

41
trend/cci100.go Normal file
View File

@@ -0,0 +1,41 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
视频号:量化牛牛:CCI指标修改一个参数,“单车”变“汽车”
收益很不稳定,至少8H盈利。
*/
func CCI100(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
cci := ta.CCI(e.Close, 50)
cciN100 := cci.Cross(-100)
cciP100 := cci.Cross(100)
if len(s.LongOrders) > 0 {
if cciP100 == 1 {
// 上穿100,减仓
s.CloseOrders(&strat.ExitReq{Tag: "half", ExitRate: 0.5})
} else if cciP100 == -1 {
// 下穿100,平仓
s.CloseOrders(&strat.ExitReq{Tag: "exit"})
} else if cciN100 == -1 {
// 止损离场
s.CloseOrders(&strat.ExitReq{Tag: "stop"})
}
}
if cciN100 == 1 {
// 上穿-100,入场
s.OpenOrder(&strat.EnterReq{Tag: "long"})
}
},
}
}

53
trend/cciMa.go Normal file
View File

@@ -0,0 +1,53 @@
package trend
import (
"fmt"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
来自视频号:落升聊股:周K线+CCI指标,操作简单,只看执行力
适用于4H,48品种,210101-241101,收益725%,回撤23%,夏普5.14
熊市期间有回撤
*/
func CciMa(p *config.RunPolicyConfig) *strat.TradeStrat {
cciLen := p.DefInt("cciLen", 89, core.PNorm(50, 200))
maLen := p.DefInt("maLen", 20, core.PNorm(10, 40))
tpRate := p.Def("tpRate", 3, core.PNorm(1, 5))
slRate := p.Def("slRate", 2, core.PNorm(1, 3))
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
cci := ta.CCI(e.Close, cciLen).Get(0)
ma := ta.SMA(e.Close, maLen).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
dirt := float64(0)
if c > ma && cci > 0 && len(s.LongOrders) == 0 {
dirt = 1
} else if c < ma && cci < 0 && len(s.ShortOrders) == 0 {
dirt = -1
}
if dirt != 0 {
sl := atr * slRate
tp := sl * tpRate
//limit, sl, tp := atr*0.7, atr*3, atr*9
//if dirt < 0 {
// limit, sl, tp = atr*0.2, atr*1.6, atr*4
//}
s.OpenOrder(&strat.EnterReq{
Tag: fmt.Sprintf("%v", dirt),
//Limit: c - limit*dirt,
Short: dirt < 0,
StopLossVal: sl,
TakeProfitVal: tp,
})
}
},
}
}

39
trend/common.go Normal file
View File

@@ -0,0 +1,39 @@
package trend
import (
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/trend/ma1"
)
func init() {
strat.AddStratGroup("trend", map[string]strat.FuncMakeStrat{
"t01v1": T01V1,
"macdx": MACDX,
"fastio": fastIO,
"maCross": MaCross,
"ma1": ma1.MainV2_1,
"ma1_v3": ma1.MainV3,
"SMACrossV1": SMACrossV1,
"SMACrossV2": SMACrossV2,
"MACDX2": MACDX2,
"MACDEMAV2": MACDEMAV2,
"MACDEMAV3": MACDEMAV3,
"SuperFollow": SuperFollow,
"CciMa": CciMa,
"dvrsi": DVRSI,
"cci100": CCI100,
"KdjBig": KdjBig,
"KdjX": KdjX,
"MaMulti": MaMulti,
"pcmp": pcmp,
"tdi": eelfranzTDI,
"randCut": randCut,
"smp1": smp1,
"swing": swing,
"m01": SuperFollow,
"m02": MACDEMAV2,
"m03": SMACrossV1,
"m04": MACDX2,
})
}

59
trend/dv2.go Normal file
View File

@@ -0,0 +1,59 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
基于DV2超卖且大均线上方时做多
基于RSI4百分位排名超卖,且大均线上方时做多
效果好于双均线仅做多。
DV2加入做空部分持续亏钱
RSI加入做空变化不大
*/
func DVRSI(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
RunTimeFrames: []string{"4h"},
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
dv := ta.DV2(e.High, e.Low, e.Close, 126, 2).Get(0)
sma := ta.SMA(e.Close, 50).Get(0)
ma10 := ta.SMA(e.Close, 10).Get(0)
rsi := ta.PercentRank(ta.RSI(e.Close, 4), 126).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
if len(s.LongOrders) > 0 {
if c < ma10 {
for _, o := range s.LongOrders {
holdNum := e.BarCount(o.EnterAt)
if holdNum > 5 {
s.CloseOrders(&strat.ExitReq{Tag: "exitL", OrderID: o.ID})
}
}
}
} else if len(s.ShortOrders) > 0 {
if c > ma10 {
for _, o := range s.ShortOrders {
holdNum := e.BarCount(o.EnterAt)
if holdNum > 5 {
s.CloseOrders(&strat.ExitReq{Tag: "exitS", OrderID: o.ID})
}
}
}
} else if dv <= 10 && c > sma {
s.OpenOrder(&strat.EnterReq{Tag: "long", StopLossVal: atr * 3})
} else if rsi < 10 && c > sma {
s.OpenOrder(&strat.EnterReq{Tag: "long", StopLossVal: atr * 3})
}
//else if rsi > 90 && c < sma {
// s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true, StopLossVal: atr})
//}
},
}
}

86
trend/eelfranzTDI.go Normal file
View File

@@ -0,0 +1,86 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
https://www.forexfactory.com/thread/291622-trading-made-simple
在1d周期,大多数品种上长期较好;稳定性一般
*/
func eelfranzTDI(p *config.RunPolicyConfig) *strat.TradeStrat {
var rsiLen = p.DefInt("rsiLen", 13, core.PNorm(8, 25))
var rsiMaLen = p.DefInt("rsiMa", 34, core.PNorm(20, 40))
var fastLen = p.DefInt("fast", 2, core.PNorm(2, 5))
var slowLen = p.DefInt("slow", 7, core.PNorm(4, 15))
return &strat.TradeStrat{
WarmupNum: 50,
OnBar: func(s *strat.StratJob) {
e := s.Env
rsi := ta.RSI(e.Close, rsiLen)
rsiMa := ta.SMA(rsi, rsiMaLen).Get(0)
stDev := StDev(rsi, rsiMaLen).Get(0)
upZone := rsiMa + 1.6185*stDev
dnZone := rsiMa - 1.6185*stDev
// market base line
marketBase := (upZone + dnZone) / 2
// rsi price line: green
fast := ta.SMA(rsi, fastLen).Get(0)
// trade signal line: red
slow := ta.SMA(rsi, slowLen).Get(0)
if len(s.LongOrders) > 0 {
if fast < slow {
s.CloseOrders(&strat.ExitReq{
Tag: "exitL",
Dirt: core.OdDirtLong,
})
}
} else if fast > max(slow, marketBase) {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
}
if len(s.ShortOrders) > 0 {
if fast > slow {
s.CloseOrders(&strat.ExitReq{
Tag: "exitS",
Dirt: core.OdDirtShort,
})
}
} else if slow > max(fast, marketBase) {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
})
}
},
}
}
func StDev(obj *ta.Series, period int) *ta.Series {
res := obj.To("stDev", period)
if res.Cached() {
return res
}
arr := ta.WrapFloatArr(res, period, obj.Get(0))
if len(arr) < period {
return res.Append(math.NaN())
} else {
var sum, ssum float64
for _, v := range arr {
sum += v
ssum += v * v
}
var lenFlt = float64(period)
variance := (ssum*lenFlt - sum*sum) / (lenFlt * (lenFlt - 1))
return res.Append(math.Sqrt(variance))
}
}

53
trend/fastio.go Normal file
View File

@@ -0,0 +1,53 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
func fastIO(p *config.RunPolicyConfig) *strat.TradeStrat {
lenAtr := 15
baseAtrLen := int(math.Round(float64(lenAtr) * 4.3))
return &strat.TradeStrat{
WarmupNum: 100,
EachMaxLong: 1,
EachMaxShort: 1,
DrawDownExit: true,
OnBar: func(s *strat.StratJob) {
e := s.Env
rsi4 := ta.RSI50(e.Close, 4).Get(0)
rsi14 := ta.RSI50(e.Close, 14).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
if rsi4 > 30 && rsi14 > 25 && rsi14 < 40 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
StopLossVal: atrBase,
TakeProfitVal: atrBase * 2.5,
})
} else if rsi4 < -30 && rsi14 < -25 && rsi14 > -40 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
StopLossVal: atrBase,
TakeProfitVal: atrBase * 2.5,
})
}
},
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
sl := od.GetStopLoss()
if sl == nil {
return 0
}
slRate := sl.Range / od.Enter.Average
if maxChg > slRate {
return 0.63
}
return 0
},
}
}

46
trend/kdjBig.go Normal file
View File

@@ -0,0 +1,46 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
视频号:量化牛牛:改一个参数,如何轻松拿捏行情呢?
KDJ的9,3,3改9,3,30(原文89),然后平滑D和50交叉时开平仓。
最小4H
加入EMA做空后更稳定。
*/
func KdjBig(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
_, kdjD, _ := ta.KDJ(e.High, e.Low, e.Close, 9, 3, 29)
jx50 := kdjD.Cross(50)
maaX := ta.EMA(e.Close, 9).Cross(ta.EMA(e.Close, 30))
if len(s.LongOrders) > 0 {
if jx50 == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "exitL", Dirt: core.OdDirtLong})
}
} else if len(s.ShortOrders) > 0 {
if maaX == 1 {
s.CloseOrders(&strat.ExitReq{Tag: "exitS", Dirt: core.OdDirtShort})
}
} else if jx50 == 1 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
} else if maaX == -1 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
})
}
},
}
}

45
trend/kdjX.go Normal file
View File

@@ -0,0 +1,45 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
视频号:漫谈期市:日内高胜率交易系统
kdj:18,3,3
20下金叉开多,80上死叉开空
效果差,无法盈利
*/
func KdjX(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
k, d, _ := ta.KDJ(e.High, e.Low, e.Close, 18, 3, 3)
kdx := k.Cross(d)
//maaX := ta.EMA(e.Close.Cross(9), ta.EMA(e.Close, 30))
if len(s.LongOrders) > 0 {
if kdx == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "exitL", Dirt: core.OdDirtLong})
}
} else if len(s.ShortOrders) > 0 {
if kdx == 1 {
s.CloseOrders(&strat.ExitReq{Tag: "exitS", Dirt: core.OdDirtShort})
}
} else if kdx == 1 && d.Get(0) < 20 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
} else if kdx == -1 && d.Get(0) > 80 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
})
}
},
}
}

68
trend/ma1/common.go Normal file
View File

@@ -0,0 +1,68 @@
package ma1
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
func Main(pol *config.RunPolicyConfig) *strat.TradeStrat {
return MainV2_1(pol)
}
var (
// 这里是默认参数,请尽量在MainVX()中修改,不要在这里修改
periodBig = 30
periodSml = 10
parentRate = 0.7
periodParBig = int(float64(periodBig) * parentRate)
periodParSml = int(float64(periodSml) * parentRate)
sampleNum = 500 // 斜率采样数量
sampleStep = 2 // 斜率计算间隔
atrLen = 14
openOffRate = float64(0) // 开单时,从均线偏移基准ATR的倍数
goodRate = float64(10) // 收益超过此倍数的ATR时,将止损更新为均线
badRate = float64(5) // 损失超过此倍数的ATR时,止损退出
)
type MoreType struct {
*com.Slop
hitGoods map[int64]bool // 触发goodRate的订单ID,允许每个bar更新止损
open int // 1开多 -1开空
}
func onStartUp(s *strat.StratJob) {
s.More = &MoreType{
Slop: com.NewSlop(sampleNum, 0.25),
hitGoods: make(map[int64]bool),
}
}
func onInfoMaCross(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
smaSml := ta.SMA(e.Close, periodParSml)
smaBig := ta.SMA(e.Close, periodParBig)
x := smaSml.Cross(smaBig)
more, _ := s.More.(*MoreType)
if x == 1 || x == -1 {
more.Dirt = x
}
}
func onInfoMaSlop(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
sma := ta.SMA(e.Close, periodParBig)
prevSma := sma.Get(sampleStep)
if e.BarNum%sampleStep > 0 || math.IsNaN(prevSma) {
return
}
more, _ := s.More.(*MoreType)
curSma := sma.Get(0)
slop := (curSma - prevSma) / curSma
//more.Slop.Update(e.BarNum, slop)
if slop > 0 {
more.Dirt = 1
} else {
more.Dirt = -1
}
}

63
trend/ma1/v1.go Normal file
View File

@@ -0,0 +1,63 @@
package ma1
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
func MainV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
periodSml = 300
periodBig = 1800
parentRate = 0.5
periodParBig = int(float64(periodBig) * parentRate)
periodParSml = int(float64(periodSml) * parentRate)
return &strat.TradeStrat{
Version: 1,
WarmupNum: periodBig,
MinTfScore: 0.75,
//DrawDownExit: true,
OnStartUp: onStartUp,
OnPairInfos: com.MakePairInfos(sampleNum*sampleStep + periodParBig),
OnInfoBar: onInfoMaCross,
OnBar: func(s *strat.StratJob) {
e := s.Env
sml := ta.SMA(e.Close, 10)
big := ta.SMA(e.Close, 50)
x := sml.Cross(big)
smaSml := ta.SMA(e.Close, periodSml)
smaBig := ta.SMA(e.Close, periodBig)
crx := smaSml.Cross(smaBig)
more, _ := s.More.(*MoreType)
if crx == 1 || crx == -1 {
closeTag := "x_short"
if crx < 0 {
closeTag = "x_long"
}
_ = s.CloseOrders(&strat.ExitReq{
Tag: closeTag,
Dirt: crx * -1,
})
if crx == more.Dirt {
// 交叉信号和大环境一致
more.open = crx
}
}
if more.open != 0 && more.open == -x {
more.open = 0
openTag := "long"
if x > 0 {
openTag = "short"
}
_ = s.OpenOrder(&strat.EnterReq{
Tag: openTag,
Short: x > 0,
})
}
},
}
}

80
trend/ma1/v2.1.go Normal file
View File

@@ -0,0 +1,80 @@
package ma1
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
)
/*
针对15m的参数
*/
func MainV2_1(pol *config.RunPolicyConfig) *strat.TradeStrat {
periodSml = 120
periodBig = 800
parentRate = 0.5
periodParBig = int(float64(periodBig) * parentRate)
periodParSml = int(float64(periodSml) * parentRate)
return &strat.TradeStrat{
Version: 1,
WarmupNum: sampleNum*sampleStep + periodBig,
MinTfScore: 0.75,
//DrawDownExit: true,
OnStartUp: onStartUp,
//OnPairInfos: onPairInfos,
//OnInfoBar: onInfoMaSlop,
OnBar: func(s *strat.StratJob) {
e := s.Env
sml := ta.SMA(e.Close, 30)
big := ta.SMA(e.Close, 70)
x := sml.Cross(big)
smaSml := ta.SMA(e.Close, periodSml)
smaBig := ta.SMA(e.Close, periodBig)
crx := smaSml.Cross(smaBig)
more, _ := s.More.(*MoreType)
if crx == 1 || crx == -1 {
closeTag := "x_short"
if crx < 0 {
closeTag = "x_long"
}
_ = s.CloseOrders(&strat.ExitReq{
Tag: closeTag,
Dirt: crx * -1,
})
more.open = crx
//if crx == more.Dirt {
// 交叉信号和大环境一致
//openTag := "long"
//if crx < 0 {
// openTag = "short"
//}
//_ = s.OpenOrder(&strategy.EnterReq{
// Tag: openTag,
// Short: crx < 0,
//})
//}
}
prevSma := smaBig.Get(sampleStep)
if e.BarNum%sampleStep == 0 && !math.IsNaN(prevSma) {
curSma := smaBig.Get(0)
more.Slop.Update(e.BarNum, (curSma-prevSma)/curSma)
}
x = -x
if more.open != 0 && more.open == x && more.open*more.Dirt >= 0 {
more.open = 0
openTag := "long"
if x < 0 {
openTag = "short"
}
_ = s.OpenOrder(&strat.EnterReq{
Tag: openTag,
Short: x < 0,
})
}
},
}
}

84
trend/ma1/v2.go Normal file
View File

@@ -0,0 +1,84 @@
package ma1
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
/*
针对15m的参数
*/
func MainV2(pol *config.RunPolicyConfig) *strat.TradeStrat {
periodSml = 120
periodBig = 750
parentRate = 0.5
periodParBig = int(float64(periodBig) * parentRate)
periodParSml = int(float64(periodSml) * parentRate)
return &strat.TradeStrat{
Version: 1,
WarmupNum: periodBig,
MinTfScore: 0.75,
//DrawDownExit: true,
OnStartUp: onStartUp,
OnPairInfos: com.MakePairInfos(sampleNum*sampleStep + periodParBig),
OnInfoBar: onInfoMaCross,
OnBar: func(s *strat.StratJob) {
e := s.Env
sml := ta.SMA(e.Close, 30)
big := ta.SMA(e.Close, 70)
x := sml.Cross(big)
smaSml := ta.SMA(e.Close, periodSml)
smaBig := ta.SMA(e.Close, periodBig)
crx := smaSml.Cross(smaBig)
more, _ := s.More.(*MoreType)
if crx == 1 || crx == -1 {
closeTag := "x_short"
if crx < 0 {
closeTag = "x_long"
}
_ = s.CloseOrders(&strat.ExitReq{
Tag: closeTag,
Dirt: crx * -1,
})
if crx == more.Dirt {
// 交叉信号和大环境一致
more.open = crx
//openTag := "long"
//if crx < 0 {
// openTag = "short"
//}
//_ = s.OpenOrder(&strategy.EnterReq{
// Tag: openTag,
// Short: crx < 0,
//})
}
}
x = -x
if more.open != 0 && more.open == x {
more.open = 0
openTag := "long"
if x < 0 {
openTag = "short"
}
_ = s.OpenOrder(&strat.EnterReq{
Tag: openTag,
Short: x < 0,
})
}
},
//GetDrawDownExitRate: func(s *strategy.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
// if maxChg > 3 {
// return 0.2
// } else if maxChg > 1 {
// return 0.25
// } else if maxChg > 0.5 {
// return 0.3
// }
// return 0
//},
}
}

74
trend/ma1/v3.go Normal file
View File

@@ -0,0 +1,74 @@
package ma1
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
)
/*
针对1h的参数
*/
func MainV3(pol *config.RunPolicyConfig) *strat.TradeStrat {
periodSml = 28
periodBig = 160
parentRate = 0.75
periodParBig = int(float64(periodBig) * parentRate)
periodParSml = int(float64(periodSml) * parentRate)
return &strat.TradeStrat{
Version: 1,
WarmupNum: periodBig,
MinTfScore: 0.75,
//DrawDownExit: true,
OnStartUp: onStartUp,
OnPairInfos: com.MakePairInfos(sampleNum*sampleStep + periodParBig),
OnInfoBar: onInfoMaCross,
OnBar: func(s *strat.StratJob) {
e := s.Env
sml := ta.SMA(e.Close, 7)
big := ta.SMA(e.Close, 24)
x := sml.Cross(big)
smaSml := ta.SMA(e.Close, periodSml)
smaBig := ta.SMA(e.Close, periodBig)
crx := smaSml.Cross(smaBig)
more, _ := s.More.(*MoreType)
if crx == 1 || crx == -1 {
closeTag := "x_short"
if crx < 0 {
closeTag = "x_long"
}
_ = s.CloseOrders(&strat.ExitReq{
Tag: closeTag,
Dirt: crx * -1,
})
if crx == more.Dirt {
// 交叉信号和大环境一致
more.open = crx
//openTag := "long"
//if crx < 0 {
// openTag = "short"
//}
//_ = s.OpenOrder(&strategy.EnterReq{
// Tag: openTag,
// Short: crx < 0,
//})
}
}
x = -x
if more.open != 0 && more.open == x {
more.open = 0
openTag := "long"
if x < 0 {
openTag = "short"
}
_ = s.OpenOrder(&strat.EnterReq{
Tag: openTag,
Short: x < 0,
})
}
},
}
}

55
trend/maMulti.go Normal file
View File

@@ -0,0 +1,55 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
视频号:六叔大师兄:散户用一个战法,当天100%不亏 2025/01/25
5日上穿10日买入;5日上穿20日加仓;
5日向下减仓,5日下穿10日平仓;
反之做空亦然;
去掉5日向下减仓,更好一点。
5,10,20适合8h;目前10,20,40适合4h
固定50品种在23年持平
滚动50品种在23年小亏
*/
func MaMulti(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
ma5 := ta.SMA(e.Close, 10)
ma10 := ta.SMA(e.Close, 20)
ma20 := ta.SMA(e.Close, 40)
ma5X10 := ma5.Cross(ma10)
ma5x20 := ma5.Cross(ma20)
if len(s.LongOrders) == 1 && ma5x20 == 1 {
s.OpenOrder(&strat.EnterReq{Tag: "l2", CostRate: 0.5})
}
if len(s.LongOrders) > 0 {
if ma5X10 == -1 {
s.CloseOrders(&strat.ExitReq{Tag: "exit", Dirt: core.OdDirtLong})
}
} else if ma5X10 == 1 {
s.OpenOrder(&strat.EnterReq{Tag: "l1", CostRate: 0.5})
}
if len(s.ShortOrders) == 1 && ma5x20 == -1 {
s.OpenOrder(&strat.EnterReq{Tag: "s2", Short: true, CostRate: 0.5})
}
if len(s.ShortOrders) > 0 {
if ma5X10 == 1 {
s.CloseOrders(&strat.ExitReq{Tag: "exitS", Dirt: core.OdDirtShort})
}
} else if ma5X10 == -1 {
s.OpenOrder(&strat.EnterReq{Tag: "s1", Short: true, CostRate: 0.5})
}
},
}
}

58
trend/ma_cross.go Normal file
View File

@@ -0,0 +1,58 @@
package trend
import (
"fmt"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
适用4h
*/
func MaCross(pol *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
Version: 1,
WarmupNum: 130,
MinTfScore: 0.75,
OnBar: func(s *strat.StratJob) {
e := s.Env
ma5 := ta.SMA(e.Close, 14)
ma30 := ta.SMA(e.Close, 40)
xnum := ma5.Cross(ma30)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
//ma5Val := ma5.Get(0)
maBigVal := ma30.Get(0)
if xnum == 1 && len(s.LongOrders) == 0 {
err := s.OpenOrder(&strat.EnterReq{
Tag: "enter",
Limit: maBigVal,
StopLoss: maBigVal - atr*2,
})
if err != nil {
fmt.Printf("open fail: %s", err)
}
} else if xnum == -1 && len(s.LongOrders) > 0 {
//longOd := s.LongOrders[0]
//if maBigVal-longOd.Enter.Price > atr*2 {
err := s.CloseOrders(&strat.ExitReq{
Tag: "exit",
//Limit: maBigVal,
})
if err != nil {
fmt.Printf("close fail: %s", err)
}
//}
}
//else if len(s.LongOrders) > 0 {
// c := e.Close.Get(0)
// for _, od := range s.LongOrders {
// if od.Status >= ormo.InOutStatusFullEnter && (c-od.Enter.Price) > atr*2 {
// od.SetInfo(orm.OdInfoStopLoss, maBigVal)
// }
// }
//}
},
}
}

47
trend/macd.go Normal file
View File

@@ -0,0 +1,47 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
func MACDX(pol *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 220,
EachMaxLong: 1,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 29).Get(0)
macd, macdSig := ta.MACD(e.Close, 12, 26, 9)
macdX := macd.Cross(macdSig)
maBig := ta.SMA(e.Close, 200).Get(0)
isBull := c > maBig
kdjK, kdjD, _ := ta.KDJ(e.High, e.Low, e.Close, 30, 5, 5)
kdjX := kdjK.Cross(kdjD)
if kdjX < 0 {
kdjX = -kdjX
}
rsi := ta.RSI(e.Close, 4).Get(0) - 50
if isBull && rsi < 30 && (macdX == 1 && kdjX <= 3 || macdX > 1 && kdjX == 1) && macd.Get(0) < 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
StopLossVal: atr * 0.8,
TakeProfitVal: atr * 3,
})
} else if !isBull && rsi > -30 && (macdX == -1 && kdjX <= 3 || macdX < -1 && kdjX == 1) && macd.Get(0) > 0 {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
StopLossVal: atr * 0.8,
TakeProfitVal: atr * 3,
})
}
},
}
}

59
trend/pcmp.go Normal file
View File

@@ -0,0 +1,59 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
)
func pcmp(pol *config.RunPolicyConfig) *strat.TradeStrat {
// 定义可优化的超参数
shortPeriod := int(pol.Def("short", 7, core.PNorm(5, 10)))
longPeriod := int(pol.Def("long", 14, core.PNorm(10, 20)))
return &strat.TradeStrat{
WarmupNum: longPeriod + 5, // 预热数据数量,确保有足够的历史数据
EachMaxLong: 1, // 最多持有1个多单
EachMaxShort: 1, // 最多持有1个空单
OnBar: func(s *strat.StratJob) {
e := s.Env
curPrice := e.Close.Get(0)
// 检查当前价格是否高于短周期和长周期前的价格
shortPriceHigher := curPrice > e.Close.Get(shortPeriod)
longPriceHigher := curPrice > e.Close.Get(longPeriod)
// 检查当前价格是否低于短周期和长周期前的价格
shortPriceLower := curPrice < e.Close.Get(shortPeriod)
longPriceLower := curPrice < e.Close.Get(longPeriod)
// 多头信号:当前价格比两个周期前都高
goLong := shortPriceHigher && longPriceHigher
// 空头信号:当前价格比两个周期前都低
goShort := shortPriceLower && longPriceLower
// 检查当前订单状态
hasLongOrder := len(s.LongOrders) > 0
hasShortOrder := len(s.ShortOrders) > 0
// 开多单逻辑:当前价格比两个周期前都高,且没有持仓
if goLong && !hasLongOrder && !hasShortOrder {
s.OpenOrder(&strat.EnterReq{Tag: "long"})
} else if goShort && !hasShortOrder && !hasLongOrder {
// 开空单逻辑:当前价格比两个周期前都低,且没有持仓
s.OpenOrder(&strat.EnterReq{Tag: "short", Short: true})
}
// 平多单逻辑:不满足做多条件,且有多单持仓
if !goLong && hasLongOrder {
s.CloseOrders(&strat.ExitReq{Tag: "close_long", Dirt: core.OdDirtLong})
}
// 平空单逻辑:不满足做空条件,且有空单持仓
if !goShort && hasShortOrder {
s.CloseOrders(&strat.ExitReq{Tag: "close_short", Dirt: core.OdDirtShort})
}
},
}
}

54
trend/randCut.go Normal file
View File

@@ -0,0 +1,54 @@
package trend
import (
"fmt"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
"math"
"math/rand"
)
func randCut(p *config.RunPolicyConfig) *strat.TradeStrat {
slRate := p.Def("slRate", 3, core.PNorm(1, 3))
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 30)
slRange := atr.Get(0) * slRate
odList := s.GetOrders(0)
if len(odList) > 0 {
for _, od := range odList {
sl := od.GetStopLoss()
if od.Short {
if sl.Price > c+slRange {
od.SetStopLoss(&ormo.ExitTrigger{
Price: c + slRange,
})
}
} else if sl.Price < c-slRange {
od.SetStopLoss(&ormo.ExitTrigger{
Price: c - slRange,
})
}
}
} else {
openRate := 0.015 * c / atr.Get(0)
if openRate < 1 {
openRate = math.Sqrt(openRate)
}
isShort := rand.Float64() > 0.5
s.OpenOrder(&strat.EnterReq{
Tag: fmt.Sprintf("%v", isShort),
Short: isShort,
CostRate: openRate,
StopLossVal: slRange,
})
}
},
}
}

50
trend/rsi_macd.go Normal file
View File

@@ -0,0 +1,50 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
func rsi_macd(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 100,
OnBar: func(s *strat.StratJob) {
e := s.Env
rsi := ta.RSI(e.Close, 2).Get(0)
sml := ta.SMA(e.Close, 5).Get(0)
big := ta.SMA(e.Close, 20).Get(0)
if len(s.LongOrders) > 0 {
for _, od := range s.LongOrders {
barNum := e.BarCount(od.EnterAt)
if barNum > 5 {
s.CloseOrders(&strat.ExitReq{
Tag: "exitL",
OrderID: od.ID,
})
}
}
} else if rsi <= 10 && sml > big {
s.OpenOrder(&strat.EnterReq{
Tag: "long",
})
}
if len(s.ShortOrders) > 0 {
for _, od := range s.ShortOrders {
barNum := e.BarCount(od.EnterAt)
if barNum > 5 {
s.CloseOrders(&strat.ExitReq{
Tag: "exitS",
OrderID: od.ID,
})
}
}
} else if rsi >= 90 && sml < big {
s.OpenOrder(&strat.EnterReq{
Tag: "short",
Short: true,
})
}
},
}
}

119
trend/smp1.go Normal file
View File

@@ -0,0 +1,119 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm/ormo"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
测试仅c<h1时有明显收益,其他如l1,c1,hlc1等,收益都不够好
初始策略:日线级别,c<h1,tr>atr时开多,持有一日平仓
*/
func smp1(p *config.RunPolicyConfig) *strat.TradeStrat {
allowOpen := false
return &strat.TradeStrat{
WarmupNum: 10,
RunTimeFrames: []string{"4h"},
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
return []*strat.PairSub{
{"_cur_", "1d", 30},
}
},
OnSymbols: func(items []string) []string {
hasBTC := false
for _, it := range items {
if it == "BTC/USDT:USDT" {
hasBTC = true
}
}
if !hasBTC {
return append([]string{"BTC/USDT:USDT"}, items...)
}
return items
},
OnStartUp: func(s *strat.StratJob) {
s.More = 0
},
OnBar: func(s *strat.StratJob) {
e := s.Env
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
doOpen := s.More.(int)
c := e.Close.Get(0)
o := e.Open.Get(0)
if len(s.LongOrders) > 0 {
slPrice := c - atr*3
for _, od := range s.LongOrders {
holdNum := e.BarCount(od.EnterAt)
if holdNum < 8 {
continue
}
sl := od.GetStopLoss()
if sl == nil && (c-od.InitPrice < atr*3 || o >= c-atr*0.6) {
s.CloseOrders(&strat.ExitReq{
Tag: "exit",
OrderID: od.ID,
})
} else if sl == nil || slPrice > sl.Price {
od.SetStopLoss(&ormo.ExitTrigger{
Price: slPrice,
})
}
}
} else if doOpen == 1 {
s.More = 0
s.OpenOrder(&strat.EnterReq{
Tag: "long1",
})
}
},
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
if pair == "BTC/USDT:USDT" {
ma30 := ta.SMA(e.Close, 45).Get(0)
c := e.Close.Get(0)
allowOpen = c > ma30
}
c := e.Close.Get(0)
h1 := e.High.Get(1)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
tr := ta.TR(e.High, e.Low, e.Close).Get(0)
ma := ta.SMA(e.Close, 14).Get(0)
if allowOpen && len(s.LongOrders) == 0 && c < h1-atr*0.4 && c > ma {
if tr > atr {
s.More = 1
}
}
},
}
}
func smp0(p *config.RunPolicyConfig) *strat.TradeStrat {
return &strat.TradeStrat{
WarmupNum: 30,
RunTimeFrames: []string{"1d"},
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
h1 := e.High.Get(1)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
tr := ta.TR(e.High, e.Low, e.Close).Get(0)
ma := ta.SMA(e.Close, 14).Get(0)
if len(s.LongOrders) > 0 {
s.CloseOrders(&strat.ExitReq{
Tag: "exit",
Dirt: core.OdDirtLong,
})
} else if c < h1-atr*0.4 && c > ma {
if tr > atr {
s.OpenOrder(&strat.EnterReq{
Tag: "long1",
TakeProfitVal: atr * 2,
})
}
}
},
}
}

98
trend/swing.go Normal file
View File

@@ -0,0 +1,98 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/strat"
ta "github.com/banbox/banta"
)
/*
初版:https://jesse.trade/strategies/trendswingtrader-v1
去掉e1<c或e1>c后,更不稳定
adx对部分条件应用会更好,直接全部过滤略差
加入海龟资金管理&ER开仓系数后表现略差
*/
func swing(p *config.RunPolicyConfig) *strat.TradeStrat {
slRate := p.Def("slRate", 4.5, core.PNorm(0.5, 5))
tpRate := p.Def("tpRate", 8, core.PNorm(3, 13))
return &strat.TradeStrat{
WarmupNum: 200,
OnBar: func(s *strat.StratJob) {
e := s.Env
c := e.Close.Get(0)
adx := ta.ADX(e.High, e.Low, e.Close, 14).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
e1 := ta.EMA(e.Close, 30).Get(0)
e2 := ta.EMA(e.Close, 50).Get(0)
e3 := ta.EMA(e.Close, 120).Get(0)
openRate := float64(1)
trend := float64(0)
tag := ""
if e2 < e1 && e1 < c {
if e3 < e2 {
tag = "long1"
} else {
tag = "long2"
if adx <= 25 {
// 表现较差
openRate *= 0.5
}
}
trend = 1
} else if e2 > e1 && e1 > c {
if e3 > e2 {
tag = "short1"
} else {
tag = "short2"
if adx <= 25 {
// 表现较差
openRate *= 0.5
}
}
trend = -1
}
if tag != "" {
if adx <= 25 {
tag += "_a"
}
}
if len(s.LongOrders) > 0 {
for _, od := range s.LongOrders {
sl := od.GetStopLoss()
curSL := c - atr*slRate
if curSL > sl.Price {
sl.Price = curSL
}
}
} else if trend == 1 && tag != "" && openRate > 0 {
s.OpenOrder(&strat.EnterReq{
Tag: tag,
CostRate: openRate,
StopLossVal: atr * slRate,
TakeProfitVal: atr * tpRate,
TakeProfitRate: 0.5,
})
}
if len(s.ShortOrders) > 0 {
for _, od := range s.ShortOrders {
sl := od.GetStopLoss()
curSL := c + atr*slRate
if curSL < sl.Price {
sl.Price = curSL
}
}
} else if trend == -1 && tag != "" && openRate > 0 {
s.OpenOrder(&strat.EnterReq{
Tag: tag,
Short: true,
CostRate: openRate,
StopLossVal: atr * slRate,
TakeProfitVal: atr * tpRate,
TakeProfitRate: 0.5,
})
}
},
}
}

84
trend/t01v1.go Normal file
View File

@@ -0,0 +1,84 @@
package trend
import (
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/strat"
"github.com/banbox/banstagy/com"
ta "github.com/banbox/banta"
"math"
)
func calcDirt(e *ta.BarEnv) float64 {
h, l := e.High.Get(0), e.Low.Get(0)
o, c := e.Open.Get(0), e.Close.Get(0)
h1, l1 := e.High.Get(1), e.Low.Get(1)
//h2, l2 := e.High.Get(2), e.Low.Get(2)
if h == l {
return 0
}
bodyRate := math.Abs(o-c) / (h - l)
if bodyRate < 0.5 {
return 0
}
subH1, subL1 := h-h1, l-l1
//subH2, subL2 := h1-h2, l1-l2
if subH1 > 0 && subL1 > 0 {
//if math.IsNaN(subH2) || subH2 < 0 || subL2 < 0 {
// return 0
//}
//if subL2+subH2 < subH1+subL1 {
// return 1
//}
return 1
}
//else if subH1 < 0 && subL1 < 0 {
// if math.IsNaN(subH2) || subH2 > 0 || subL2 > 0 {
// return 0
// }
// if subL2+subH2 > subH1+subL1 {
// return -1
// }
// return 0
//}
return 0
}
func T01V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
lenAtr := 15
baseAtrLen := int(math.Round(float64(lenAtr) * 4.3))
return &strat.TradeStrat{
Version: 1,
WarmupNum: 30,
MinTfScore: 0.75,
DrawDownExit: true,
OnStartUp: func(s *strat.StratJob) {
s.More = float64(0)
},
//OnPairInfos: common.MakePairInfos(10),
OnBar: func(s *strat.StratJob) {
e := s.Env
ma := ta.SMA(e.Close, 10).Get(0)
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
atrRate := math.Sqrt(atr.Get(0) / atrBase)
//bigDirt, _ := s.More.(float64)
c := e.Close.Get(0)
dirt := calcDirt(e)
maSub := c - ma
if s.OrderNum == 0 && dirt != 0 && maSub*dirt > 0 { // && bigDirt == dirt {
slVal := atrBase * atrRate * 0.2
slLong, slShort := c-slVal, c+slVal
com.FastOpen(s, dirt, slLong, slShort, 0)
}
},
//OnInfoBar: func(s *strategy.StratJob, e *ta.BarEnv, pair, tf string) {
// s.More = calcDirt(e)
//},
}
}