package ent import ( "errors" "flag" "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/opt" "github.com/banbox/banbot/orm" "github.com/banbox/banbot/orm/ormo" utils2 "github.com/banbox/banexg/utils" "strconv" ) func hisSharpe(args []string) error { var configPaths config.ArrString var inPath string var sub = flag.NewFlagSet("fac", flag.ExitOnError) sub.Var(&configPaths, "config", "config path to use, Multiple -config options may be used") sub.StringVar(&inPath, "in", "", "path for all pairs orders e.g.: orders.gob") err_ := sub.Parse(args) if err_ != nil { return err_ } core.SetRunMode(core.RunModeBackTest) err := biz.SetupComsExg(&config.CmdArgs{ Configs: configPaths, }) if err != nil { return err } var startMs = config.TimeRange.StartMS var endMS = config.TimeRange.EndMS if len(config.StakeCurrency) == 0 { return errors.New("`stake_currency` in yml is required") } var tfSecs int var orders []*ormo.InOutOrder if inPath == "" { return errors.New("-in is required") } else { inPath = config.ParsePath(inPath) } orders, err = ormo.LoadOrdersGob(inPath) if err != nil { return err } var exsMap = make(map[int32]*orm.ExSymbol) var pairMap = make(map[string]int32) var totalCost float64 var validOdNum int if len(orders) > 0 { startMs = orders[0].RealEnterMS() endMS = orders[0].RealExitMS() for _, od := range orders { curStart := od.RealEnterMS() if curStart < startMs && curStart > 0 { startMs = curStart } curEnd := od.RealExitMS() if curEnd > endMS { endMS = curEnd } tfSecs = max(tfSecs, utils2.TFToSecs(od.Timeframe)) curCost := od.EnterCost() if curCost > 0 { totalCost += curCost validOdNum += 1 } if _, ok := pairMap[od.Symbol]; !ok { exs, err := orm.GetExSymbolCur(od.Symbol) if err != nil { return err } exsMap[exs.ID] = exs pairMap[od.Symbol] = exs.ID } } } else { return errors.New("orders is empty") } if validOdNum == 0 { return errors.New("no valid orders") } if tfSecs == 0 { tfSecs = utils2.TFToSecs("1d") } tf := "1d" // 滚动测试因子 rangeStart, _ := btime.ParseTimeMS("2022-11-19") rangeEnd, _ := btime.ParseTimeMS("2024-11-18") pairOrders, err := opt.CutOrdersInRange(orders, rangeStart, rangeEnd) if err != nil { return err } pairOrders = map[string][]*ormo.InOutOrder{ "WIF/USDT:USDT": pairOrders["WIF/USDT:USDT"], } pairInfos, err := opt.CalcPairStats(pairOrders, rangeStart, rangeEnd, tf) if err != nil { return err } initFund := config.WalletAmounts["USDT"] rangeSecs := (rangeEnd - rangeStart) / 1000 for _, sta := range pairInfos { reals := make([]float64, 0, len(sta.Returns)) curFund := initFund for _, v := range sta.Returns { curFund += v reals = append(reals, curFund) } sharp, _, err := opt.CalcMeasuresByReal(reals, rangeSecs, "", 0, 0) if err != nil { return err } labels := make([]string, len(reals)) for i := range reals { labels[i] = strconv.Itoa(i) } g := opt.Chart{ Labels: labels, Datasets: []*opt.ChartDs{ { Label: "pow(x, 1.5)", Data: reals, BorderColor: "rgb(75, 192, 192)", }, }, } g.DumpFile("D:/dump_pairs2.html") fmt.Printf("%s sharpe: %v", sta.Symbol, sharp) } return nil }