Files
banstagy/ent/max_vol.go
2026-08-24 20:53:21 +08:00

183 lines
4.5 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 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
}