Files
banstagy/old/s01/v2.go
2026-08-24 20:53:21 +08:00

121 lines
3.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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