This commit is contained in:
2026-08-24 20:53:21 +08:00
commit 6e78bba16a
287 changed files with 32443 additions and 0 deletions

165
old/eat.go Normal file
View 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
}
}
},
}
}