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

182
ent/max_vol.go Normal file
View File

@@ -0,0 +1,182 @@
package ent
import (
"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"
"github.com/banbox/banstagy/com"
"math"
"path/filepath"
"sort"
"strconv"
)
type volSta struct {
code string
longVol *com.Ema
shortVol *com.Ema
longRate float64
shortRate float64
weight float64
price float64
nexts []*orm.InfoKline
num int
}
func maxVolTest() *errs.Error {
exgId := "binance"
tf := "1h"
maAlpha := 0.03
viewNextNum := 3
exsMap := orm.GetExSymbols(exgId, banexg.MarketLinear)
exsList := make([]*orm.ExSymbol, 0, len(exsMap))
envs := make(map[string]*volSta)
envList := make([]*volSta, 0, len(exsMap))
for _, exs := range exsMap {
_, quote, _, _ := core.SplitSymbol(exs.Symbol)
if quote != "USDT" {
continue
}
exsList = append(exsList, exs)
env := &volSta{
code: exs.Symbol,
longVol: com.NewEMA(maAlpha),
shortVol: com.NewEMA(maAlpha),
}
envs[exs.Symbol] = env
envList = append(envList, env)
}
barNum := 0
barTimeMS := int64(0)
updateWeights := func() {
total := float64(0)
for _, e := range envs {
total += e.longVol.Val + e.shortVol.Val
}
if math.IsNaN(total) {
return
}
for _, e := range envs {
wei := (e.longVol.Val + e.shortVol.Val) / total
e.weight = math.Pow(wei, 0.5)
}
}
var rows [][]string
var head = []string{"time", "code", "longRt", "shortRt"}
for i := 0; i < viewNextNum; i++ {
head = append(head, "p"+strconv.Itoa(i+1))
}
rows = append(rows, head)
checkBatch := func() {
sort.Slice(envList, func(i, j int) bool {
return envList[i].longRate > envList[j].shortRate
})
for i := 0; i < 3; i++ {
e := envList[i]
row := []string{
btime.ToDateStr(barTimeMS, core.DefaultDateFmt),
e.code,
strconv.FormatFloat(e.longRate, 'f', 3, 64),
strconv.FormatFloat(e.shortRate, 'f', 3, 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
lineTot := (b.High - b.Low) - math.Abs(b.Open-b.Close)
total := (b.High - b.Low) + lineTot + core.AmtDust
longTot := lineTot
if b.Open < b.Close {
longTot += math.Abs(b.Open - b.Close)
}
avgPrice := (b.High + b.Low + b.Close) / 3
quoteVol := avgPrice * b.Volume
longRt := longTot / total
longVol := quoteVol * longRt
shortVol := quoteVol - longVol
sta.longVol.Update(longVol)
sta.shortVol.Update(shortVol)
if b.IsWarmUp {
return
}
// 暂时不考虑多空直接比例
sta.longRate = longVol / sta.longVol.Val * sta.weight * math.Pow(longRt, 2)
sta.shortRate = shortVol / sta.shortVol.Val * sta.weight * math.Pow(1-longRt, 2)
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", "moneyFlow.csv")
err2 := utils.WriteCsvFile(outPath, rows, false)
if err == nil {
err = err2
}
return err
}