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

195
ent/max_chg.go Normal file
View File

@@ -0,0 +1,195 @@
package ent
import (
"fmt"
"github.com/banbox/banbot/biz"
"github.com/banbox/banbot/btime"
"github.com/banbox/banbot/config"
"github.com/banbox/banbot/core"
"github.com/banbox/banbot/orm"
"github.com/banbox/banbot/utils"
"github.com/banbox/banexg"
"github.com/banbox/banexg/errs"
utils2 "github.com/banbox/banexg/utils"
"github.com/banbox/banstagy/com"
"github.com/banbox/banta"
"math"
"path/filepath"
"sort"
"strconv"
)
type chgSta struct {
env *banta.BarEnv
volMa *com.Ema
chg float64 // 变动百分比
stability float64 // 稳定性分数
adx float64
rsi float64
er float64
price float64
weight float64
nexts []*orm.InfoKline
num int
}
func maxChgTest() *errs.Error {
exgId := "binance"
tf := "1m"
maAlpha := 0.03
viewNextNum := 5
tfMSecs := int64(utils2.TFToSecs(tf) * 1000)
exsMap := orm.GetExSymbols(exgId, banexg.MarketLinear)
exsList := make([]*orm.ExSymbol, 0, len(exsMap))
envs := make(map[string]*chgSta)
staList := make([]*chgSta, 0, len(exsMap))
topStas := make([]*chgSta, 0, len(exsMap)/4)
for _, exs := range exsMap {
_, quote, _, _ := core.SplitSymbol(exs.Symbol)
if quote != "USDT" {
continue
}
exsList = append(exsList, exs)
env := &chgSta{
env: &banta.BarEnv{
TimeFrame: tf,
TFMSecs: tfMSecs,
Exchange: exs.Exchange,
MarketType: exs.Market,
Symbol: exs.Symbol,
MaxCache: 1000,
},
volMa: com.NewEMA(maAlpha),
}
envs[exs.Symbol] = env
staList = append(staList, env)
}
barNum := 0
barTimeMS := int64(0)
var rows [][]string
var head = []string{"time", "code", "chg", "weight", "price", "adx", "rsi", "er"}
for i := 0; i < viewNextNum; i++ {
head = append(head, "p"+strconv.Itoa(i+1))
}
rows = append(rows, head)
updateWeights := func() {
total := float64(0)
for _, e := range envs {
total += e.volMa.Val
}
if math.IsNaN(total) || total == 0 {
return
}
for _, e := range envs {
e.weight = (e.volMa.Val / total) * 100
}
sort.Slice(staList, func(i, j int) bool {
return staList[i].weight > staList[j].weight
})
topStas = staList[:150]
}
checkBatch := func() {
sort.Slice(topStas, func(i, j int) bool {
return math.Abs(topStas[i].chg) > math.Abs(topStas[j].chg)
})
for i := 0; i < 3; i++ {
e := topStas[i]
row := []string{
btime.ToDateStr(barTimeMS, core.DefaultDateFmt),
e.env.Symbol,
strconv.FormatFloat(e.chg, 'f', 2, 64),
strconv.FormatFloat(e.weight, 'f', 2, 64),
fmt.Sprintf("%.3e", e.price),
strconv.FormatFloat(e.adx, 'f', 2, 64),
strconv.FormatFloat(e.rsi, 'f', 2, 64),
strconv.FormatFloat(e.er, 'f', 2, 64),
}
for j := 0; j < viewNextNum; j++ {
rate := (e.nexts[j].Close/e.price - 1) * 100
row = append(row, strconv.FormatFloat(rate, 'f', 2, 64))
}
rows = append(rows, row)
}
}
totalSecs := (config.TimeRange.EndMS - config.TimeRange.StartMS) / 1000
pbar := utils.NewPrgBar(int(totalSecs), "Run")
defer pbar.Close()
onBar := func(b *orm.InfoKline, nexts []*orm.InfoKline) {
if b.Time > barTimeMS {
if !b.IsWarmUp && barTimeMS > 0 {
pbar.Add(int((b.Time - barTimeMS) / 1000))
}
barNum += 1
barTimeMS = b.Time
if barNum%20 == 1 {
// 每隔20个bar,更新全局权重
updateWeights()
}
if !b.IsWarmUp && barNum%5 == 0 {
// 每隔5个bar,计算一次变化
checkBatch()
}
}
sta := envs[b.Symbol]
sta.num += 1
e := sta.env
e.OnBar(b.Time, b.Open, b.High, b.Low, b.Close, b.Volume,
b.Quote, b.BuyVolume, b.TradeNum)
avgPrice := (b.High + b.Low + b.Close) / 3
sta.volMa.Update(b.Volume * avgPrice)
sta.chg = (b.Close/b.Open - 1) * 100
sta.adx = banta.ADX(e.High, e.Low, e.Close, 3).Get(0)
sta.rsi = banta.RSI(e.Close, 3).Get(0)
sta.er = banta.ER(e.Close, 3).Get(0)
if b.IsWarmUp {
return
}
sta.nexts = nexts
sta.price = b.Close
}
var replayErr *errs.Error
verCh := make(chan int, 1)
onData := func(evt *orm.DataSeries, nexts []*orm.DataSeries) {
bar, err_ := orm.AsKline(evt)
if err_ != nil {
replayErr = errs.New(errs.CodeRunTime, err_)
select {
case verCh <- -1:
default:
}
return
}
futureBars := make([]*orm.InfoKline, 0, len(nexts))
for _, next := range nexts {
futureBar, convErr := orm.AsKline(next)
if convErr != nil {
replayErr = errs.New(errs.CodeRunTime, convErr)
select {
case verCh <- -1:
default:
}
return
}
futureBars = append(futureBars, futureBar)
}
onBar(bar, futureBars)
}
err := biz.RunHistSeries(&biz.RunHistSeriesArgs{
ExsList: exsList,
Start: config.TimeRange.StartMS,
End: config.TimeRange.EndMS,
ViewNextNum: viewNextNum,
TfWarms: map[string]int{tf: 100},
VerCh: verCh,
OnData: onData,
})
if err == nil && replayErr != nil {
err = replayErr
}
outPath := filepath.Join(config.GetDataDir(), "dump", "maxChg.csv")
err2 := utils.WriteCsvFile(outPath, rows, false)
if err == nil {
err = err2
}
return err
}