init
This commit is contained in:
113
trend/20250208/MACDEMAV2.go
Normal file
113
trend/20250208/MACDEMAV2.go
Normal 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,
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
107
trend/20250208/SMACrossV1.go
Normal file
107
trend/20250208/SMACrossV1.go
Normal 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})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
98
trend/20250208/SuperFollow.go
Normal file
98
trend/20250208/SuperFollow.go
Normal 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
11
trend/20250208/main.go
Normal 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
113
trend/20250225/MACDEMAV2.go
Normal 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
91
trend/20250225/MACDX.go
Normal 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
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
107
trend/20250225/SMACrossV1.go
Normal file
107
trend/20250225/SMACrossV1.go
Normal 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})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
111
trend/20250225/SuperFollow.go
Normal file
111
trend/20250225/SuperFollow.go
Normal 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
113
trend/MACDEMAV2.go
Normal 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
114
trend/MACDEMAV3.go
Normal 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
105
trend/MACDX.go
Normal 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
116
trend/SMACrossV1.go
Normal 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
144
trend/SMACrossV2.go
Normal 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
111
trend/SuperFollow.go
Normal 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
41
trend/cci100.go
Normal 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
53
trend/cciMa.go
Normal 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
39
trend/common.go
Normal 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
59
trend/dv2.go
Normal 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
86
trend/eelfranzTDI.go
Normal 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
53
trend/fastio.go
Normal 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
46
trend/kdjBig.go
Normal 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
45
trend/kdjX.go
Normal 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
68
trend/ma1/common.go
Normal 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
63
trend/ma1/v1.go
Normal 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
80
trend/ma1/v2.1.go
Normal 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
84
trend/ma1/v2.go
Normal 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
74
trend/ma1/v3.go
Normal 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
55
trend/maMulti.go
Normal 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
58
trend/ma_cross.go
Normal 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
47
trend/macd.go
Normal 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
59
trend/pcmp.go
Normal 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
54
trend/randCut.go
Normal 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
50
trend/rsi_macd.go
Normal 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
119
trend/smp1.go
Normal 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
98
trend/swing.go
Normal 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
84
trend/t01v1.go
Normal 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)
|
||||
//},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user