init
This commit is contained in:
117
old/CorrMeanRev.go
Normal file
117
old/CorrMeanRev.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/core"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banbot/utils"
|
||||
"github.com/banbox/banexg/log"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"gonum.org/v1/gonum/floats"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type CoMeSta struct {
|
||||
corr float64
|
||||
atrBs float64
|
||||
}
|
||||
|
||||
func CorrMeanRev(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
corrHisLen := 70
|
||||
avgCorr := float64(0)
|
||||
rsiUpp := 70.0
|
||||
rsiLow := 30.0
|
||||
overBuy, overSell := 0.0, 0.0
|
||||
avgMaOff := 0.0
|
||||
lenAtr := int(pol.Def("atr", 20, core.PNorm(7, 40)))
|
||||
baseAtrLen := int(float64(lenAtr) * 4.3)
|
||||
return &strat.TradeStrat{
|
||||
WarmupNum: 100,
|
||||
BatchInOut: true,
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
s.More = &CoMeSta{}
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
m, _ := s.More.(*CoMeSta)
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
|
||||
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
|
||||
m.atrBs = atrBase
|
||||
//ma := ta.SMA(e.Close, 10).Get(0)
|
||||
//maOff := (e.Close.Get(0) - ma) / m.atrBs
|
||||
rsi := ta.RSI(e.Close, 14).Get(0)
|
||||
if m.corr >= 0.9 && avgCorr > 0.7 && s.OrderNum == 0 {
|
||||
// 全品种趋同70%以上,当前品种趋同90%
|
||||
dirt := 0
|
||||
if rsi > 70 {
|
||||
dirt = 1
|
||||
} else if rsi < 30 {
|
||||
dirt = -1
|
||||
}
|
||||
//if avgMaOff > 0.2 && maOff > 0 {
|
||||
// dirt = 1
|
||||
//} else if avgMaOff < -0.2 && maOff < 0 {
|
||||
// dirt = -1
|
||||
//}
|
||||
if dirt != 0 {
|
||||
s.OpenOrder(&strat.EnterReq{
|
||||
Tag: strconv.Itoa(dirt),
|
||||
Short: dirt < 0,
|
||||
StopLossVal: atr.Get(0) * 2,
|
||||
TakeProfitVal: atr.Get(0) * 5,
|
||||
})
|
||||
}
|
||||
} else if overBuy > 0.7 && rsi > 85 {
|
||||
s.CloseOrders(&strat.ExitReq{Tag: "closeL", Dirt: core.OdDirtLong})
|
||||
} else if overSell > 0.7 && rsi < 15 {
|
||||
s.CloseOrders(&strat.ExitReq{Tag: "closeS", Dirt: core.OdDirtShort})
|
||||
}
|
||||
},
|
||||
OnBatchJobs: func(jobs []*strat.StratJob) {
|
||||
envs := make([]*ta.BarEnv, 0, len(jobs))
|
||||
dataLen, barNum := 0, 0
|
||||
for _, j := range jobs {
|
||||
dataLen = j.Env.Close.Len()
|
||||
barNum = j.Env.BarNum
|
||||
break
|
||||
}
|
||||
if dataLen < corrHisLen+3 {
|
||||
return
|
||||
}
|
||||
batchNumFlt := float64(len(jobs))
|
||||
overBuy, overSell = 0.0, 0.0
|
||||
avgMaOff = 0
|
||||
for _, j := range jobs {
|
||||
e := j.Env
|
||||
m, _ := j.More.(*CoMeSta)
|
||||
envs = append(envs, e)
|
||||
rsi := ta.RSI(e.Close, 14).Get(0)
|
||||
if rsi > rsiUpp {
|
||||
overBuy += 1
|
||||
} else if rsi < rsiLow {
|
||||
overSell += 1
|
||||
}
|
||||
ma := ta.SMA(e.Close, 10).Get(0)
|
||||
avgMaOff += (e.Close.Get(0) - ma) / m.atrBs
|
||||
}
|
||||
overBuy /= batchNumFlt
|
||||
overSell /= batchNumFlt
|
||||
avgMaOff /= batchNumFlt
|
||||
if barNum%10 > 0 {
|
||||
// 每10个bar计算一次相关性
|
||||
return
|
||||
}
|
||||
_, corrs, err := utils.CalcEnvsCorr(envs, corrHisLen)
|
||||
if err != nil {
|
||||
log.Warn("CalcEnvsCorr fail", zap.String("e", err.Error()))
|
||||
return
|
||||
}
|
||||
avgCorr = floats.Sum(corrs) / float64(len(corrs))
|
||||
for i, j := range jobs {
|
||||
m, _ := j.More.(*CoMeSta)
|
||||
m.corr = corrs[i]
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
44
old/boll_back_com.go
Normal file
44
old/boll_back_com.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
ta "github.com/banbox/banta"
|
||||
"math"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type MoreType struct {
|
||||
lastCalc int
|
||||
BollSlops []float64
|
||||
MaSlops []float64
|
||||
BollUpSlop float64
|
||||
BollDownSlop float64
|
||||
MaUpSlop float64
|
||||
MaDownSlop float64
|
||||
}
|
||||
|
||||
func (m *MoreType) UpdateSlops(e *ta.BarEnv, bollSlop, maSlop float64, sampleNum int) {
|
||||
m.BollSlops = append(m.BollSlops, math.Abs(bollSlop))
|
||||
m.MaSlops = append(m.MaSlops, math.Abs(maSlop))
|
||||
if len(m.BollSlops) < sampleNum || e.BarNum-m.lastCalc < sampleNum/2 {
|
||||
return
|
||||
}
|
||||
if len(m.BollSlops) > sampleNum {
|
||||
m.BollSlops = m.BollSlops[len(m.BollSlops)-sampleNum:]
|
||||
m.MaSlops = m.MaSlops[len(m.MaSlops)-sampleNum:]
|
||||
}
|
||||
thres := CutScore(m.BollSlops, 0.25)
|
||||
m.BollUpSlop = thres
|
||||
m.BollDownSlop = -thres
|
||||
thres = CutScore(m.MaSlops, 0.25)
|
||||
m.MaUpSlop = thres
|
||||
m.MaDownSlop = -thres
|
||||
m.lastCalc = e.BarNum
|
||||
}
|
||||
|
||||
func CutScore(vals []float64, rate float64) float64 {
|
||||
arr := make([]float64, len(vals))
|
||||
copy(arr, vals)
|
||||
slices.Sort(arr)
|
||||
idx := int(float64(len(vals)) * rate)
|
||||
return arr[idx]
|
||||
}
|
||||
78
old/boll_back_v1.go
Normal file
78
old/boll_back_v1.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
v1SlopLen = 2
|
||||
v1BollLen = 26
|
||||
v1MaLen = 50
|
||||
v1AtrLen = 14
|
||||
v1SampleNum = 300
|
||||
)
|
||||
|
||||
func BollBackV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: 1000,
|
||||
MinTfScore: 0.75,
|
||||
DrawDownExit: true,
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
s.More = &MoreType{}
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
|
||||
_, bollMid, _ := ta.BBANDS(e.Close, v1BollLen, 2, 2)
|
||||
ma := ta.SMA(e.Close, v1MaLen)
|
||||
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, v1AtrLen)
|
||||
//baseAtrLen := int(math.Round(float64(v1AtrLen) * 4.3))
|
||||
//atrBase := ta.Lowest(ta.Highest(atr, v1AtrLen), baseAtrLen).Get(0)
|
||||
|
||||
bollSub := bollMid.Get(0) - bollMid.Get(v1SlopLen)
|
||||
maSub := ma.Get(0) - ma.Get(v1SlopLen)
|
||||
if math.IsNaN(maSub) || math.IsNaN(bollSub) {
|
||||
return
|
||||
}
|
||||
|
||||
bollSlop := bollSub / bollMid.Get(0)
|
||||
maSlop := maSub / ma.Get(0)
|
||||
more, _ := s.More.(*MoreType)
|
||||
|
||||
if e.BarNum%v1SlopLen == 0 {
|
||||
more.UpdateSlops(e, bollSlop, maSlop, v1SampleNum)
|
||||
}
|
||||
|
||||
if s.OrderNum > 0 || bollSlop*maSlop < 0 || more.BollUpSlop == 0 {
|
||||
// 已开单,或者布林中轨和均线方向不一致,或者上下限尚未确定,跳过
|
||||
return
|
||||
}
|
||||
if bollSlop >= more.BollDownSlop && bollSlop <= more.BollUpSlop || maSlop >= more.MaDownSlop && maSlop <= more.MaUpSlop {
|
||||
// 布林中轨或者均线未突破斜率阈值
|
||||
return
|
||||
}
|
||||
|
||||
dirt := 1
|
||||
if bollSlop < 0 {
|
||||
dirt *= -1
|
||||
}
|
||||
atrVal := atr.Get(0) //*0.5 + atrBase*0.5
|
||||
stopLoss := e.Close.Get(0) - atrVal*float64(dirt)
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "enter",
|
||||
StopLoss: stopLoss,
|
||||
Short: dirt < 0,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open fail", zap.Error(err))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
75
old/boll_back_v2.go
Normal file
75
old/boll_back_v2.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
v2SlopLen = 5
|
||||
v2BollLen = 26
|
||||
v2AtrLen = 14
|
||||
v2SampleNum = 300
|
||||
v2RsiLen = 15
|
||||
)
|
||||
|
||||
func BollBackV2(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: 300,
|
||||
MinTfScore: 0.75,
|
||||
DrawDownExit: true,
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
s.More = &MoreType{}
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
|
||||
rsi := ta.RSI(e.Close, v2RsiLen).Get(0) - 50
|
||||
|
||||
_, bollMid, _ := ta.BBANDS(e.Close, v2BollLen, 2, 2)
|
||||
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, v2AtrLen)
|
||||
//baseAtrLen := int(math.Round(float64(v2AtrLen) * 4.3))
|
||||
//atrBase := ta.Lowest(ta.Highest(atr, v2AtrLen), baseAtrLen).Get(0)
|
||||
|
||||
bollSlop := bollMid.Get(0)/bollMid.Get(v2SlopLen) - 1
|
||||
if math.IsNaN(bollSlop) {
|
||||
return
|
||||
}
|
||||
more, _ := s.More.(*MoreType)
|
||||
|
||||
if e.BarNum%v2SlopLen == 0 {
|
||||
more.UpdateSlops(e, bollSlop, 0, v2SampleNum)
|
||||
}
|
||||
|
||||
if s.OrderNum > 0 || bollSlop*rsi > 0 || more.BollUpSlop == 0 || math.Abs(rsi) <= 20 {
|
||||
// 已开单,或者布林中轨和均线方向不一致,或者上下限尚未确定,跳过
|
||||
return
|
||||
}
|
||||
if bollSlop >= more.BollDownSlop && bollSlop <= more.BollUpSlop {
|
||||
// 布林中轨或者均线未突破斜率阈值
|
||||
return
|
||||
}
|
||||
|
||||
dirt := 1
|
||||
if rsi < 0 {
|
||||
dirt = -1
|
||||
}
|
||||
atrVal := atr.Get(0) * 3 //*0.5 + atrBase*0.5
|
||||
stopLoss := e.Close.Get(0) - atrVal*float64(dirt)
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "enter",
|
||||
StopLoss: stopLoss,
|
||||
Short: dirt < 0,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open fail", zap.Error(err))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
75
old/breakout_v1.go
Normal file
75
old/breakout_v1.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/core"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
/*
|
||||
适合4h,收益很不稳定
|
||||
*/
|
||||
|
||||
func BreakOutV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
periodBig := 200
|
||||
periodSml := 30
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: periodBig,
|
||||
MinTfScore: 0.75,
|
||||
//DrawDownExit: true,
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
hhBig := ta.Highest(e.Close, periodBig).Get(1)
|
||||
//llSml := ta.Lowest(e.Close, periodSml).Get(1)
|
||||
llBig := ta.Lowest(e.Close, periodBig).Get(1)
|
||||
//hhSml := ta.Highest(e.Close, periodSml).Get(1)
|
||||
maSml := ta.SMA(e.Close, periodSml)
|
||||
maBig := ta.SMA(e.Close, periodBig)
|
||||
maX := maSml.Cross(maBig)
|
||||
c := e.Close.Get(0)
|
||||
openTag := ""
|
||||
closeTag := ""
|
||||
if len(s.LongOrders) == 0 && c >= hhBig {
|
||||
openTag = "long"
|
||||
} else if len(s.ShortOrders) == 0 && c <= llBig {
|
||||
openTag = "short"
|
||||
}
|
||||
if maX == 1 {
|
||||
closeTag = "xshort"
|
||||
} else if maX == -1 {
|
||||
closeTag = "xlong"
|
||||
}
|
||||
//if len(s.LongOrders) > 0 && c <= llSml {
|
||||
// closeTag = "xlong"
|
||||
//} else if len(s.ShortOrders) > 0 && c >= hhSml {
|
||||
// closeTag = "xshort"
|
||||
//}
|
||||
if openTag != "" {
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: openTag,
|
||||
Short: openTag == "short",
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open fail", zap.Error(err))
|
||||
}
|
||||
}
|
||||
if closeTag != "" {
|
||||
dirt := core.OdDirtLong
|
||||
if closeTag == "xshort" {
|
||||
dirt = core.OdDirtShort
|
||||
}
|
||||
err := s.CloseOrders(&strat.ExitReq{
|
||||
Tag: closeTag,
|
||||
Dirt: dirt,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("close fail", zap.Error(err))
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
26
old/common.go
Normal file
26
old/common.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banstagy/old/rev"
|
||||
"github.com/banbox/banstagy/old/rsi_ptn_rev"
|
||||
"github.com/banbox/banstagy/old/s01"
|
||||
"github.com/banbox/banstagy/old/t01"
|
||||
)
|
||||
|
||||
func init() {
|
||||
strat.AddStratGroup("old", map[string]strat.FuncMakeStrat{
|
||||
"boll_back0": BollBackV1,
|
||||
"boll_back": BollBackV2,
|
||||
"breakout": BreakOutV1,
|
||||
"ped": Ped,
|
||||
"corrMean": CorrMeanRev,
|
||||
"macd": MACD,
|
||||
"rev": rev.S01V1,
|
||||
"rsi_ptn_rev": rsi_ptn_rev.MainV1,
|
||||
"s01v1": s01.MainV1,
|
||||
"s01v2": s01.MainV2, // 建议版本
|
||||
"xem4o": xem40,
|
||||
"t01": t01.Main4HV1,
|
||||
})
|
||||
}
|
||||
165
old/eat.go
Normal file
165
old/eat.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
var (
|
||||
lenAtr = 9
|
||||
rangeRate = 0.6 // 预计bar利润区间比率:60%
|
||||
ShakeTop = 0.2 // 只对分数前20%的标的进行震荡交易
|
||||
minProfitPct = 0.01 // 最小目标盈利百分比
|
||||
)
|
||||
|
||||
type TMore struct {
|
||||
symbol string
|
||||
shakeScore float64 // 震荡分数:(1-平均实体比率)*平均bar波动比率
|
||||
btmPrice float64 // 平均向下突破比率
|
||||
topPrice float64 // 平均向上突破比率
|
||||
shakeOK bool // 是否允许震荡中开单
|
||||
shakeHit float64 // 震荡首先触发位置:-1触发顶部,1触发底部
|
||||
}
|
||||
|
||||
func Eat(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
baseAtrLen := int(math.Round(float64(lenAtr) * 5))
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: max(30, baseAtrLen),
|
||||
MinTfScore: 0.75,
|
||||
BatchInfo: true,
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
s.More = &TMore{
|
||||
symbol: s.Symbol.Symbol,
|
||||
}
|
||||
},
|
||||
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
|
||||
return []*strat.PairSub{
|
||||
{Pair: "_cur_", TimeFrame: "8h", WarmupNum: 30},
|
||||
}
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
h, l, c := e.High.Get(0), e.Low.Get(0), e.Close.Get(0)
|
||||
m, _ := s.More.(*TMore)
|
||||
if m.shakeOK {
|
||||
// 允许震荡开单
|
||||
if m.shakeHit == 0 {
|
||||
if h >= m.topPrice {
|
||||
m.shakeHit = -1
|
||||
} else if l <= m.btmPrice {
|
||||
m.shakeHit = 1
|
||||
}
|
||||
}
|
||||
if s.OrderNum == 0 && m.shakeHit != 0 {
|
||||
slRange := (m.topPrice - m.btmPrice)
|
||||
tag := "long"
|
||||
trigPrice := m.btmPrice
|
||||
takeProfit := m.topPrice
|
||||
if m.shakeHit < 0 {
|
||||
tag = "short"
|
||||
trigPrice = m.topPrice
|
||||
takeProfit = m.btmPrice
|
||||
}
|
||||
stopLoss := trigPrice - slRange*m.shakeHit
|
||||
slDst := (c - stopLoss) * m.shakeHit / slRange
|
||||
tpDst := (takeProfit - c) * m.shakeHit / slRange
|
||||
if slDst > 0.5 && tpDst > 0.7 {
|
||||
// 到止损的距离不低于50%
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: tag,
|
||||
Short: m.shakeHit < 0,
|
||||
StopLoss: stopLoss,
|
||||
TakeProfit: takeProfit,
|
||||
})
|
||||
//date := btime.ToDateStr(btime.TimeMS(), "")
|
||||
//log.Info(fmt.Sprintf("%s %s open %s c:%.3f sl:%.3f, tp:%.3f", s.Symbols.Symbols,
|
||||
// date, tag, c, stopLoss, takeProfit))
|
||||
if err != nil {
|
||||
log.Error("open fail", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
|
||||
// ma := ta.EMA(e.Close, 5)
|
||||
rsi := ta.RSI(e.Close, 9)
|
||||
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr)
|
||||
atrBase := ta.Lowest(ta.Highest(atr, lenAtr), baseAtrLen).Get(0)
|
||||
atrRate := atr.Get(0) / atrBase
|
||||
|
||||
// 计算平均实体比率
|
||||
o, h, l, c := e.Open.Get(0), e.High.Get(0), e.Low.Get(0), e.Close.Get(0)
|
||||
ph, pl, pc := e.High.Get(1), e.Low.Get(1), e.Close.Get(1)
|
||||
solidTop, solidBtm := max(o, c), min(o, c)
|
||||
tRange, pRange := h-l, ph-pl
|
||||
//tr := e.GetSeries("tRange")
|
||||
//tr.Set(math.Sqrt(tRange * 100 / c))
|
||||
//maTRate := ta.EMA(tr, 3)
|
||||
solRate := e.Close.To("solRate", 0)
|
||||
solRate.Set(math.Abs(o-c) / tRange)
|
||||
maSRT := ta.EMA(solRate, 3).Get(0)
|
||||
|
||||
// 计算上下行比率
|
||||
dnRate := e.Close.To("dnRate", 0)
|
||||
dnRate.Set((l - pc) / pRange)
|
||||
maDnRate := ta.EMA(dnRate, 5)
|
||||
upRate := e.Close.To("upRate", 0)
|
||||
upRate.Set((h - pc) / pRange)
|
||||
maUpRate := ta.EMA(upRate, 5)
|
||||
|
||||
m, _ := s.More.(*TMore)
|
||||
m.shakeScore = (1 - maSRT) // * maTRate.Get(0)
|
||||
top := c + maUpRate.Get(0)*tRange
|
||||
btm := c + maDnRate.Get(0)*tRange
|
||||
edgeOff := (top - btm) * (1 - rangeRate) * 0.5
|
||||
m.btmPrice = btm - edgeOff
|
||||
m.topPrice = top + edgeOff
|
||||
//m.maChg = (ma.Get(0) - ma.Get(1)) / pRange
|
||||
topLineRate := (h - solidTop) / tRange
|
||||
btmLineRate := (solidBtm - l) / tRange
|
||||
lineDiff := math.Abs(topLineRate-btmLineRate) / max(topLineRate, btmLineRate)
|
||||
rsiVal, pRsi := rsi.Get(0)-50, rsi.Get(1)-50
|
||||
m.shakeOK = (top-btm)*rangeRate/c >= minProfitPct && lineDiff < 0.35 && maSRT < 0.3
|
||||
m.shakeHit = 0
|
||||
//log.Info(fmt.Sprintf("h: %.3f l:%.3f c:%.3f maSRT: %.3f upRate:%.3f dnRate:%.3f %v", h, l, c,
|
||||
// maSRT.Get(0), maUpRate.Get(0), maDnRate.Get(0), m.shakeOK))
|
||||
if math.Abs(rsiVal) > 20 || math.Abs(pRsi) > 20 {
|
||||
// (ATR较大/反向影线占比大)和RSI都极端时,容易反转,禁止震荡开单
|
||||
revLineRate := btmLineRate
|
||||
if rsiVal > 0 {
|
||||
revLineRate = topLineRate
|
||||
}
|
||||
if atrRate > 2.5 || atrRate > 1.3 && revLineRate > 0.75 {
|
||||
m.shakeOK = false
|
||||
}
|
||||
}
|
||||
},
|
||||
OnBatchInfos: func(tf string, jobs map[string]*strat.JobEnv) {
|
||||
// 筛选出所有币中shakeScore降序的前n个,然后在子周期中低买高卖
|
||||
var mores = make([]*TMore, 0, len(jobs))
|
||||
for _, job := range jobs {
|
||||
m, _ := job.Job.More.(*TMore)
|
||||
mores = append(mores, m)
|
||||
}
|
||||
var shakeTopN = int(math.Ceil(float64(len(jobs)) * ShakeTop))
|
||||
sort.Slice(mores, func(i, j int) bool {
|
||||
return mores[i].shakeScore > mores[j].shakeScore
|
||||
})
|
||||
for _, m := range mores {
|
||||
if shakeTopN > 0 && m.shakeOK {
|
||||
shakeTopN -= 1
|
||||
} else {
|
||||
m.shakeOK = false
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
127
old/macd_v1.go
Normal file
127
old/macd_v1.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/banbox/banbot/btime"
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
"github.com/banbox/banstagy/com"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func MACD(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: 300,
|
||||
MinTfScore: 0.75,
|
||||
DrawDownExit: true,
|
||||
OnStartUp: onStartUp,
|
||||
OnBar: onBar,
|
||||
}
|
||||
}
|
||||
|
||||
type MoreMACD struct {
|
||||
*com.ExmTrace
|
||||
max1 *com.ExmItem
|
||||
max2 *com.ExmItem
|
||||
slope float64 // 斜率
|
||||
delta float64 // 直线偏移值
|
||||
}
|
||||
|
||||
/*
|
||||
val: 当前指标值
|
||||
pNum: 前一个索引
|
||||
ptime:前一个时间戳
|
||||
*/
|
||||
func (m *MoreMACD) update(val float64, pNum int, ptime int64) bool {
|
||||
if m.ExmTrace.Update(val, pNum, ptime) {
|
||||
var exm *com.ExmItem
|
||||
last := m.Hist[len(m.Hist)-1]
|
||||
if last.Valid && m.ExmTrace.Expect < 0 {
|
||||
exm = last
|
||||
} else if len(m.Hist) > 1 && m.ExmTrace.Expect > 0 {
|
||||
exm = m.Hist[len(m.Hist)-2]
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
// 更新最高点和次高点
|
||||
if m.max1 == nil || exm.Value >= m.max1.Value {
|
||||
m.max1 = exm
|
||||
m.max2 = nil
|
||||
} else if m.max1 != nil && pNum-exm.BarNum > 500 {
|
||||
// 最高点超过500个bar过期
|
||||
if m.max2 != nil && m.max2.Value > exm.Value {
|
||||
exm = m.max2
|
||||
}
|
||||
m.max1 = m.max2
|
||||
m.max2 = nil
|
||||
} else if m.max2 == nil || exm.Value > m.max2.Value {
|
||||
m.max2 = exm
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func onStartUp(s *strat.StratJob) {
|
||||
s.More = &MoreMACD{
|
||||
ExmTrace: &com.ExmTrace{},
|
||||
}
|
||||
}
|
||||
|
||||
func onBar(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
macd, _ := ta.MACD(e.Close, 12, 26, 9)
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
|
||||
|
||||
m, _ := s.More.(*MoreMACD)
|
||||
|
||||
c := e.Close.Get(0)
|
||||
|
||||
if m.slope > 0 && m.max1 != nil && m.max2 != nil {
|
||||
point := m.slope*float64(e.BarNum) + m.delta
|
||||
tag := ""
|
||||
stopLoss := float64(0)
|
||||
if c-atr*2 > point && len(s.LongOrders) == 0 {
|
||||
// 突破压力线,做多
|
||||
tag = "long"
|
||||
stopLoss = point - atr
|
||||
} else if c+atr*0.5 > point && c <= point+atr && len(s.ShortOrders) == 0 {
|
||||
// 触发压力线,开空
|
||||
tag = "short"
|
||||
stopLoss = max(c, point) + atr*2
|
||||
}
|
||||
if tag != "" && !s.IsWarmUp {
|
||||
price1 := e.Close.Get(e.BarNum - m.max1.BarNum)
|
||||
price2 := e.Close.Get(e.BarNum - m.max2.BarNum)
|
||||
date := btime.ToDateStr(e.TimeStop, "")
|
||||
date1 := btime.ToDateStr(m.max1.TimeMS, "")
|
||||
date2 := btime.ToDateStr(m.max2.TimeMS, "")
|
||||
log.Info(fmt.Sprintf("%s open %s, %s %s %.5f - %s %.5f", date, tag, s.Symbol.Symbol,
|
||||
date1, price1, date2, price2))
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: tag,
|
||||
StopLoss: stopLoss,
|
||||
Short: tag == "short",
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open fail", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if m.update(macd.Get(0), e.BarNum-1, e.TimeStart-e.TFMSecs) {
|
||||
price1 := e.Close.Get(e.BarNum - m.max1.BarNum)
|
||||
price2 := e.Close.Get(e.BarNum - m.max2.BarNum)
|
||||
// 更新斜率和偏移值
|
||||
m.slope = (price2 - price1) / float64(m.max2.BarNum-m.max1.BarNum)
|
||||
m.delta = price1 - m.slope*float64(m.max1.BarNum)
|
||||
//date1 := btime.ToDateStr(m.max1.TimeMS, "")
|
||||
//date2 := btime.ToDateStr(m.max2.TimeMS, "")
|
||||
//log.Info(fmt.Sprintf("update pt2, %s %s %.5f - %s %.5f", s.Symbols.Symbols,
|
||||
// date1, price1, date2, price2))
|
||||
}
|
||||
}
|
||||
71
old/ped.go
Normal file
71
old/ped.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/core"
|
||||
"github.com/banbox/banbot/strat"
|
||||
ta "github.com/banbox/banta"
|
||||
)
|
||||
|
||||
type pedSta struct {
|
||||
bigDirt int
|
||||
midRsi float64
|
||||
}
|
||||
|
||||
func Ped(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
lenAtr := int(pol.Def("atr", 20, core.PNorm(7, 40)))
|
||||
baseAtrLen := int(float64(lenAtr) * 4.3)
|
||||
return &strat.TradeStrat{
|
||||
WarmupNum: 100,
|
||||
OnPairInfos: func(s *strat.StratJob) []*strat.PairSub {
|
||||
return []*strat.PairSub{
|
||||
{"_cur_", "15m", 100},
|
||||
{"_cur_", "1h", 205},
|
||||
}
|
||||
},
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
s.More = &pedSta{}
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
m, _ := s.More.(*pedSta)
|
||||
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)
|
||||
maBig := ta.SMA(e.Close, 10).Get(0)
|
||||
rsi := ta.RSI(e.Close, 14).Get(0)
|
||||
if s.OrderNum > 0 {
|
||||
return
|
||||
}
|
||||
if m.bigDirt > 0 && m.midRsi < 70 && c > maBig && rsi > 70 {
|
||||
s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "long",
|
||||
StopLossVal: atrBase,
|
||||
TakeProfitVal: atrBase * 7,
|
||||
})
|
||||
} else if m.bigDirt < 0 && m.midRsi > 30 && c < maBig && rsi < 30 {
|
||||
s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "short",
|
||||
Short: true,
|
||||
StopLossVal: atrBase,
|
||||
TakeProfitVal: atrBase * 7,
|
||||
})
|
||||
}
|
||||
},
|
||||
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
|
||||
m, _ := s.More.(*pedSta)
|
||||
if tf == "1h" {
|
||||
maSml := ta.SMA(e.Close, 20).Get(0)
|
||||
maBig := ta.SMA(e.Close, 100).Get(0)
|
||||
if maSml > maBig {
|
||||
m.bigDirt = 1
|
||||
} else {
|
||||
m.bigDirt = -1
|
||||
}
|
||||
} else {
|
||||
// 15m
|
||||
m.midRsi = ta.RSI(e.Close, 14).Get(0)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
119
old/rev/01.go
Normal file
119
old/rev/01.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package rev
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/core"
|
||||
"github.com/banbox/banbot/orm/ormo"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banstagy/com"
|
||||
ta "github.com/banbox/banta"
|
||||
"math"
|
||||
)
|
||||
|
||||
type MoreRev struct {
|
||||
thres float64 // 阈值
|
||||
dirt float64 // 1rsi高于0,-1rsi低于0
|
||||
hitAt int // 进入极值的BarNum
|
||||
exmVal float64 // 最大极值
|
||||
bigRsi float64 // 大周期rsi
|
||||
}
|
||||
|
||||
func (m *MoreRev) update(rsi50 float64, barNum int) {
|
||||
rsiAbs := math.Abs(rsi50)
|
||||
if rsiAbs < m.thres {
|
||||
m.dirt = 0
|
||||
m.hitAt = 0
|
||||
m.exmVal = 0
|
||||
return
|
||||
}
|
||||
if m.dirt == 0 {
|
||||
if rsi50 > 0 {
|
||||
m.dirt = 1
|
||||
} else {
|
||||
m.dirt = -1
|
||||
}
|
||||
m.hitAt = barNum
|
||||
m.exmVal = rsiAbs
|
||||
} else if m.exmVal < rsiAbs {
|
||||
m.exmVal = rsiAbs
|
||||
}
|
||||
}
|
||||
|
||||
func S01V1(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
var lenRsi = 22
|
||||
var lenRsi2 = 140
|
||||
var thresRsi = 20.0
|
||||
var hitRsi = 22.0
|
||||
var minKeep = 3
|
||||
|
||||
lenAtr := 15
|
||||
baseAtrLen := int(math.Round(float64(lenAtr) * 4.3))
|
||||
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: lenRsi * 2,
|
||||
MinTfScore: 0.75,
|
||||
DrawDownExit: true,
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
s.More = &MoreRev{thres: thresRsi}
|
||||
},
|
||||
OnPairInfos: com.MakePairInfos(lenRsi2),
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
m, _ := s.More.(*MoreRev)
|
||||
rsi := ta.RSI(e.Close, lenRsi)
|
||||
rsiMa := ta.SMA(rsi, 3)
|
||||
rsiVal := rsi.Get(0)
|
||||
rsiX := rsi.Cross(rsiMa)
|
||||
|
||||
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)
|
||||
|
||||
c := e.Close.Get(0)
|
||||
bigRsiFit := math.Abs(m.bigRsi) > 5 && m.bigRsi*m.dirt > 0
|
||||
rsiFit := m.dirt != 0 && m.exmVal >= hitRsi && e.BarNum-m.hitAt >= minKeep
|
||||
if s.OrderNum == 0 && bigRsiFit && rsiFit && (rsiX == 1 || rsiX == -1) {
|
||||
// rsi处于极值范围,且触发最大极值,且满足最少极值数量,且和rsi均值交叉
|
||||
slVal := atrBase * atrRate * 5
|
||||
slLong, slShort := c-slVal, c+slVal
|
||||
//entPrice := c - slVal*0.3
|
||||
//if m.dirt > 0 {
|
||||
// entPrice = c - slVal*0.3
|
||||
//}
|
||||
com.FastOpen(s, -m.dirt, slLong, slShort, 0)
|
||||
} else if rsiFit && s.EnteredNum > 0 && m.bigRsi*m.dirt > 0 {
|
||||
if m.dirt == 1 && len(s.LongOrders) > 0 && m.bigRsi > 2 {
|
||||
// 平多
|
||||
_ = s.CloseOrders(&strat.ExitReq{
|
||||
Tag: "exitL",
|
||||
Dirt: core.OdDirtLong,
|
||||
})
|
||||
} else if m.dirt == -1 && len(s.ShortOrders) > 0 && m.bigRsi < -2 {
|
||||
_ = s.CloseOrders(&strat.ExitReq{
|
||||
Tag: "exitS",
|
||||
Dirt: core.OdDirtShort,
|
||||
})
|
||||
}
|
||||
}
|
||||
m.update(rsiVal-50, e.BarNum)
|
||||
},
|
||||
OnInfoBar: func(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
|
||||
m, _ := s.More.(*MoreRev)
|
||||
m.bigRsi = ta.RSI50(e.Close, lenRsi2).Get(0)
|
||||
},
|
||||
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
|
||||
sl := od.GetStopLoss()
|
||||
if sl == nil || sl.Range == 0 {
|
||||
return 0
|
||||
}
|
||||
bestRate := maxChg * od.InitPrice / sl.Range
|
||||
if bestRate > 2 {
|
||||
return 0.3
|
||||
} else if bestRate > 1 {
|
||||
return 0.5
|
||||
}
|
||||
return 0
|
||||
},
|
||||
}
|
||||
}
|
||||
57
old/rsi_ptn_rev/v1.go
Normal file
57
old/rsi_ptn_rev/v1.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package rsi_ptn_rev
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
"github.com/banbox/banstagy/ptn"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
v1RsiLen = 9
|
||||
v1RsiThres = 25
|
||||
v1AtrLen = 14
|
||||
)
|
||||
|
||||
func MainV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: 30,
|
||||
MinTfScore: 0.75,
|
||||
DrawDownExit: true,
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
|
||||
rsi := ta.RSI(e.Close, v1RsiLen).Get(0) - 50
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, v1AtrLen)
|
||||
baseAtrLen := int(math.Round(float64(v1AtrLen) * 4.3))
|
||||
atrBase := ta.Lowest(ta.Highest(atr, v1AtrLen), baseAtrLen).Get(0)
|
||||
atrVal := atr.Get(0)
|
||||
|
||||
if math.IsNaN(atrBase) || math.Abs(rsi) <= v1RsiThres || s.OrderNum > 0 || atrVal < atrBase {
|
||||
return
|
||||
}
|
||||
ptn := ptn.Recognize(e)
|
||||
if ptn == nil {
|
||||
// 未识别到蜡烛形态,或者形态与RSI相反,忽略
|
||||
return
|
||||
}
|
||||
ptnDirt := float64(ptn.Dirt)
|
||||
if rsi*ptnDirt > 0 {
|
||||
return
|
||||
}
|
||||
stopLoss := e.Close.Get(0) - atrVal*ptnDirt
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "enter",
|
||||
StopLoss: stopLoss,
|
||||
Short: ptnDirt < 0,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open fail", zap.Error(err))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
163
old/s01/main.go
Normal file
163
old/s01/main.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package s01
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"math"
|
||||
)
|
||||
|
||||
/*
|
||||
此策略对应python原始策略名为PivotRev
|
||||
|
||||
【s01_base】
|
||||
是最初版本的策略,所有标的使用固定的RSI差阈值:300周期9, 50周期20
|
||||
|
||||
【s01_adp.50】~【s01_adp.100】
|
||||
增加了标的自适应的前20个高于固定阈值50%~100%的所有RSI值的均值,作为实际阈值。
|
||||
开单数量倍增,曲线稍微平滑一些,收益更高。
|
||||
测试最佳值是54%
|
||||
|
||||
|
||||
【s01_adpb.55】~【s01_adp.70】
|
||||
将bigTmp和smlTmp同时满足时才记录,前面是各自达到阈值就记录。
|
||||
改了后订单减少40%左右,收益减少30%左右。
|
||||
不采用
|
||||
|
||||
后续考虑记录RSI300和RSI50的历史峰值,然后峰值排序,取Top50%的均值作为阈值。
|
||||
*/
|
||||
|
||||
var (
|
||||
RsiBig = 300
|
||||
RsiSml = 50
|
||||
ThsBig = float64(9)
|
||||
ThsSml = float64(20)
|
||||
AtrLen = 14
|
||||
|
||||
bigMin = float64(ThsBig) * 0.55
|
||||
smlMin = float64(ThsSml) * 0.55
|
||||
|
||||
AvgLastNum = 20
|
||||
)
|
||||
|
||||
type MoreType struct {
|
||||
hit bool
|
||||
bigThsHis []float64
|
||||
smlThsHis []float64
|
||||
bigThs float64
|
||||
smlThs float64
|
||||
bigTmp float64
|
||||
smlTmp float64
|
||||
}
|
||||
|
||||
func (m *MoreType) close() {
|
||||
if m.bigTmp > bigMin {
|
||||
m.bigThsHis = append(m.bigThsHis, m.bigTmp)
|
||||
if len(m.bigThsHis) > AvgLastNum {
|
||||
m.bigThsHis = m.bigThsHis[len(m.bigThsHis)-AvgLastNum:]
|
||||
}
|
||||
sumVal := float64(0)
|
||||
for _, val := range m.bigThsHis {
|
||||
sumVal += val
|
||||
}
|
||||
m.bigThs = sumVal / float64(len(m.bigThsHis))
|
||||
}
|
||||
if m.smlTmp > smlMin {
|
||||
m.smlThsHis = append(m.smlThsHis, m.smlTmp)
|
||||
if len(m.smlThsHis) > AvgLastNum {
|
||||
m.smlThsHis = m.smlThsHis[len(m.smlThsHis)-AvgLastNum:]
|
||||
}
|
||||
sumSml := float64(0)
|
||||
for _, val := range m.smlThsHis {
|
||||
sumSml += val
|
||||
}
|
||||
m.smlThs = sumSml / float64(len(m.smlThsHis))
|
||||
}
|
||||
m.bigTmp = -1
|
||||
m.smlTmp = -1
|
||||
m.hit = false
|
||||
}
|
||||
|
||||
func (m *MoreType) check(big, sml float64) {
|
||||
if m.bigTmp < 0 {
|
||||
m.bigTmp = math.Abs(big)
|
||||
} else {
|
||||
m.bigTmp = max(m.bigTmp, math.Abs(big))
|
||||
}
|
||||
if m.smlTmp < 0 {
|
||||
m.smlTmp = math.Abs(sml)
|
||||
} else {
|
||||
m.smlTmp = max(m.smlTmp, math.Abs(sml))
|
||||
}
|
||||
}
|
||||
|
||||
func MainV0(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: RsiBig * 10,
|
||||
MinTfScore: 0.75,
|
||||
DrawDownExit: true,
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
s.More = &MoreType{
|
||||
bigThs: ThsBig,
|
||||
smlThs: ThsSml,
|
||||
bigTmp: -1,
|
||||
smlTmp: -1,
|
||||
}
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
ma5 := ta.EMA(e.Close, 5)
|
||||
ma20 := ta.EMA(e.Close, 20)
|
||||
maX := ma5.Cross(ma20)
|
||||
|
||||
rsiB := ta.RSI(e.Close, RsiBig).Get(0) - 50
|
||||
rsiS := ta.RSI(e.Close, RsiSml).Get(0) - 50
|
||||
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, AtrLen)
|
||||
baseAtrLen := int(math.Round(float64(AtrLen) * 4.3))
|
||||
atrB := ta.Lowest(ta.Highest(atr, AtrLen), baseAtrLen).Get(0)
|
||||
|
||||
if math.IsNaN(rsiB) || math.IsInf(rsiB, 0) {
|
||||
// 过滤无效值
|
||||
return
|
||||
}
|
||||
|
||||
m, _ := s.More.(*MoreType)
|
||||
|
||||
if math.Abs(float64(maX)) == 1 {
|
||||
// 均线交叉,顶底切换,允许开单
|
||||
m.close()
|
||||
}
|
||||
m.check(rsiB, rsiS)
|
||||
if m.hit {
|
||||
// 已开单,禁止重复开单
|
||||
return
|
||||
}
|
||||
|
||||
if math.Abs(rsiB) <= m.bigThs || math.Abs(rsiS) <= m.smlThs {
|
||||
// 未触发阈值,不开单
|
||||
return
|
||||
}
|
||||
|
||||
m.hit = true // 禁止同方向再次开单
|
||||
isShort := rsiB > 0
|
||||
odDirt := float64(1)
|
||||
if isShort {
|
||||
odDirt = -1
|
||||
}
|
||||
stopLoss := e.Close.Get(0) - max(atrB*3, atr.Get(0)*1.5)*odDirt
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "enter",
|
||||
Short: isShort,
|
||||
StopLoss: stopLoss,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open order fail", zap.String("pair", s.Symbol.Symbol),
|
||||
zap.String("stagy", s.Strat.Name), zap.Error(err))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
71
old/s01/v1.go
Normal file
71
old/s01/v1.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package s01
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"math"
|
||||
)
|
||||
|
||||
/*
|
||||
此策略对应python原始策略名为PivotRev
|
||||
*/
|
||||
|
||||
func MainV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
RsiBig = 60
|
||||
RsiSml = 14
|
||||
ThsBig = 20
|
||||
ThsSml = 30
|
||||
AtrLen = 14
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: RsiBig,
|
||||
MinTfScore: 0.75,
|
||||
DrawDownExit: true,
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
ma5 := ta.EMA(e.Close, 5)
|
||||
ma20 := ta.EMA(e.Close, 20)
|
||||
maX := ma5.Cross(ma20)
|
||||
|
||||
rsiB := ta.RSI(e.Close, RsiBig).Get(0) - 50
|
||||
rsiS := ta.RSI(e.Close, RsiSml).Get(0) - 50
|
||||
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, AtrLen)
|
||||
basev1AtrLen := int(math.Round(float64(AtrLen) * 4.3))
|
||||
atrB := ta.Lowest(ta.Highest(atr, AtrLen), basev1AtrLen).Get(0)
|
||||
|
||||
if math.Abs(float64(maX)) == 1 {
|
||||
// 均线交叉,顶底切换,允许开单
|
||||
s.More = nil
|
||||
} else if s.More != nil {
|
||||
// 禁止开单
|
||||
return
|
||||
}
|
||||
|
||||
if math.Abs(rsiB) <= ThsBig || math.Abs(rsiS) <= ThsSml {
|
||||
// 未触发阈值,不开单
|
||||
return
|
||||
}
|
||||
|
||||
s.More = true // 禁止同方向再次开单
|
||||
isShort := rsiB > 0
|
||||
odDirt := float64(1)
|
||||
if isShort {
|
||||
odDirt = -1
|
||||
}
|
||||
stopLoss := e.Close.Get(0) - max(atrB*3, atr.Get(0)*1.5)*odDirt
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "enter",
|
||||
Short: isShort,
|
||||
StopLoss: stopLoss,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open order fail", zap.String("pair", s.Symbol.Symbol),
|
||||
zap.String("stagy", s.Strat.Name), zap.Error(err))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
120
old/s01/v2.go
Normal file
120
old/s01/v2.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package s01
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/banbox/banbot/btime"
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/orm/ormo"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"math"
|
||||
)
|
||||
|
||||
type S1More struct {
|
||||
JumpRates map[int64]float64
|
||||
HitNum int // 记录当前是否已开过单。对于单边行情,为避免重复开单,只有当rsi转折时才开单
|
||||
}
|
||||
|
||||
func MainV2(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
RsiSml = 14
|
||||
ThsSml = 40
|
||||
AtrLen = 14
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: RsiBig,
|
||||
MinTfScore: 0.1,
|
||||
DrawDownExit: true,
|
||||
BatchInOut: true,
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
s.More = &S1More{
|
||||
JumpRates: make(map[int64]float64),
|
||||
}
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
rsi := ta.RSI(e.Close, RsiSml)
|
||||
rsiS := rsi.Get(0) - 50
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
|
||||
|
||||
m, _ := s.More.(*S1More)
|
||||
|
||||
// 检查是否RSI多次触发,且首次转折
|
||||
openOK := m.HitNum > 1 && math.Abs(rsiS) < math.Abs(rsi.Get(1)-50)
|
||||
if math.Abs(rsiS) < ThsSml && !openOK {
|
||||
// rsi低于阈值,且不属于多次触发后转折
|
||||
m.HitNum = 0
|
||||
return
|
||||
}
|
||||
if rsiS > 0 && len(s.ShortOrders) > 0 || rsiS < 0 && len(s.LongOrders) > 0 {
|
||||
// 已有入场订单,不重复开单
|
||||
return
|
||||
}
|
||||
m.HitNum += 1
|
||||
if m.HitNum > 1 && !openOK {
|
||||
// 重复触发,只允许rsi调头时第二次入场
|
||||
return
|
||||
}
|
||||
c := e.Close.Get(0)
|
||||
stopLoss := c - atr*2
|
||||
tag := "long"
|
||||
if rsiS > 0 {
|
||||
stopLoss = c + atr*2
|
||||
tag = "short"
|
||||
}
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: tag,
|
||||
Short: rsiS > 0,
|
||||
StopLoss: stopLoss,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open order fail", zap.String("pair", s.Symbol.Symbol),
|
||||
zap.String("stagy", s.Strat.Name), zap.Error(err))
|
||||
}
|
||||
},
|
||||
OnBatchJobs: func(jobs []*strat.StratJob) {
|
||||
openNum := float64(0)
|
||||
for _, j := range jobs {
|
||||
if len(j.Entrys) > 0 {
|
||||
openNum += 1
|
||||
}
|
||||
}
|
||||
openRate := openNum / float64(len(jobs))
|
||||
// 这里无需限制openRate的上限,前面已禁止单个趋势重复多次开单
|
||||
if openRate < 0.2 {
|
||||
for _, j := range jobs {
|
||||
j.Entrys = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
log.Info(fmt.Sprintf("%s open orders, num: %v, total: %v, rate: %.2f",
|
||||
btime.ToDateStr(btime.TimeMS(), ""), openNum, len(jobs), openRate))
|
||||
},
|
||||
GetDrawDownExitRate: func(s *strat.StratJob, od *ormo.InOutOrder, maxChg float64) float64 {
|
||||
more, _ := s.More.(*S1More)
|
||||
jumpRate, ok := more.JumpRates[od.ID]
|
||||
if !ok {
|
||||
e := s.Env
|
||||
jumpRate = (e.Close.Get(RsiSml)/e.Close.Get(0) - 1) * 0.3
|
||||
more.JumpRates[od.ID] = jumpRate
|
||||
}
|
||||
var rate float64
|
||||
switch {
|
||||
case maxChg > jumpRate*15:
|
||||
rate = 0.15
|
||||
case maxChg > jumpRate*10:
|
||||
rate = 0.17
|
||||
case maxChg > jumpRate*3:
|
||||
rate = 0.25
|
||||
case maxChg > jumpRate*1:
|
||||
rate = 0.37
|
||||
case maxChg > jumpRate*0.5:
|
||||
rate = 0.5
|
||||
default:
|
||||
rate = 0
|
||||
}
|
||||
return rate
|
||||
},
|
||||
}
|
||||
}
|
||||
64
old/s01/v3.go
Normal file
64
old/s01/v3.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package s01
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/core"
|
||||
"github.com/banbox/banbot/strat"
|
||||
ta "github.com/banbox/banta"
|
||||
"math"
|
||||
"slices"
|
||||
)
|
||||
|
||||
func MainV3(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
RsiSml = 100
|
||||
watchBig := 5
|
||||
watchSml := 3
|
||||
threshold := float64(17)
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: RsiBig,
|
||||
MinTfScore: 0.75,
|
||||
//DrawDownExit: true,
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
rsi := ta.RSI(e.Close, RsiSml)
|
||||
sml := ta.SMA(rsi, watchSml)
|
||||
big := ta.SMA(rsi, watchBig)
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, 14).Get(0)
|
||||
crx := sml.Cross(big)
|
||||
if crx != 1 && crx != -1 {
|
||||
return
|
||||
}
|
||||
rsiVal := float64(0)
|
||||
if rsi.Get(watchBig) > 50 {
|
||||
rsiVal = slices.Max(rsi.Range(0, watchBig*2))
|
||||
} else {
|
||||
rsiVal = slices.Min(rsi.Range(0, watchBig*2))
|
||||
}
|
||||
if math.Abs(rsiVal-50) < threshold {
|
||||
return
|
||||
}
|
||||
c := e.Close.Get(0)
|
||||
if crx == -1 {
|
||||
_ = s.CloseOrders(&strat.ExitReq{
|
||||
Tag: "x_short",
|
||||
Dirt: core.OdDirtShort,
|
||||
})
|
||||
_ = s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "long",
|
||||
StopLoss: c - atr*10,
|
||||
})
|
||||
} else if crx == 1 {
|
||||
_ = s.CloseOrders(&strat.ExitReq{
|
||||
Tag: "x_long",
|
||||
Dirt: core.OdDirtLong,
|
||||
})
|
||||
_ = s.OpenOrder(&strat.EnterReq{
|
||||
Tag: "short",
|
||||
Short: true,
|
||||
StopLoss: c + atr*10,
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
23
old/t01/1h.go
Normal file
23
old/t01/1h.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package t01
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
)
|
||||
|
||||
func Main1HV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
// 最适合1h的参数,测试20240101-20240324,50币,无需大周期趋势
|
||||
maSml = 10
|
||||
openOffRate = -1.5
|
||||
badRate = 1.5
|
||||
goodRate = 1
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: 300,
|
||||
MinTfScore: 0.75,
|
||||
//OnPairInfos: onPairInfos,
|
||||
OnStartUp: onStartUp,
|
||||
//OnInfoBar: onInfoBar,
|
||||
OnBar: onBar,
|
||||
}
|
||||
}
|
||||
BIN
old/t01/20240322_24_1h.xlsx
Normal file
BIN
old/t01/20240322_24_1h.xlsx
Normal file
Binary file not shown.
BIN
old/t01/20240322_24_4h.xlsx
Normal file
BIN
old/t01/20240322_24_4h.xlsx
Normal file
Binary file not shown.
BIN
old/t01/20240322_24_5m.xlsx
Normal file
BIN
old/t01/20240322_24_5m.xlsx
Normal file
Binary file not shown.
23
old/t01/4h.go
Normal file
23
old/t01/4h.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package t01
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
)
|
||||
|
||||
func Main4HV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
// 最适合4h的参数,测试20240101-20240324,50币,无需大周期趋势
|
||||
maSml = 10
|
||||
openOffRate = -1
|
||||
badRate = 1.5
|
||||
goodRate = 1
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: 300,
|
||||
MinTfScore: 0.75,
|
||||
//OnPairInfos: onPairInfos,
|
||||
OnStartUp: onStartUp,
|
||||
//OnInfoBar: onInfoBar,
|
||||
OnBar: onBar,
|
||||
}
|
||||
}
|
||||
138
old/t01/common.go
Normal file
138
old/t01/common.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package t01
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/orm/ormo"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banexg/log"
|
||||
"github.com/banbox/banstagy/com"
|
||||
ta "github.com/banbox/banta"
|
||||
"go.uber.org/zap"
|
||||
"math"
|
||||
)
|
||||
|
||||
var (
|
||||
// 这里是默认参数,请尽量在MainVX()中修改,不要在这里修改
|
||||
maBig = 30
|
||||
maSml = 30
|
||||
maParent = 50
|
||||
sampleNum = 500 // 斜率采样数量
|
||||
sampleStep = 2 // 斜率计算间隔
|
||||
atrLen = 14
|
||||
openOffRate = float64(0) // 开单时,从均线偏移基准ATR的倍数
|
||||
goodRate = float64(10) // 收益超过此倍数的ATR时,将止损更新为均线
|
||||
badRate = float64(5) // 损失超过此倍数的ATR时,止损退出
|
||||
)
|
||||
|
||||
type MoreType struct {
|
||||
bigSlop *com.Slop
|
||||
hitGoods map[int64]bool // 触发goodRate的订单ID,允许每个bar更新止损
|
||||
}
|
||||
|
||||
func openOrder(s *strat.StratJob, closePrice, dirt, price, stopLoss float64) {
|
||||
if (stopLoss-closePrice)*dirt >= 0 {
|
||||
// 当前止损立刻满足,跳过
|
||||
return
|
||||
}
|
||||
tag := "long"
|
||||
if dirt < 0 {
|
||||
tag = "short"
|
||||
}
|
||||
err := s.OpenOrder(&strat.EnterReq{
|
||||
Tag: tag,
|
||||
Limit: price,
|
||||
StopLoss: stopLoss,
|
||||
Short: dirt < 0,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("open order fail", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func onStartUp(s *strat.StratJob) {
|
||||
s.More = &MoreType{
|
||||
bigSlop: com.NewSlop(sampleNum, 0.25),
|
||||
hitGoods: make(map[int64]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func onInfoBar(s *strat.StratJob, e *ta.BarEnv, pair, tf string) {
|
||||
sma := ta.SMA(e.Close, maParent)
|
||||
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.bigSlop.Update(e.BarNum, slop)
|
||||
}
|
||||
|
||||
func onBar(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, atrLen)
|
||||
baseAtrLen := int(math.Round(float64(atrLen) * 4.3))
|
||||
atrBase := ta.Lowest(ta.Highest(atr, atrLen), baseAtrLen).Get(0)
|
||||
c := e.Close.Get(0)
|
||||
smaBig := ta.SMA(e.Close, maBig)
|
||||
smaVal := smaBig.Get(0)
|
||||
// smaSml := ta.SMA(e.Close, maSml)
|
||||
// maX := smaSml.Cross(smaBig)
|
||||
// rsiVal := ta.RSI(e.Close, 20).Get(0)
|
||||
|
||||
more, _ := s.More.(*MoreType)
|
||||
prevSma := smaBig.Get(sampleStep)
|
||||
if e.BarNum%sampleStep == 0 && !math.IsNaN(prevSma) {
|
||||
slop := (smaVal - prevSma) / smaVal
|
||||
more.bigSlop.Update(e.BarNum, slop)
|
||||
}
|
||||
|
||||
var longOd, shortOd *ormo.InOutOrder
|
||||
if len(s.LongOrders) > 0 {
|
||||
longOd = s.LongOrders[0]
|
||||
}
|
||||
if len(s.ShortOrders) > 0 {
|
||||
shortOd = s.ShortOrders[0]
|
||||
}
|
||||
|
||||
atrVal := atr.Get(0)
|
||||
slRange := max(atrBase*badRate, atrVal*1.5)
|
||||
|
||||
// 检查是否触发盈利阈值,若触发更新止损
|
||||
var orders = []*ormo.InOutOrder{longOd, shortOd}
|
||||
for _, od := range orders {
|
||||
if od != nil {
|
||||
odDirt := 1.0
|
||||
if od.Short {
|
||||
odDirt = -1
|
||||
}
|
||||
isGood, ok := more.hitGoods[od.ID]
|
||||
if !ok && (c-od.Enter.Average)*odDirt >= atrBase*goodRate {
|
||||
more.hitGoods[od.ID] = true
|
||||
isGood = true
|
||||
}
|
||||
if isGood {
|
||||
// 已触发盈利阈值,每个bar更新止损
|
||||
sl := od.GetStopLoss()
|
||||
if sl == nil || (smaVal-sl.Price)*odDirt > 0 {
|
||||
od.SetStopLoss(&ormo.ExitTrigger{Price: smaVal})
|
||||
}
|
||||
} else if od.Status == ormo.InOutStatusInit {
|
||||
// 尚未入场,更新入场价格,更新止损
|
||||
_ = od.SetEnterLimit(smaVal)
|
||||
od.SetStopLoss(&ormo.ExitTrigger{Price: smaVal - odDirt*slRange})
|
||||
}
|
||||
}
|
||||
}
|
||||
if atrVal < atrBase {
|
||||
// && more.bigSlop.Dirt > 0
|
||||
if longOd == nil && more.bigSlop.Dirt >= 0 {
|
||||
// 开多单 && c-smaVal+slRange > atrBase*0.5
|
||||
openOrder(s, c, 1, 0, c-slRange)
|
||||
}
|
||||
// && more.bigSlop.Dirt < 0
|
||||
if shortOd == nil && more.bigSlop.Dirt <= 0 {
|
||||
// 开空单 && smaVal+slRange-c > atrBase*0.5
|
||||
openOrder(s, c, -1, 0, c+slRange)
|
||||
}
|
||||
}
|
||||
}
|
||||
27
old/t01/v1.go
Normal file
27
old/t01/v1.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package t01
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/strat"
|
||||
"github.com/banbox/banstagy/com"
|
||||
)
|
||||
|
||||
func MainV1(pol *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
// 最适合5m的参数,测试20240322-20240324,50币,无需大周期趋势
|
||||
maSml = 10
|
||||
maBig = 50
|
||||
maParent = 30
|
||||
openOffRate = 0.5
|
||||
badRate = 3
|
||||
goodRate = 3
|
||||
return &strat.TradeStrat{
|
||||
Version: 1,
|
||||
WarmupNum: 300,
|
||||
MinTfScore: 0.75,
|
||||
//DrawDownExit: true,
|
||||
OnStartUp: onStartUp,
|
||||
OnBar: onBar,
|
||||
OnPairInfos: com.MakePairInfos(sampleNum*sampleStep + maParent),
|
||||
OnInfoBar: onInfoBar,
|
||||
}
|
||||
}
|
||||
89
old/xem4o.go
Normal file
89
old/xem4o.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package old
|
||||
|
||||
import (
|
||||
"github.com/banbox/banbot/config"
|
||||
"github.com/banbox/banbot/exg"
|
||||
"github.com/banbox/banbot/orm/ormo"
|
||||
"github.com/banbox/banbot/strat"
|
||||
ta "github.com/banbox/banta"
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
/*
|
||||
这是针对XEM/USDT:USDT的策略,其最小价格变动0.6%,挂单等待成交盈利很稳定。
|
||||
但实盘时实际成交量很小,挂单十几分钟才吃进去。
|
||||
*/
|
||||
|
||||
func xem40(p *config.RunPolicyConfig) *strat.TradeStrat {
|
||||
lenAtr := 14
|
||||
return &strat.TradeStrat{
|
||||
WarmupNum: 300,
|
||||
MinTfScore: 0.3,
|
||||
EachMaxLong: 1,
|
||||
EachMaxShort: 1,
|
||||
OnStartUp: func(s *strat.StratJob) {
|
||||
pip, err := exg.Default.PriceOnePip(s.Symbol.Symbol)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.More = pip
|
||||
},
|
||||
OnBar: func(s *strat.StratJob) {
|
||||
e := s.Env
|
||||
c := e.Close.Get(0)
|
||||
pip := s.More.(float64)
|
||||
if pip/c < 0.002 {
|
||||
// 仅针对XEM,最小价格变动是0.6%
|
||||
return
|
||||
}
|
||||
volMa := ta.SMA(e.Volume, 14).Get(0)
|
||||
maSml := ta.SMA(e.Close, 50).Get(0)
|
||||
maBig := ta.SMA(e.Close, 300).Get(0)
|
||||
rsi := ta.RSI50(e.Close, 50).Get(0)
|
||||
atr := ta.ATR(e.High, e.Low, e.Close, lenAtr).Get(0)
|
||||
|
||||
if s.OrderNum > 0 {
|
||||
var od *ormo.InOutOrder
|
||||
if len(s.LongOrders) > 0 {
|
||||
od = s.LongOrders[0]
|
||||
} else {
|
||||
od = s.ShortOrders[0]
|
||||
}
|
||||
if od.Status == ormo.InOutStatusPartEnter && (e.TimeStop-od.RealEnterMS())/e.TFMSecs > 3 {
|
||||
s.CloseOrders(&strat.ExitReq{Tag: "cancel", UnFillOnly: true})
|
||||
}
|
||||
return
|
||||
}
|
||||
sub1, sub2 := c-maSml, maSml-maBig
|
||||
dirt := 0
|
||||
if sub1*sub2 <= 0 && math.Abs(sub2) < atr {
|
||||
// 震荡行情
|
||||
if rsi > 3 {
|
||||
dirt = -1
|
||||
} else if rsi < -3 {
|
||||
dirt = 1
|
||||
}
|
||||
}
|
||||
if dirt == 0 && math.Abs(sub2) < pip {
|
||||
// 波动很小,直接开单
|
||||
dirt = 1
|
||||
if c > maSml {
|
||||
dirt = -1
|
||||
}
|
||||
}
|
||||
if dirt != 0 {
|
||||
amt := min(volMa*0.1, config.StakeAmount/c)
|
||||
s.OpenOrder(&strat.EnterReq{
|
||||
Tag: strconv.Itoa(dirt),
|
||||
Short: dirt < 0,
|
||||
Limit: c,
|
||||
Amount: amt,
|
||||
StopLossVal: pip * 2,
|
||||
TakeProfitVal: pip,
|
||||
StopBars: 20,
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user