package arb import ( _ "embed" "github.com/banbox/banbot/btime" "github.com/banbox/banbot/config" "github.com/banbox/banbot/core" "github.com/banbox/banbot/exg" "github.com/banbox/banbot/opt" "github.com/banbox/banbot/orm" "github.com/banbox/banexg" "github.com/banbox/banexg/errs" "github.com/banbox/banexg/utils" "github.com/banbox/banta" "math" "strings" ) func GenTwoPairRatio() *errs.Error { //LineExamples() //return nil //groups := []string{"1000PEPE/USDT:USDT", "1000BONK/USDT:USDT"} groups := []string{ "LPT,ATH,MOODENG,RNDR,APT,TRUMP,DOT,HYPE,BAKE,SPX,BOME,TUT,PUMP,BERA,OG,EOS,MERL,TAO,NMR,FET,TIA,FHE,ZORA,LINK,POL,TRX,1000PEPE,ETHFI,PROVE,TREE", "RED,SUI,VIRTUAL,NEIRO,GALA,TON,PAXG,XNY,CRV,NAORIS,XRP,NEAR,AVAX,ETC,XLM,MATIC,AAVE,SEI,1000SHIB,DAM,SPK,MEME,OP,FIL,KAITO,FARTCOIN,EIGEN,BCH,IP,XPL", } //startMS := config.TimeRange.StartMS endMS, _ := btime.ParseTimeMS("20250921") tf := "15m" core.Market = "linear" tfMSecs := int64(utils.TFToSecs(tf) * 1000) barLimit := 30000 startMS := endMS - tfMSecs*int64(barLimit) barsArr := make([][]*TimeFlt, 0, len(groups)) allPairs := strings.Split(strings.Join(groups, ","), ",") allPairs, err := config.ParsePairs(allPairs...) if err != nil { return err } exsMap := make(map[int32]*orm.ExSymbol) for _, pair := range allPairs { exs, err := orm.GetExSymbolCur(pair) if err != nil { return err } exsMap[exs.ID] = exs } err = orm.BulkDownOHLCV(exg.Default, exsMap, tf, startMS, endMS, 0, nil) if err != nil { return err } for _, group := range groups { pairs := strings.Split(group, ",") prices, err := GetGroupPrices(pairs, tf, startMS, endMS) if err != nil { return err } barsArr = append(barsArr, prices) } rateArr := make([]*TimeFlt, len(barsArr[0])) for i, va := range barsArr[0] { rateArr[i] = &TimeFlt{ Stamp: va.Stamp, Val: va.Val / barsArr[1][i].Val, } } path := "D:/ratios.html" title := "price ratio" return dumpRateChart(rateArr, tf, path, title) } // GetGroupPrices 计算分组内多个品种的平均价格 func GetGroupPrices(pairs []string, tf string, startMS, endMS int64) ([]*TimeFlt, *errs.Error) { var groupBar [][]*banexg.Kline pairs, err := config.ParsePairs(pairs...) if err != nil { return nil, err } tfMSecs := int64(utils.TFToSecs(tf) * 1000) barLimit := (endMS - startMS) / tfMSecs for _, pair := range pairs { exs, err := orm.GetExSymbolCur(pair) if err != nil { return nil, err } _, bars, err := orm.GetOHLCV(exs, tf, startMS, endMS, 0, false) if err != nil { return nil, err } if float64(len(bars)) > float64(barLimit)*0.8 { groupBar = append(groupBar, bars) } } // 对分组内品种计算价格归一化均值 groupBar = getAlignBars(groupBar...) if len(groupBar) == 0 { return nil, errs.NewMsg(errs.CodeParamInvalid, "align bars fail for %v", pairs) } for _, gp := range groupBar { base := gp[0].Close gp[0].Close = 1 for i := 1; i < len(gp); i++ { gp[i].Close /= base } } barNum := len(groupBar[0]) bars := make([]*TimeFlt, 0, barNum) for j := 0; j < barNum; j++ { var sumVal float64 for _, gp := range groupBar { sumVal += gp[j].Close } bars = append(bars, &TimeFlt{ Stamp: groupBar[0][j].Time, Val: sumVal / float64(len(groupBar)), }) } return bars, nil } type TimeFlt struct { Stamp int64 Val float64 } func dumpRateChart(rates []*TimeFlt, tf string, path, title string) *errs.Error { if len(rates) == 0 { return nil } var labels []string var arrRaw []float64 var arrFast []float64 var arrSlow []float64 var arrMdMa []float64 var arrBigMa []float64 var arrBigUp []float64 var arrBigDn []float64 var arrHH, arrLL []float64 bollWid := 0.0043 showNum := 1440 stepFlt := float64(len(rates)) / float64(showNum) stepSize := int(math.Round(stepFlt)) tfMSecs := int64(utils.TFToSecs(tf) * 1000) lenFast := int(stepFlt * 5.77) lenSlow := int(stepFlt * 31.25) lenMid := int(stepFlt * 96.5) lenBig := int(stepFlt * 320.2) lenStd := int(stepFlt * 96.3) lenHL := int(stepFlt * 14.42) var idx = 0 env, _ := banta.NewBarEnv(core.ExgName, core.Market, "", tf) env.TimeStart = rates[idx].Stamp env.TimeStop = rates[idx].Stamp + tfMSecs rate := env.NewSeries(nil) rowId := 0 dateFmt := "01-02 15:04" for idx < len(rates) { item := rates[idx] env.TimeStart += tfMSecs env.TimeStop += tfMSecs env.BarNum += 1 rowId += 1 ratio := item.Val rate.Append(ratio) maFast := banta.EMA(rate, lenFast) maSlow := banta.EMA(rate, lenSlow) //66 maMid := banta.EMA(rate, lenMid).Get(0) maBig := banta.EMA(rate, lenBig) dev := banta.StdDev(rate, lenStd) stdDev := banta.SMA(dev, lenStd).Get(0) * 1.7 bollWidAvg := bollWid*maMid*0.5 + stdDev*0.5 hh := banta.Highest(rate, lenHL).Get(0) ll := banta.Lowest(rate, lenHL).Get(0) bigVal := maBig.Get(0) if rowId%stepSize == 0 && !math.IsNaN(maMid) { labels = append(labels, btime.ToDateStr(item.Stamp, dateFmt)) arrRaw = append(arrRaw, ratio) arrFast = append(arrFast, maFast.Get(0)) arrSlow = append(arrSlow, maSlow.Get(0)) arrMdMa = append(arrMdMa, maMid) arrBigMa = append(arrBigMa, bigVal) arrBigUp = append(arrBigUp, maMid+bollWidAvg) arrBigDn = append(arrBigDn, maMid-bollWidAvg) arrHH = append(arrHH, hh) arrLL = append(arrLL, ll) } idx += 1 } return opt.DumpChart(path, title, labels, 5, nil, []*opt.ChartDs{ {Label: "raw", Data: arrRaw}, {Label: "ma5", Data: arrFast, Hidden: true}, {Label: "ma10", Data: arrSlow, Hidden: true}, {Label: "mid", Data: arrMdMa}, {Label: "big", Data: arrBigMa, Hidden: true}, {Label: "upp", Data: arrBigUp, Hidden: false}, {Label: "dnn", Data: arrBigDn, Hidden: false}, //{Label: "hh", Data: arrHH, Hidden: true}, //{Label: "ll", Data: arrLL, Hidden: true}, }) }