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

164 lines
3.7 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 (
"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))
}
},
}
}