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

137
ent/his_sharpe.go Normal file
View File

@@ -0,0 +1,137 @@
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
}