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 }, } }