120 lines
3.0 KiB
Go
120 lines
3.0 KiB
Go
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
|
||
},
|
||
}
|
||
}
|