init
This commit is contained in:
182
ent/max_vol.go
Normal file
182
ent/max_vol.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user